prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Poetry fails to install p4python due to read-only files
  <!--
    Hi there! Thank you for discovering and submitting an issue.
  
    Before you submit this; let's make sure of a few things.
    Please make sure the following boxes are ticked if they are correct.
    If not, please try and fulfill these first.
  -->
  
  <!-- Checked checkbox should look like this: [x] -->
  - [x] I am on the [latest](https://github.com/sdispater/poetry/releases/latest) Poetry version.
  - [x] I have searched the [issues](https://github.com/sdispater/poetry/issues) of this repo and believe that this is not a duplicate.
  - [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).
  
  <!--
    Once those are done, if you're able to fill in the following list with your information,
    it'd be very helpful to whoever handles the issue.
  -->
  
  - **OS version and name**: Windows 10
  - **Poetry version**: poetry 0.12.2
  - **Link of a [pyproject.toml Gist](https://gist.github.com/epage/5f28e3b1e5eeb9a30697363e369a5fde)
  - **Link of a [backtrace Gist](https://gist.github.com/epage/2584ad981ff5d9f175d55212b0192987)
  
  ## Issue
  
  In digging into the problem, it seems that p4python's files are all marked read-only, causing windows to error when trying to delete them via `shutil.rmtree` which is invoked by poetry's custom temp directory handling.
  
  </issue>
  <code>
  [start of poetry/utils/helpers.py]
  1 import os
  2 import re
  3 import shutil
  4 import stat
  5 import tempfile
  6 
  7 from contextlib import contextmanager
  8 from typing import List
  9 from typing import Optional
  10 
  11 from poetry.config.config import Config
  12 from poetry.utils._compat import Path
  13 from poetry.version import Version
  14 
  15 
  16 try:
  17     from collections.abc import Mapping
  18 except ImportError:
  19     from collections import Mapping
  20 
  21 
  22 _canonicalize_regex = re.compile("[-_]+")
  23 
  24 
  25 def canonicalize_name(name):  # type: (str) -> str
  26     return _canonicalize_regex.sub("-", name).lower()
  27 
  28 
  29 def module_name(name):  # type: (str) -> str
  30     return canonicalize_name(name).replace(".", "_").replace("-", "_")
  31 
  32 
  33 def normalize_version(version):  # type: (str) -> str
  34     return str(Version(version))
  35 
  36 
  37 @contextmanager
  38 def temporary_directory(*args, **kwargs):
  39     try:
  40         from tempfile import TemporaryDirectory
  41 
  42         with TemporaryDirectory(*args, **kwargs) as name:
  43             yield name
  44     except ImportError:
  45         name = tempfile.mkdtemp(*args, **kwargs)
  46 
  47         yield name
  48 
  49         shutil.rmtree(name)
  50 
  51 
  52 def parse_requires(requires):  # type: (str) -> List[str]
  53     lines = requires.split("\n")
  54 
  55     requires_dist = []
  56     in_section = False
  57     current_marker = None
  58     for line in lines:
  59         line = line.strip()
  60         if not line:
  61             if in_section:
  62                 in_section = False
  63 
  64             continue
  65 
  66         if line.startswith("["):
  67             # extras or conditional dependencies
  68             marker = line.lstrip("[").rstrip("]")
  69             if ":" not in marker:
  70                 extra, marker = marker, None
  71             else:
  72                 extra, marker = marker.split(":")
  73 
  74             if extra:
  75                 if marker:
  76                     marker = '{} and extra == "{}"'.format(marker, extra)
  77                 else:
  78                     marker = 'extra == "{}"'.format(extra)
  79 
  80             if marker:
  81                 current_marker = marker
  82 
  83             continue
  84 
  85         if current_marker:
  86             line = "{} ; {}".format(line, current_marker)
  87 
  88         requires_dist.append(line)
  89 
  90     return requires_dist
  91 
  92 
  93 def get_cert(config, repository_name):  # type: (Config, str) -> Optional[Path]
  94     cert = config.get("certificates.{}.cert".format(repository_name))
  95     if cert:
  96         return Path(cert)
  97     else:
  98         return None
  99 
  100 
  101 def get_client_cert(config, repository_name):  # type: (Config, str) -> Optional[Path]
  102     client_cert = config.get("certificates.{}.client-cert".format(repository_name))
  103     if client_cert:
  104         return Path(client_cert)
  105     else:
  106         return None
  107 
  108 
  109 def _on_rm_error(func, path, exc_info):
  110     if not os.path.exists(path):
  111         return
  112 
  113     os.chmod(path, stat.S_IWRITE)
  114     func(path)
  115 
  116 
  117 def safe_rmtree(path):
  118     if Path(path).is_symlink():
  119         return os.unlink(str(path))
  120 
  121     shutil.rmtree(path, onerror=_on_rm_error)
  122 
  123 
  124 def merge_dicts(d1, d2):
  125     for k, v in d2.items():
  126         if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], Mapping):
  127             merge_dicts(d1[k], d2[k])
  128         else:
  129             d1[k] = d2[k]
  130
  [end of poetry/utils/helpers.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/poetry/utils/helpers.py b/poetry/utils/helpers.py
  --- a/poetry/utils/helpers.py
  +++ b/poetry/utils/helpers.py
  @@ -34,19 +34,18 @@
       return str(Version(version))
   
   
  +def _del_ro(action, name, exc):
  +    os.chmod(name, stat.S_IWRITE)
  +    os.remove(name)
  +
  +
   @contextmanager
   def temporary_directory(*args, **kwargs):
  -    try:
  -        from tempfile import TemporaryDirectory
  -
  -        with TemporaryDirectory(*args, **kwargs) as name:
  -            yield name
  -    except ImportError:
  -        name = tempfile.mkdtemp(*args, **kwargs)
  +    name = tempfile.mkdtemp(*args, **kwargs)
   
  -        yield name
  +    yield name
   
  -        shutil.rmtree(name)
  +    shutil.rmtree(name, onerror=_del_ro)
   
   
   def parse_requires(requires):  # type: (str) -> List[str]
  
verification_info: {"golden_diff": "diff --git a/poetry/utils/helpers.py b/poetry/utils/helpers.py\n--- a/poetry/utils/helpers.py\n+++ b/poetry/utils/helpers.py\n@@ -34,19 +34,18 @@\n     return str(Version(version))\n \n \n+def _del_ro(action, name, exc):\n+    os.chmod(name, stat.S_IWRITE)\n+    os.remove(name)\n+\n+\n @contextmanager\n def temporary_directory(*args, **kwargs):\n-    try:\n-        from tempfile import TemporaryDirectory\n-\n-        with TemporaryDirectory(*args, **kwargs) as name:\n-            yield name\n-    except ImportError:\n-        name = tempfile.mkdtemp(*args, **kwargs)\n+    name = tempfile.mkdtemp(*args, **kwargs)\n \n-        yield name\n+    yield name\n \n-        shutil.rmtree(name)\n+    shutil.rmtree(name, onerror=_del_ro)\n \n \n def parse_requires(requires):  # type: (str) -> List[str]\n", "issue": "Poetry fails to install p4python due to read-only files\n<!--\r\n  Hi there! Thank you for discovering and submitting an issue.\r\n\r\n  Before you submit this; let's make sure of a few things.\r\n  Please make sure the following boxes are ticked if they are correct.\r\n  If not, please try and fulfill these first.\r\n-->\r\n\r\n<!-- Checked checkbox should look like this: [x] -->\r\n- [x] I am on the [latest](https://github.com/sdispater/poetry/releases/latest) Poetry version.\r\n- [x] I have searched the [issues](https://github.com/sdispater/poetry/issues) of this repo and believe that this is not a duplicate.\r\n- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).\r\n\r\n<!--\r\n  Once those are done, if you're able to fill in the following list with your information,\r\n  it'd be very helpful to whoever handles the issue.\r\n-->\r\n\r\n- **OS version and name**: Windows 10\r\n- **Poetry version**: poetry 0.12.2\r\n- **Link of a [pyproject.toml Gist](https://gist.github.com/epage/5f28e3b1e5eeb9a30697363e369a5fde)\r\n- **Link of a [backtrace Gist](https://gist.github.com/epage/2584ad981ff5d9f175d55212b0192987)\r\n\r\n## Issue\r\n\r\nIn digging into the problem, it seems that p4python's files are all marked read-only, causing windows to error when trying to delete them via `shutil.rmtree` which is invoked by poetry's custom temp directory handling.\n", "before_files": [{"content": "import os\nimport re\nimport shutil\nimport stat\nimport tempfile\n\nfrom contextlib import contextmanager\nfrom typing import List\nfrom typing import Optional\n\nfrom poetry.config.config import Config\nfrom poetry.utils._compat import Path\nfrom poetry.version import Version\n\n\ntry:\n    from collections.abc import Mapping\nexcept ImportError:\n    from collections import Mapping\n\n\n_canonicalize_regex = re.compile(\"[-_]+\")\n\n\ndef canonicalize_name(name):  # type: (str) -> str\n    return _canonicalize_regex.sub(\"-\", name).lower()\n\n\ndef module_name(name):  # type: (str) -> str\n    return canonicalize_name(name).replace(\".\", \"_\").replace(\"-\", \"_\")\n\n\ndef normalize_version(version):  # type: (str) -> str\n    return str(Version(version))\n\n\n@contextmanager\ndef temporary_directory(*args, **kwargs):\n    try:\n        from tempfile import TemporaryDirectory\n\n        with TemporaryDirectory(*args, **kwargs) as name:\n            yield name\n    except ImportError:\n        name = tempfile.mkdtemp(*args, **kwargs)\n\n        yield name\n\n        shutil.rmtree(name)\n\n\ndef parse_requires(requires):  # type: (str) -> List[str]\n    lines = requires.split(\"\\n\")\n\n    requires_dist = []\n    in_section = False\n    current_marker = None\n    for line in lines:\n        line = line.strip()\n        if not line:\n            if in_section:\n                in_section = False\n\n            continue\n\n        if line.startswith(\"[\"):\n            # extras or conditional dependencies\n            marker = line.lstrip(\"[\").rstrip(\"]\")\n            if \":\" not in marker:\n                extra, marker = marker, None\n            else:\n                extra, marker = marker.split(\":\")\n\n            if extra:\n                if marker:\n                    marker = '{} and extra == \"{}\"'.format(marker, extra)\n                else:\n                    marker = 'extra == \"{}\"'.format(extra)\n\n            if marker:\n                current_marker = marker\n\n            continue\n\n        if current_marker:\n            line = \"{} ; {}\".format(line, current_marker)\n\n        requires_dist.append(line)\n\n    return requires_dist\n\n\ndef get_cert(config, repository_name):  # type: (Config, str) -> Optional[Path]\n    cert = config.get(\"certificates.{}.cert\".format(repository_name))\n    if cert:\n        return Path(cert)\n    else:\n        return None\n\n\ndef get_client_cert(config, repository_name):  # type: (Config, str) -> Optional[Path]\n    client_cert = config.get(\"certificates.{}.client-cert\".format(repository_name))\n    if client_cert:\n        return Path(client_cert)\n    else:\n        return None\n\n\ndef _on_rm_error(func, path, exc_info):\n    if not os.path.exists(path):\n        return\n\n    os.chmod(path, stat.S_IWRITE)\n    func(path)\n\n\ndef safe_rmtree(path):\n    if Path(path).is_symlink():\n        return os.unlink(str(path))\n\n    shutil.rmtree(path, onerror=_on_rm_error)\n\n\ndef merge_dicts(d1, d2):\n    for k, v in d2.items():\n        if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], Mapping):\n            merge_dicts(d1[k], d2[k])\n        else:\n            d1[k] = d2[k]\n", "path": "poetry/utils/helpers.py"}]}