prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  HdfsTarget commands fail when many targets are instantiated
  I've recently added an existence check to a large mapreduce task for which some input files may be missing. With a large enough set of inputs, it will fail every time. I've simplified it to the following code:
  
  ``` python
  from luigi.contrib.hdfs import HdfsTarget
  
  many_targets = [HdfsTarget('/') for _ in range(2000)]
  all(target.exists() for target in many_targets)
  ```
  
  This will break if I use any past 1000 or so. Here the client uses snakebite. For a more direct triggering, we can also do
  
  ``` python
  from snakebite.client import AutoConfigClient
  
  clients = [AutoConfigClient() for _ in range(10000)]
  all(client.test('/', exists=True) for client in clients)
  ```
  
  In either case, the bug goes away if I use a generator expression rather than a list comprehension. The problem is that when I'm dealing with objects coming out of luigi calls like input_hadoop, it's too late for me to decide between lists and iterators. I can code around this by instantiating all of my HdfsTargets with the same client, but I'm not sure this is safe. It could also be fixed in luigi if we had get_autoconfig_client return the same object each time. Is there any reason this wouldn't work?
  
  
  </issue>
  <code>
  [start of luigi/contrib/hdfs/clients.py]
  1 # -*- coding: utf-8 -*-
  2 #
  3 # Copyright 2012-2015 Spotify AB
  4 #
  5 # Licensed under the Apache License, Version 2.0 (the "License");
  6 # you may not use this file except in compliance with the License.
  7 # You may obtain a copy of the License at
  8 #
  9 # http://www.apache.org/licenses/LICENSE-2.0
  10 #
  11 # Unless required by applicable law or agreed to in writing, software
  12 # distributed under the License is distributed on an "AS IS" BASIS,
  13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 # See the License for the specific language governing permissions and
  15 # limitations under the License.
  16 #
  17 
  18 """
  19 The implementations of the hdfs clients. The hadoop cli client and the
  20 snakebite client.
  21 """
  22 
  23 
  24 from luigi.contrib.hdfs import config as hdfs_config
  25 from luigi.contrib.hdfs import snakebite_client as hdfs_snakebite_client
  26 from luigi.contrib.hdfs import webhdfs_client as hdfs_webhdfs_client
  27 from luigi.contrib.hdfs import hadoopcli_clients as hdfs_hadoopcli_clients
  28 import luigi.contrib.target
  29 import logging
  30 
  31 logger = logging.getLogger('luigi-interface')
  32 
  33 
  34 def get_autoconfig_client():
  35     """
  36     Creates the client as specified in the `luigi.cfg` configuration.
  37     """
  38     configured_client = hdfs_config.get_configured_hdfs_client()
  39     if configured_client == "webhdfs":
  40         return hdfs_webhdfs_client.WebHdfsClient()
  41     if configured_client == "snakebite":
  42         return hdfs_snakebite_client.SnakebiteHdfsClient()
  43     if configured_client == "snakebite_with_hadoopcli_fallback":
  44         return luigi.contrib.target.CascadingClient([hdfs_snakebite_client.SnakebiteHdfsClient(),
  45                                                      hdfs_hadoopcli_clients.create_hadoopcli_client()])
  46     if configured_client == "hadoopcli":
  47         return hdfs_hadoopcli_clients.create_hadoopcli_client()
  48     raise Exception("Unknown hdfs client " + configured_client)
  49 
  50 
  51 def _with_ac(method_name):
  52     def result(*args, **kwargs):
  53         return getattr(get_autoconfig_client(), method_name)(*args, **kwargs)
  54     return result
  55 
  56 exists = _with_ac('exists')
  57 rename = _with_ac('rename')
  58 remove = _with_ac('remove')
  59 mkdir = _with_ac('mkdir')
  60 listdir = _with_ac('listdir')
  61
  [end of luigi/contrib/hdfs/clients.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/luigi/contrib/hdfs/clients.py b/luigi/contrib/hdfs/clients.py
  --- a/luigi/contrib/hdfs/clients.py
  +++ b/luigi/contrib/hdfs/clients.py
  @@ -19,33 +19,42 @@
   The implementations of the hdfs clients. The hadoop cli client and the
   snakebite client.
   """
  -
  +import logging
  +import threading
   
   from luigi.contrib.hdfs import config as hdfs_config
   from luigi.contrib.hdfs import snakebite_client as hdfs_snakebite_client
   from luigi.contrib.hdfs import webhdfs_client as hdfs_webhdfs_client
   from luigi.contrib.hdfs import hadoopcli_clients as hdfs_hadoopcli_clients
   import luigi.contrib.target
  -import logging
   
   logger = logging.getLogger('luigi-interface')
   
  +_AUTOCONFIG_CLIENT = threading.local()
  +
   
  -def get_autoconfig_client():
  +def get_autoconfig_client(client_cache=_AUTOCONFIG_CLIENT):
       """
       Creates the client as specified in the `luigi.cfg` configuration.
       """
  -    configured_client = hdfs_config.get_configured_hdfs_client()
  -    if configured_client == "webhdfs":
  -        return hdfs_webhdfs_client.WebHdfsClient()
  -    if configured_client == "snakebite":
  -        return hdfs_snakebite_client.SnakebiteHdfsClient()
  -    if configured_client == "snakebite_with_hadoopcli_fallback":
  -        return luigi.contrib.target.CascadingClient([hdfs_snakebite_client.SnakebiteHdfsClient(),
  -                                                     hdfs_hadoopcli_clients.create_hadoopcli_client()])
  -    if configured_client == "hadoopcli":
  -        return hdfs_hadoopcli_clients.create_hadoopcli_client()
  -    raise Exception("Unknown hdfs client " + configured_client)
  +    try:
  +        return client_cache.client
  +    except AttributeError:
  +        configured_client = hdfs_config.get_configured_hdfs_client()
  +        if configured_client == "webhdfs":
  +            client_cache.client = hdfs_webhdfs_client.WebHdfsClient()
  +        elif configured_client == "snakebite":
  +            client_cache.client = hdfs_snakebite_client.SnakebiteHdfsClient()
  +        elif configured_client == "snakebite_with_hadoopcli_fallback":
  +            client_cache.client = luigi.contrib.target.CascadingClient([
  +                hdfs_snakebite_client.SnakebiteHdfsClient(),
  +                hdfs_hadoopcli_clients.create_hadoopcli_client(),
  +            ])
  +        elif configured_client == "hadoopcli":
  +            client_cache.client = hdfs_hadoopcli_clients.create_hadoopcli_client()
  +        else:
  +            raise Exception("Unknown hdfs client " + configured_client)
  +        return client_cache.client
   
   
   def _with_ac(method_name):
  
verification_info: {"golden_diff": "diff --git a/luigi/contrib/hdfs/clients.py b/luigi/contrib/hdfs/clients.py\n--- a/luigi/contrib/hdfs/clients.py\n+++ b/luigi/contrib/hdfs/clients.py\n@@ -19,33 +19,42 @@\n The implementations of the hdfs clients. The hadoop cli client and the\n snakebite client.\n \"\"\"\n-\n+import logging\n+import threading\n \n from luigi.contrib.hdfs import config as hdfs_config\n from luigi.contrib.hdfs import snakebite_client as hdfs_snakebite_client\n from luigi.contrib.hdfs import webhdfs_client as hdfs_webhdfs_client\n from luigi.contrib.hdfs import hadoopcli_clients as hdfs_hadoopcli_clients\n import luigi.contrib.target\n-import logging\n \n logger = logging.getLogger('luigi-interface')\n \n+_AUTOCONFIG_CLIENT = threading.local()\n+\n \n-def get_autoconfig_client():\n+def get_autoconfig_client(client_cache=_AUTOCONFIG_CLIENT):\n     \"\"\"\n     Creates the client as specified in the `luigi.cfg` configuration.\n     \"\"\"\n-    configured_client = hdfs_config.get_configured_hdfs_client()\n-    if configured_client == \"webhdfs\":\n-        return hdfs_webhdfs_client.WebHdfsClient()\n-    if configured_client == \"snakebite\":\n-        return hdfs_snakebite_client.SnakebiteHdfsClient()\n-    if configured_client == \"snakebite_with_hadoopcli_fallback\":\n-        return luigi.contrib.target.CascadingClient([hdfs_snakebite_client.SnakebiteHdfsClient(),\n-                                                     hdfs_hadoopcli_clients.create_hadoopcli_client()])\n-    if configured_client == \"hadoopcli\":\n-        return hdfs_hadoopcli_clients.create_hadoopcli_client()\n-    raise Exception(\"Unknown hdfs client \" + configured_client)\n+    try:\n+        return client_cache.client\n+    except AttributeError:\n+        configured_client = hdfs_config.get_configured_hdfs_client()\n+        if configured_client == \"webhdfs\":\n+            client_cache.client = hdfs_webhdfs_client.WebHdfsClient()\n+        elif configured_client == \"snakebite\":\n+            client_cache.client = hdfs_snakebite_client.SnakebiteHdfsClient()\n+        elif configured_client == \"snakebite_with_hadoopcli_fallback\":\n+            client_cache.client = luigi.contrib.target.CascadingClient([\n+                hdfs_snakebite_client.SnakebiteHdfsClient(),\n+                hdfs_hadoopcli_clients.create_hadoopcli_client(),\n+            ])\n+        elif configured_client == \"hadoopcli\":\n+            client_cache.client = hdfs_hadoopcli_clients.create_hadoopcli_client()\n+        else:\n+            raise Exception(\"Unknown hdfs client \" + configured_client)\n+        return client_cache.client\n \n \n def _with_ac(method_name):\n", "issue": "HdfsTarget commands fail when many targets are instantiated\nI've recently added an existence check to a large mapreduce task for which some input files may be missing. With a large enough set of inputs, it will fail every time. I've simplified it to the following code:\n\n``` python\nfrom luigi.contrib.hdfs import HdfsTarget\n\nmany_targets = [HdfsTarget('/') for _ in range(2000)]\nall(target.exists() for target in many_targets)\n```\n\nThis will break if I use any past 1000 or so. Here the client uses snakebite. For a more direct triggering, we can also do\n\n``` python\nfrom snakebite.client import AutoConfigClient\n\nclients = [AutoConfigClient() for _ in range(10000)]\nall(client.test('/', exists=True) for client in clients)\n```\n\nIn either case, the bug goes away if I use a generator expression rather than a list comprehension. The problem is that when I'm dealing with objects coming out of luigi calls like input_hadoop, it's too late for me to decide between lists and iterators. I can code around this by instantiating all of my HdfsTargets with the same client, but I'm not sure this is safe. It could also be fixed in luigi if we had get_autoconfig_client return the same object each time. Is there any reason this wouldn't work?\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2012-2015 Spotify AB\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#\n\n\"\"\"\nThe implementations of the hdfs clients. The hadoop cli client and the\nsnakebite client.\n\"\"\"\n\n\nfrom luigi.contrib.hdfs import config as hdfs_config\nfrom luigi.contrib.hdfs import snakebite_client as hdfs_snakebite_client\nfrom luigi.contrib.hdfs import webhdfs_client as hdfs_webhdfs_client\nfrom luigi.contrib.hdfs import hadoopcli_clients as hdfs_hadoopcli_clients\nimport luigi.contrib.target\nimport logging\n\nlogger = logging.getLogger('luigi-interface')\n\n\ndef get_autoconfig_client():\n    \"\"\"\n    Creates the client as specified in the `luigi.cfg` configuration.\n    \"\"\"\n    configured_client = hdfs_config.get_configured_hdfs_client()\n    if configured_client == \"webhdfs\":\n        return hdfs_webhdfs_client.WebHdfsClient()\n    if configured_client == \"snakebite\":\n        return hdfs_snakebite_client.SnakebiteHdfsClient()\n    if configured_client == \"snakebite_with_hadoopcli_fallback\":\n        return luigi.contrib.target.CascadingClient([hdfs_snakebite_client.SnakebiteHdfsClient(),\n                                                     hdfs_hadoopcli_clients.create_hadoopcli_client()])\n    if configured_client == \"hadoopcli\":\n        return hdfs_hadoopcli_clients.create_hadoopcli_client()\n    raise Exception(\"Unknown hdfs client \" + configured_client)\n\n\ndef _with_ac(method_name):\n    def result(*args, **kwargs):\n        return getattr(get_autoconfig_client(), method_name)(*args, **kwargs)\n    return result\n\nexists = _with_ac('exists')\nrename = _with_ac('rename')\nremove = _with_ac('remove')\nmkdir = _with_ac('mkdir')\nlistdir = _with_ac('listdir')\n", "path": "luigi/contrib/hdfs/clients.py"}]}