prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Impala pandas_interop.py DataFrameWriter.write_csv() fails with PermissionError on Windows Platforms
  pandas_interop.py DataFrameWriter.write_csv() fails with PermissionError on Windows Platforms due to how Pythons [tempfile.NamedTemporaryFile()](https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile) works. 
  
  Specifically, if the OS is Windows and the NamedTemporaryFile delete parameter is True, the IO operation will fail, because Python will open the file and then Pandas will attempt to open the file again. See [this SO answer ](https://stackoverflow.com/a/23212515/3744998)for more information. 
  
  I have replicated the issue manually and verified that setting the delete parameter to False resolves the issue. Perhaps we can add a platform check and explicitly set the delete parameter based on the platform? Then after we [exit the context statements scope](https://github.com/ibis-project/ibis/blob/master/ibis/impala/pandas_interop.py#L80), explicitly delete the temporary file. I imagine it could look something like the following.
  
  ``` python
  
      import os
  
      def write_csv(self, path):
          if os.name == 'nt':
              # Should probably think of a better name for this boolean
              delete = False
          else:
              delete = True
  
          with tempfile.NamedTemporaryFile(delete=delete) as f:
              tmp_name = f.name
              # Write the DataFrame to the temporary file path
              if options.verbose:
                  util.log(
                      'Writing DataFrame to temporary file {}'.format(f.name)
                  )
  
              self.df.to_csv(
                  f.name,
                  header=False,
                  index=False,
                  sep=',',
                  quoting=csv.QUOTE_NONE,
                  escapechar='\\',
                  na_rep='#NULL',
              )
              f.seek(0)
  
              if options.verbose:
                  util.log('Writing CSV to: {0}'.format(path))
  
              self.hdfs.put(path, f.name)
  
          if not delete:
              os.remove(tmp_name)
  
          return path
  ```
  
  
  I don't know that much about the Ibis code base, so this is just a first pass. I hope it's helpful. 
  
  </issue>
  <code>
  [start of ibis/impala/pandas_interop.py]
  1 # Copyright 2014 Cloudera Inc.
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 # http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 
  15 import csv
  16 import tempfile
  17 
  18 from posixpath import join as pjoin
  19 
  20 import ibis.common.exceptions as com
  21 import ibis.expr.schema as sch
  22 import ibis.util as util
  23 from ibis.config import options
  24 
  25 
  26 class DataFrameWriter:
  27 
  28     """
  29     Interface class for writing pandas objects to Impala tables
  30 
  31     Class takes ownership of any temporary data written to HDFS
  32     """
  33 
  34     def __init__(self, client, df, path=None):
  35         self.client = client
  36         self.hdfs = client.hdfs
  37 
  38         self.df = df
  39 
  40         self.temp_hdfs_dirs = []
  41 
  42     def write_temp_csv(self):
  43         temp_hdfs_dir = pjoin(
  44             options.impala.temp_hdfs_path, 'pandas_{}'.format(util.guid())
  45         )
  46         self.hdfs.mkdir(temp_hdfs_dir)
  47 
  48         # Keep track of the temporary HDFS file
  49         self.temp_hdfs_dirs.append(temp_hdfs_dir)
  50 
  51         # Write the file to HDFS
  52         hdfs_path = pjoin(temp_hdfs_dir, '0.csv')
  53 
  54         self.write_csv(hdfs_path)
  55 
  56         return temp_hdfs_dir
  57 
  58     def write_csv(self, path):
  59         with tempfile.NamedTemporaryFile() as f:
  60             # Write the DataFrame to the temporary file path
  61             if options.verbose:
  62                 util.log(
  63                     'Writing DataFrame to temporary file {}'.format(f.name)
  64                 )
  65 
  66             self.df.to_csv(
  67                 f.name,
  68                 header=False,
  69                 index=False,
  70                 sep=',',
  71                 quoting=csv.QUOTE_NONE,
  72                 escapechar='\\',
  73                 na_rep='#NULL',
  74             )
  75             f.seek(0)
  76 
  77             if options.verbose:
  78                 util.log('Writing CSV to: {0}'.format(path))
  79 
  80             self.hdfs.put(path, f.name)
  81         return path
  82 
  83     def get_schema(self):
  84         # define a temporary table using delimited data
  85         return sch.infer(self.df)
  86 
  87     def delimited_table(self, csv_dir, name=None, database=None):
  88         temp_delimited_name = 'ibis_tmp_pandas_{0}'.format(util.guid())
  89         schema = self.get_schema()
  90 
  91         return self.client.delimited_file(
  92             csv_dir,
  93             schema,
  94             name=temp_delimited_name,
  95             database=database,
  96             delimiter=',',
  97             na_rep='#NULL',
  98             escapechar='\\\\',
  99             external=True,
  100             persist=False,
  101         )
  102 
  103     def __del__(self):
  104         try:
  105             self.cleanup()
  106         except com.IbisError:
  107             pass
  108 
  109     def cleanup(self):
  110         for path in self.temp_hdfs_dirs:
  111             self.hdfs.rmdir(path)
  112         self.temp_hdfs_dirs = []
  113         self.csv_dir = None
  114 
  115 
  116 def write_temp_dataframe(client, df):
  117     writer = DataFrameWriter(client, df)
  118     path = writer.write_temp_csv()
  119     return writer, writer.delimited_table(path)
  120
  [end of ibis/impala/pandas_interop.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/ibis/impala/pandas_interop.py b/ibis/impala/pandas_interop.py
  --- a/ibis/impala/pandas_interop.py
  +++ b/ibis/impala/pandas_interop.py
  @@ -13,8 +13,8 @@
   # limitations under the License.
   
   import csv
  +import os
   import tempfile
  -
   from posixpath import join as pjoin
   
   import ibis.common.exceptions as com
  @@ -56,15 +56,21 @@
           return temp_hdfs_dir
   
       def write_csv(self, path):
  -        with tempfile.NamedTemporaryFile() as f:
  +        # Use a temporary dir instead of a temporary file
  +        # to provide Windows support and avoid #2267
  +        # https://github.com/ibis-project/ibis/issues/2267
  +        with tempfile.TemporaryDirectory() as f:
               # Write the DataFrame to the temporary file path
  +            tmp_file_path = os.path.join(f, 'impala_temp_file.csv')
               if options.verbose:
                   util.log(
  -                    'Writing DataFrame to temporary file {}'.format(f.name)
  +                    'Writing DataFrame to temporary directory {}'.format(
  +                        tmp_file_path
  +                    )
                   )
   
               self.df.to_csv(
  -                f.name,
  +                tmp_file_path,
                   header=False,
                   index=False,
                   sep=',',
  @@ -72,12 +78,11 @@
                   escapechar='\\',
                   na_rep='#NULL',
               )
  -            f.seek(0)
   
               if options.verbose:
                   util.log('Writing CSV to: {0}'.format(path))
   
  -            self.hdfs.put(path, f.name)
  +            self.hdfs.put(path, tmp_file_path)
           return path
   
       def get_schema(self):
  
verification_info: {"golden_diff": "diff --git a/ibis/impala/pandas_interop.py b/ibis/impala/pandas_interop.py\n--- a/ibis/impala/pandas_interop.py\n+++ b/ibis/impala/pandas_interop.py\n@@ -13,8 +13,8 @@\n # limitations under the License.\n \n import csv\n+import os\n import tempfile\n-\n from posixpath import join as pjoin\n \n import ibis.common.exceptions as com\n@@ -56,15 +56,21 @@\n         return temp_hdfs_dir\n \n     def write_csv(self, path):\n-        with tempfile.NamedTemporaryFile() as f:\n+        # Use a temporary dir instead of a temporary file\n+        # to provide Windows support and avoid #2267\n+        # https://github.com/ibis-project/ibis/issues/2267\n+        with tempfile.TemporaryDirectory() as f:\n             # Write the DataFrame to the temporary file path\n+            tmp_file_path = os.path.join(f, 'impala_temp_file.csv')\n             if options.verbose:\n                 util.log(\n-                    'Writing DataFrame to temporary file {}'.format(f.name)\n+                    'Writing DataFrame to temporary directory {}'.format(\n+                        tmp_file_path\n+                    )\n                 )\n \n             self.df.to_csv(\n-                f.name,\n+                tmp_file_path,\n                 header=False,\n                 index=False,\n                 sep=',',\n@@ -72,12 +78,11 @@\n                 escapechar='\\\\',\n                 na_rep='#NULL',\n             )\n-            f.seek(0)\n \n             if options.verbose:\n                 util.log('Writing CSV to: {0}'.format(path))\n \n-            self.hdfs.put(path, f.name)\n+            self.hdfs.put(path, tmp_file_path)\n         return path\n \n     def get_schema(self):\n", "issue": "Impala pandas_interop.py DataFrameWriter.write_csv() fails with PermissionError on Windows Platforms\npandas_interop.py DataFrameWriter.write_csv() fails with PermissionError on Windows Platforms due to how Pythons [tempfile.NamedTemporaryFile()](https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile) works. \r\n\r\nSpecifically, if the OS is Windows and the NamedTemporaryFile delete parameter is True, the IO operation will fail, because Python will open the file and then Pandas will attempt to open the file again. See [this SO answer ](https://stackoverflow.com/a/23212515/3744998)for more information. \r\n\r\nI have replicated the issue manually and verified that setting the delete parameter to False resolves the issue. Perhaps we can add a platform check and explicitly set the delete parameter based on the platform? Then after we [exit the context statements scope](https://github.com/ibis-project/ibis/blob/master/ibis/impala/pandas_interop.py#L80), explicitly delete the temporary file. I imagine it could look something like the following.\r\n\r\n``` python\r\n\r\n    import os\r\n\r\n    def write_csv(self, path):\r\n        if os.name == 'nt':\r\n            # Should probably think of a better name for this boolean\r\n            delete = False\r\n        else:\r\n            delete = True\r\n\r\n        with tempfile.NamedTemporaryFile(delete=delete) as f:\r\n            tmp_name = f.name\r\n            # Write the DataFrame to the temporary file path\r\n            if options.verbose:\r\n                util.log(\r\n                    'Writing DataFrame to temporary file {}'.format(f.name)\r\n                )\r\n\r\n            self.df.to_csv(\r\n                f.name,\r\n                header=False,\r\n                index=False,\r\n                sep=',',\r\n                quoting=csv.QUOTE_NONE,\r\n                escapechar='\\\\',\r\n                na_rep='#NULL',\r\n            )\r\n            f.seek(0)\r\n\r\n            if options.verbose:\r\n                util.log('Writing CSV to: {0}'.format(path))\r\n\r\n            self.hdfs.put(path, f.name)\r\n\r\n        if not delete:\r\n            os.remove(tmp_name)\r\n\r\n        return path\r\n```\r\n\r\n\r\nI don't know that much about the Ibis code base, so this is just a first pass. I hope it's helpful. \n", "before_files": [{"content": "# Copyright 2014 Cloudera Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport csv\nimport tempfile\n\nfrom posixpath import join as pjoin\n\nimport ibis.common.exceptions as com\nimport ibis.expr.schema as sch\nimport ibis.util as util\nfrom ibis.config import options\n\n\nclass DataFrameWriter:\n\n    \"\"\"\n    Interface class for writing pandas objects to Impala tables\n\n    Class takes ownership of any temporary data written to HDFS\n    \"\"\"\n\n    def __init__(self, client, df, path=None):\n        self.client = client\n        self.hdfs = client.hdfs\n\n        self.df = df\n\n        self.temp_hdfs_dirs = []\n\n    def write_temp_csv(self):\n        temp_hdfs_dir = pjoin(\n            options.impala.temp_hdfs_path, 'pandas_{}'.format(util.guid())\n        )\n        self.hdfs.mkdir(temp_hdfs_dir)\n\n        # Keep track of the temporary HDFS file\n        self.temp_hdfs_dirs.append(temp_hdfs_dir)\n\n        # Write the file to HDFS\n        hdfs_path = pjoin(temp_hdfs_dir, '0.csv')\n\n        self.write_csv(hdfs_path)\n\n        return temp_hdfs_dir\n\n    def write_csv(self, path):\n        with tempfile.NamedTemporaryFile() as f:\n            # Write the DataFrame to the temporary file path\n            if options.verbose:\n                util.log(\n                    'Writing DataFrame to temporary file {}'.format(f.name)\n                )\n\n            self.df.to_csv(\n                f.name,\n                header=False,\n                index=False,\n                sep=',',\n                quoting=csv.QUOTE_NONE,\n                escapechar='\\\\',\n                na_rep='#NULL',\n            )\n            f.seek(0)\n\n            if options.verbose:\n                util.log('Writing CSV to: {0}'.format(path))\n\n            self.hdfs.put(path, f.name)\n        return path\n\n    def get_schema(self):\n        # define a temporary table using delimited data\n        return sch.infer(self.df)\n\n    def delimited_table(self, csv_dir, name=None, database=None):\n        temp_delimited_name = 'ibis_tmp_pandas_{0}'.format(util.guid())\n        schema = self.get_schema()\n\n        return self.client.delimited_file(\n            csv_dir,\n            schema,\n            name=temp_delimited_name,\n            database=database,\n            delimiter=',',\n            na_rep='#NULL',\n            escapechar='\\\\\\\\',\n            external=True,\n            persist=False,\n        )\n\n    def __del__(self):\n        try:\n            self.cleanup()\n        except com.IbisError:\n            pass\n\n    def cleanup(self):\n        for path in self.temp_hdfs_dirs:\n            self.hdfs.rmdir(path)\n        self.temp_hdfs_dirs = []\n        self.csv_dir = None\n\n\ndef write_temp_dataframe(client, df):\n    writer = DataFrameWriter(client, df)\n    path = writer.write_temp_csv()\n    return writer, writer.delimited_table(path)\n", "path": "ibis/impala/pandas_interop.py"}]}