We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Suspicion that `@reject_recursive_repeats` is not thread-safe
* Version: 3.16.2
* Python: 3.6
* OS: osx


### What was wrong?

When executing a few contract calls concurrently, I kept getting errors like:

```
File "/usr/local/lib/python3.6/site-packages/web3/contract.py", line 870, in call_contract_function
    normalized_data = map_abi_data(normalizers, output_types, output_data)
  File "/usr/local/lib/python3.6/site-packages/eth_utils/string.py", line 85, in inner
    return force_obj_to_text(fn(*args, **kwargs))
  File "/usr/local/lib/python3.6/site-packages/web3/utils/abi.py", line 437, in map_abi_data
    return pipe(data, *pipeline)
  File "cytoolz/functoolz.pyx", line 586, in cytoolz.functoolz.pipe (cytoolz/functoolz.c:10663)
  File "cytoolz/functoolz.pyx", line 562, in cytoolz.functoolz.c_pipe (cytoolz/functoolz.c:10494)
  File "/usr/local/lib/python3.6/site-packages/web3/utils/decorators.py", line 31, in wrapped
    wrapped_val = to_wrap(*args)
  File "/usr/local/lib/python3.6/site-packages/web3/utils/formatters.py", line 117, in recursive_map
    items_mapped = map_collection(recurse, data)
  File "/usr/local/lib/python3.6/site-packages/web3/utils/formatters.py", line 104, in map_collection
    return datatype(map(func, collection))
  File "/usr/local/lib/python3.6/site-packages/web3/utils/formatters.py", line 116, in recurse
    return recursive_map(func, item)
  File "/usr/local/lib/python3.6/site-packages/web3/utils/decorators.py", line 29, in wrapped
    raise ValueError('Recursively called %s with %r' % (to_wrap, args))
ValueError: Recursively called <function recursive_map at 0x7f012ea030d0> with (<function strip_abi_type at 0x7f012ea06ae8>, ABITypedData(abi_type='address', data='0x168910909606A2Fca90D4C28Fa39b50407b9C526'))
```

and

```
  File "/usr/local/lib/python3.6/site-packages/web3/contract.py", line 870, in call_contract_function
    normalized_data = map_abi_data(normalizers, output_types, output_data)
  File "/usr/local/lib/python3.6/site-packages/eth_utils/string.py", line 85, in inner
    return force_obj_to_text(fn(*args, **kwargs))
  File "/usr/local/lib/python3.6/site-packages/web3/utils/abi.py", line 437, in map_abi_data
    return pipe(data, *pipeline)
  File "cytoolz/functoolz.pyx", line 586, in cytoolz.functoolz.pipe (cytoolz/functoolz.c:10663)
  File "cytoolz/functoolz.pyx", line 562, in cytoolz.functoolz.c_pipe (cytoolz/functoolz.c:10494)
  File "/usr/local/lib/python3.6/site-packages/web3/utils/decorators.py", line 29, in wrapped
    raise ValueError('Recursively called %s with %r' % (to_wrap, args))
ValueError: Recursively called <function recursive_map at 0x7f012ea030d0> with (<function strip_abi_type at 0x7f012ea06ae8>, [ABITypedData(abi_type='uint256', data=1000000000000000000), ABITypedData(abi_type='address', data='0xC66eA802717bFb9833400264Dd12c2bCeAa34a6d'), ABITypedData(abi_type='uint256', data=100000000000000000000), ABITypedData(abi_type='address', data='0xECF8F87f810EcF450940c9f60066b4a7a501d6A7'), ABITypedData(abi_type='address', data='0xbe69Be9133DAA77AeAFcA0d6330c7Ba44f597b15'), ABITypedData(abi_type='bool', data=True), ABITypedData(abi_type='uint64', data=1505245070)])
```

We are connecting to a Parity node.

### How can it be fixed?

My suspicion is that because `@reject_recursive_repeats` keeps state in `to_wrap.__already_called`, this is not thread-safe and will fail if two threads want to parse the same data at the same time.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `web3/utils/compat/compat_gevent.py`
Content:
```
1 import collections
2 
3 import gevent
4 from gevent.pywsgi import (  # noqa: F401
5     WSGIServer,
6 )
7 from gevent import (  # noqa: F401
8     subprocess,
9     socket,
10     threading,
11 )
12 
13 import pylru
14 
15 from geventhttpclient import HTTPClient
16 
17 from web3.utils.six import urlparse
18 
19 
20 _client_cache = pylru.lrucache(8)
21 
22 
23 sleep = gevent.sleep
24 spawn = gevent.spawn
25 GreenletThread = gevent.Greenlet
26 
27 
28 class Timeout(gevent.Timeout):
29     def check(self):
30         pass
31 
32     def sleep(self, seconds):
33         gevent.sleep(seconds)
34 
35 
36 def make_server(host, port, application, *args, **kwargs):
37     server = WSGIServer((host, port), application, *args, **kwargs)
38     return server
39 
40 
41 def _get_client(host, port, **kwargs):
42     ordered_kwargs = collections.OrderedDict(sorted(kwargs.items()))
43     cache_key = '{0}:{1}:{2}'.format(
44         host,
45         port,
46         ':'.join((
47             "{0}={1}".format(str(key), str(value))
48             for key, value in ordered_kwargs.items()
49         ))
50     )
51     if cache_key not in _client_cache:
52         _client_cache[cache_key] = HTTPClient(host, port, **kwargs)
53     return _client_cache[cache_key]
54 
55 
56 def make_post_request(endpoint_uri, data, **kwargs):
57     url_parts = urlparse(endpoint_uri)
58 
59     host, _, port = url_parts.netloc.partition(':')
60 
61     if not port:
62         if url_parts.scheme == 'http':
63             port = 80
64         elif url_parts.scheme == 'https':
65             port = 443
66         else:
67             raise ValueError("Unsupported scheme: '{0}'".format(url_parts.scheme))
68 
69     kwargs.setdefault('ssl', url_parts.scheme == 'https')
70     kwargs.setdefault('connection_timeout', 10)
71     kwargs.setdefault('network_timeout', 10)
72     kwargs.setdefault('concurrency', 10)
73 
74     client = _get_client(host, port, **kwargs)
75     response = client.post(url_parts.path, body=data)
76     response_body = response.read()
77 
78     return response_body
79
```

Path: `web3/utils/decorators.py`
Content:
```
1 import functools
2 import warnings
3 
4 
5 class combomethod(object):
6     def __init__(self, method):
7         self.method = method
8 
9     def __get__(self, obj=None, objtype=None):
10         @functools.wraps(self.method)
11         def _wrapper(*args, **kwargs):
12             if obj is not None:
13                 return self.method(obj, *args, **kwargs)
14             else:
15                 return self.method(objtype, *args, **kwargs)
16         return _wrapper
17 
18 
19 def reject_recursive_repeats(to_wrap):
20     '''
21     Prevent simple cycles by returning None when called recursively with same instance
22     '''
23     to_wrap.__already_called = {}
24 
25     @functools.wraps(to_wrap)
26     def wrapped(*args):
27         instances = tuple(map(id, args))
28         if instances in to_wrap.__already_called:
29             raise ValueError('Recursively called %s with %r' % (to_wrap, args))
30         to_wrap.__already_called[instances] = True
31         wrapped_val = to_wrap(*args)
32         del to_wrap.__already_called[instances]
33         return wrapped_val
34     return wrapped
35 
36 
37 def deprecated_for(replace_message):
38     '''
39     Decorate a deprecated function, with info about what to use instead, like:
40 
41     @deprecated_for("toBytes()")
42     def toAscii(arg):
43         ...
44     '''
45     def decorator(to_wrap):
46         @functools.wraps(to_wrap)
47         def wrapper(*args, **kwargs):
48             warnings.simplefilter('always', DeprecationWarning)
49             warnings.warn(
50                 "%s is deprecated in favor of %s" % (to_wrap.__name__, replace_message),
51                 category=DeprecationWarning,
52                 stacklevel=2)
53             warnings.simplefilter('default', DeprecationWarning)
54             return to_wrap(*args, **kwargs)
55         return wrapper
56     return decorator
57
```

Path: `web3/utils/compat/compat_stdlib.py`
Content:
```
1 """
2 A minimal implementation of the various gevent APIs used within this codebase.
3 """
4 import time
5 import threading
6 import subprocess  # noqa: F401
7 import socket  # noqa: F401
8 from wsgiref.simple_server import make_server  # noqa: F401
9 
10 
11 sleep = time.sleep
12 
13 
14 class Timeout(Exception):
15     """
16     A limited subset of the `gevent.Timeout` context manager.
17     """
18     seconds = None
19     exception = None
20     begun_at = None
21     is_running = None
22 
23     def __init__(self, seconds=None, exception=None, *args, **kwargs):
24         self.seconds = seconds
25         self.exception = exception
26 
27     def __enter__(self):
28         self.start()
29         return self
30 
31     def __exit__(self, exc_type, exc_val, exc_tb):
32         return False
33 
34     def __str__(self):
35         if self.seconds is None:
36             return ''
37         return "{0} seconds".format(self.seconds)
38 
39     @property
40     def expire_at(self):
41         if self.seconds is None:
42             raise ValueError("Timeouts with `seconds == None` do not have an expiration time")
43         elif self.begun_at is None:
44             raise ValueError("Timeout has not been started")
45         return self.begun_at + self.seconds
46 
47     def start(self):
48         if self.is_running is not None:
49             raise ValueError("Timeout has already been started")
50         self.begun_at = time.time()
51         self.is_running = True
52 
53     def check(self):
54         if self.is_running is None:
55             raise ValueError("Timeout has not been started")
56         elif self.is_running is False:
57             raise ValueError("Timeout has already been cancelled")
58         elif self.seconds is None:
59             return
60         elif time.time() > self.expire_at:
61             self.is_running = False
62             if isinstance(self.exception, type):
63                 raise self.exception(str(self))
64             elif isinstance(self.exception, Exception):
65                 raise self.exception
66             else:
67                 raise self
68 
69     def cancel(self):
70         self.is_running = False
71 
72     def sleep(self, seconds):
73         time.sleep(seconds)
74         self.check()
75 
76 
77 class empty(object):
78     pass
79 
80 
81 class ThreadWithReturn(threading.Thread):
82     def __init__(self, target=None, args=None, kwargs=None):
83         super(ThreadWithReturn, self).__init__(
84             target=target,
85             args=args or tuple(),
86             kwargs=kwargs or {},
87         )
88         self.target = target
89         self.args = args
90         self.kwargs = kwargs
91 
92     def run(self):
93         self._return = self.target(*self.args, **self.kwargs)
94 
95     def get(self, timeout=None):
96         self.join(timeout)
97         try:
98             return self._return
99         except AttributeError:
100             raise RuntimeError("Something went wrong.  No `_return` property was set")
101 
102 
103 def spawn(target, thread_class=ThreadWithReturn, *args, **kwargs):
104     thread = thread_class(
105         target=target,
106         args=args,
107         kwargs=kwargs,
108     )
109     thread.daemon = True
110     thread.start()
111     return thread
112 
113 
114 class GreenletThread(threading.Thread):
115     def __init__(self, target=None, args=None, kwargs=None):
116         if target is None:
117             target = self._run
118         super(GreenletThread, self).__init__(
119             target=target,
120             args=args or tuple(),
121             kwargs=kwargs or {},
122         )
123         self.daemon = True
124 
125     def _run(self):
126         pass
127
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/web3/utils/compat/compat_gevent.py b/web3/utils/compat/compat_gevent.py
--- a/web3/utils/compat/compat_gevent.py
+++ b/web3/utils/compat/compat_gevent.py
@@ -5,6 +5,7 @@
     WSGIServer,
 )
 from gevent import (  # noqa: F401
+    getcurrent,
     subprocess,
     socket,
     threading,
@@ -25,6 +26,19 @@
 GreenletThread = gevent.Greenlet
 
 
+class ClassicThread(object):
+    def __init__(self, threadid):
+        self.ident = threadid
+
+
+def get_current_thread():
+    threadid = id(getcurrent())
+    return ClassicThread(threadid)
+
+
+threading.current_thread = get_current_thread
+
+
 class Timeout(gevent.Timeout):
     def check(self):
         pass
diff --git a/web3/utils/compat/compat_stdlib.py b/web3/utils/compat/compat_stdlib.py
--- a/web3/utils/compat/compat_stdlib.py
+++ b/web3/utils/compat/compat_stdlib.py
@@ -100,8 +100,8 @@
             raise RuntimeError("Something went wrong.  No `_return` property was set")
 
 
-def spawn(target, thread_class=ThreadWithReturn, *args, **kwargs):
-    thread = thread_class(
+def spawn(target, *args, **kwargs):
+    thread = ThreadWithReturn(
         target=target,
         args=args,
         kwargs=kwargs,
diff --git a/web3/utils/decorators.py b/web3/utils/decorators.py
--- a/web3/utils/decorators.py
+++ b/web3/utils/decorators.py
@@ -1,6 +1,10 @@
 import functools
 import warnings
 
+from web3.utils.compat import (
+    threading,
+)
+
 
 class combomethod(object):
     def __init__(self, method):
@@ -24,12 +28,14 @@
 
     @functools.wraps(to_wrap)
     def wrapped(*args):
-        instances = tuple(map(id, args))
-        if instances in to_wrap.__already_called:
+        arg_instances = tuple(map(id, args))
+        thread_id = threading.current_thread().ident
+        thread_local_args = (thread_id,) + arg_instances
+        if thread_local_args in to_wrap.__already_called:
             raise ValueError('Recursively called %s with %r' % (to_wrap, args))
-        to_wrap.__already_called[instances] = True
+        to_wrap.__already_called[thread_local_args] = True
         wrapped_val = to_wrap(*args)
-        del to_wrap.__already_called[instances]
+        del to_wrap.__already_called[thread_local_args]
         return wrapped_val
     return wrapped

{"golden_diff": "diff --git a/web3/utils/compat/compat_gevent.py b/web3/utils/compat/compat_gevent.py\n--- a/web3/utils/compat/compat_gevent.py\n+++ b/web3/utils/compat/compat_gevent.py\n@@ -5,6 +5,7 @@\n     WSGIServer,\n )\n from gevent import (  # noqa: F401\n+    getcurrent,\n     subprocess,\n     socket,\n     threading,\n@@ -25,6 +26,19 @@\n GreenletThread = gevent.Greenlet\n \n \n+class ClassicThread(object):\n+    def __init__(self, threadid):\n+        self.ident = threadid\n+\n+\n+def get_current_thread():\n+    threadid = id(getcurrent())\n+    return ClassicThread(threadid)\n+\n+\n+threading.current_thread = get_current_thread\n+\n+\n class Timeout(gevent.Timeout):\n     def check(self):\n         pass\ndiff --git a/web3/utils/compat/compat_stdlib.py b/web3/utils/compat/compat_stdlib.py\n--- a/web3/utils/compat/compat_stdlib.py\n+++ b/web3/utils/compat/compat_stdlib.py\n@@ -100,8 +100,8 @@\n             raise RuntimeError(\"Something went wrong.  No `_return` property was set\")\n \n \n-def spawn(target, thread_class=ThreadWithReturn, *args, **kwargs):\n-    thread = thread_class(\n+def spawn(target, *args, **kwargs):\n+    thread = ThreadWithReturn(\n         target=target,\n         args=args,\n         kwargs=kwargs,\ndiff --git a/web3/utils/decorators.py b/web3/utils/decorators.py\n--- a/web3/utils/decorators.py\n+++ b/web3/utils/decorators.py\n@@ -1,6 +1,10 @@\n import functools\n import warnings\n \n+from web3.utils.compat import (\n+    threading,\n+)\n+\n \n class combomethod(object):\n     def __init__(self, method):\n@@ -24,12 +28,14 @@\n \n     @functools.wraps(to_wrap)\n     def wrapped(*args):\n-        instances = tuple(map(id, args))\n-        if instances in to_wrap.__already_called:\n+        arg_instances = tuple(map(id, args))\n+        thread_id = threading.current_thread().ident\n+        thread_local_args = (thread_id,) + arg_instances\n+        if thread_local_args in to_wrap.__already_called:\n             raise ValueError('Recursively called %s with %r' % (to_wrap, args))\n-        to_wrap.__already_called[instances] = True\n+        to_wrap.__already_called[thread_local_args] = True\n         wrapped_val = to_wrap(*args)\n-        del to_wrap.__already_called[instances]\n+        del to_wrap.__already_called[thread_local_args]\n         return wrapped_val\n     return wrapped\n", "issue": "Suspicion that `@reject_recursive_repeats` is not thread-safe\n* Version: 3.16.2\r\n* Python: 3.6\r\n* OS: osx\r\n\r\n\r\n### What was wrong?\r\n\r\nWhen executing a few contract calls concurrently, I kept getting errors like:\r\n\r\n```\r\nFile \"/usr/local/lib/python3.6/site-packages/web3/contract.py\", line 870, in call_contract_function\r\n    normalized_data = map_abi_data(normalizers, output_types, output_data)\r\n  File \"/usr/local/lib/python3.6/site-packages/eth_utils/string.py\", line 85, in inner\r\n    return force_obj_to_text(fn(*args, **kwargs))\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/abi.py\", line 437, in map_abi_data\r\n    return pipe(data, *pipeline)\r\n  File \"cytoolz/functoolz.pyx\", line 586, in cytoolz.functoolz.pipe (cytoolz/functoolz.c:10663)\r\n  File \"cytoolz/functoolz.pyx\", line 562, in cytoolz.functoolz.c_pipe (cytoolz/functoolz.c:10494)\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/decorators.py\", line 31, in wrapped\r\n    wrapped_val = to_wrap(*args)\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/formatters.py\", line 117, in recursive_map\r\n    items_mapped = map_collection(recurse, data)\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/formatters.py\", line 104, in map_collection\r\n    return datatype(map(func, collection))\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/formatters.py\", line 116, in recurse\r\n    return recursive_map(func, item)\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/decorators.py\", line 29, in wrapped\r\n    raise ValueError('Recursively called %s with %r' % (to_wrap, args))\r\nValueError: Recursively called <function recursive_map at 0x7f012ea030d0> with (<function strip_abi_type at 0x7f012ea06ae8>, ABITypedData(abi_type='address', data='0x168910909606A2Fca90D4C28Fa39b50407b9C526'))\r\n```\r\n\r\nand\r\n\r\n```\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/contract.py\", line 870, in call_contract_function\r\n    normalized_data = map_abi_data(normalizers, output_types, output_data)\r\n  File \"/usr/local/lib/python3.6/site-packages/eth_utils/string.py\", line 85, in inner\r\n    return force_obj_to_text(fn(*args, **kwargs))\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/abi.py\", line 437, in map_abi_data\r\n    return pipe(data, *pipeline)\r\n  File \"cytoolz/functoolz.pyx\", line 586, in cytoolz.functoolz.pipe (cytoolz/functoolz.c:10663)\r\n  File \"cytoolz/functoolz.pyx\", line 562, in cytoolz.functoolz.c_pipe (cytoolz/functoolz.c:10494)\r\n  File \"/usr/local/lib/python3.6/site-packages/web3/utils/decorators.py\", line 29, in wrapped\r\n    raise ValueError('Recursively called %s with %r' % (to_wrap, args))\r\nValueError: Recursively called <function recursive_map at 0x7f012ea030d0> with (<function strip_abi_type at 0x7f012ea06ae8>, [ABITypedData(abi_type='uint256', data=1000000000000000000), ABITypedData(abi_type='address', data='0xC66eA802717bFb9833400264Dd12c2bCeAa34a6d'), ABITypedData(abi_type='uint256', data=100000000000000000000), ABITypedData(abi_type='address', data='0xECF8F87f810EcF450940c9f60066b4a7a501d6A7'), ABITypedData(abi_type='address', data='0xbe69Be9133DAA77AeAFcA0d6330c7Ba44f597b15'), ABITypedData(abi_type='bool', data=True), ABITypedData(abi_type='uint64', data=1505245070)])\r\n```\r\n\r\nWe are connecting to a Parity node.\r\n\r\n### How can it be fixed?\r\n\r\nMy suspicion is that because `@reject_recursive_repeats` keeps state in `to_wrap.__already_called`, this is not thread-safe and will fail if two threads want to parse the same data at the same time.\r\n\n", "before_files": [{"content": "import collections\n\nimport gevent\nfrom gevent.pywsgi import (  # noqa: F401\n    WSGIServer,\n)\nfrom gevent import (  # noqa: F401\n    subprocess,\n    socket,\n    threading,\n)\n\nimport pylru\n\nfrom geventhttpclient import HTTPClient\n\nfrom web3.utils.six import urlparse\n\n\n_client_cache = pylru.lrucache(8)\n\n\nsleep = gevent.sleep\nspawn = gevent.spawn\nGreenletThread = gevent.Greenlet\n\n\nclass Timeout(gevent.Timeout):\n    def check(self):\n        pass\n\n    def sleep(self, seconds):\n        gevent.sleep(seconds)\n\n\ndef make_server(host, port, application, *args, **kwargs):\n    server = WSGIServer((host, port), application, *args, **kwargs)\n    return server\n\n\ndef _get_client(host, port, **kwargs):\n    ordered_kwargs = collections.OrderedDict(sorted(kwargs.items()))\n    cache_key = '{0}:{1}:{2}'.format(\n        host,\n        port,\n        ':'.join((\n            \"{0}={1}\".format(str(key), str(value))\n            for key, value in ordered_kwargs.items()\n        ))\n    )\n    if cache_key not in _client_cache:\n        _client_cache[cache_key] = HTTPClient(host, port, **kwargs)\n    return _client_cache[cache_key]\n\n\ndef make_post_request(endpoint_uri, data, **kwargs):\n    url_parts = urlparse(endpoint_uri)\n\n    host, _, port = url_parts.netloc.partition(':')\n\n    if not port:\n        if url_parts.scheme == 'http':\n            port = 80\n        elif url_parts.scheme == 'https':\n            port = 443\n        else:\n            raise ValueError(\"Unsupported scheme: '{0}'\".format(url_parts.scheme))\n\n    kwargs.setdefault('ssl', url_parts.scheme == 'https')\n    kwargs.setdefault('connection_timeout', 10)\n    kwargs.setdefault('network_timeout', 10)\n    kwargs.setdefault('concurrency', 10)\n\n    client = _get_client(host, port, **kwargs)\n    response = client.post(url_parts.path, body=data)\n    response_body = response.read()\n\n    return response_body\n", "path": "web3/utils/compat/compat_gevent.py"}, {"content": "import functools\nimport warnings\n\n\nclass combomethod(object):\n    def __init__(self, method):\n        self.method = method\n\n    def __get__(self, obj=None, objtype=None):\n        @functools.wraps(self.method)\n        def _wrapper(*args, **kwargs):\n            if obj is not None:\n                return self.method(obj, *args, **kwargs)\n            else:\n                return self.method(objtype, *args, **kwargs)\n        return _wrapper\n\n\ndef reject_recursive_repeats(to_wrap):\n    '''\n    Prevent simple cycles by returning None when called recursively with same instance\n    '''\n    to_wrap.__already_called = {}\n\n    @functools.wraps(to_wrap)\n    def wrapped(*args):\n        instances = tuple(map(id, args))\n        if instances in to_wrap.__already_called:\n            raise ValueError('Recursively called %s with %r' % (to_wrap, args))\n        to_wrap.__already_called[instances] = True\n        wrapped_val = to_wrap(*args)\n        del to_wrap.__already_called[instances]\n        return wrapped_val\n    return wrapped\n\n\ndef deprecated_for(replace_message):\n    '''\n    Decorate a deprecated function, with info about what to use instead, like:\n\n    @deprecated_for(\"toBytes()\")\n    def toAscii(arg):\n        ...\n    '''\n    def decorator(to_wrap):\n        @functools.wraps(to_wrap)\n        def wrapper(*args, **kwargs):\n            warnings.simplefilter('always', DeprecationWarning)\n            warnings.warn(\n                \"%s is deprecated in favor of %s\" % (to_wrap.__name__, replace_message),\n                category=DeprecationWarning,\n                stacklevel=2)\n            warnings.simplefilter('default', DeprecationWarning)\n            return to_wrap(*args, **kwargs)\n        return wrapper\n    return decorator\n", "path": "web3/utils/decorators.py"}, {"content": "\"\"\"\nA minimal implementation of the various gevent APIs used within this codebase.\n\"\"\"\nimport time\nimport threading\nimport subprocess  # noqa: F401\nimport socket  # noqa: F401\nfrom wsgiref.simple_server import make_server  # noqa: F401\n\n\nsleep = time.sleep\n\n\nclass Timeout(Exception):\n    \"\"\"\n    A limited subset of the `gevent.Timeout` context manager.\n    \"\"\"\n    seconds = None\n    exception = None\n    begun_at = None\n    is_running = None\n\n    def __init__(self, seconds=None, exception=None, *args, **kwargs):\n        self.seconds = seconds\n        self.exception = exception\n\n    def __enter__(self):\n        self.start()\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        return False\n\n    def __str__(self):\n        if self.seconds is None:\n            return ''\n        return \"{0} seconds\".format(self.seconds)\n\n    @property\n    def expire_at(self):\n        if self.seconds is None:\n            raise ValueError(\"Timeouts with `seconds == None` do not have an expiration time\")\n        elif self.begun_at is None:\n            raise ValueError(\"Timeout has not been started\")\n        return self.begun_at + self.seconds\n\n    def start(self):\n        if self.is_running is not None:\n            raise ValueError(\"Timeout has already been started\")\n        self.begun_at = time.time()\n        self.is_running = True\n\n    def check(self):\n        if self.is_running is None:\n            raise ValueError(\"Timeout has not been started\")\n        elif self.is_running is False:\n            raise ValueError(\"Timeout has already been cancelled\")\n        elif self.seconds is None:\n            return\n        elif time.time() > self.expire_at:\n            self.is_running = False\n            if isinstance(self.exception, type):\n                raise self.exception(str(self))\n            elif isinstance(self.exception, Exception):\n                raise self.exception\n            else:\n                raise self\n\n    def cancel(self):\n        self.is_running = False\n\n    def sleep(self, seconds):\n        time.sleep(seconds)\n        self.check()\n\n\nclass empty(object):\n    pass\n\n\nclass ThreadWithReturn(threading.Thread):\n    def __init__(self, target=None, args=None, kwargs=None):\n        super(ThreadWithReturn, self).__init__(\n            target=target,\n            args=args or tuple(),\n            kwargs=kwargs or {},\n        )\n        self.target = target\n        self.args = args\n        self.kwargs = kwargs\n\n    def run(self):\n        self._return = self.target(*self.args, **self.kwargs)\n\n    def get(self, timeout=None):\n        self.join(timeout)\n        try:\n            return self._return\n        except AttributeError:\n            raise RuntimeError(\"Something went wrong.  No `_return` property was set\")\n\n\ndef spawn(target, thread_class=ThreadWithReturn, *args, **kwargs):\n    thread = thread_class(\n        target=target,\n        args=args,\n        kwargs=kwargs,\n    )\n    thread.daemon = True\n    thread.start()\n    return thread\n\n\nclass GreenletThread(threading.Thread):\n    def __init__(self, target=None, args=None, kwargs=None):\n        if target is None:\n            target = self._run\n        super(GreenletThread, self).__init__(\n            target=target,\n            args=args or tuple(),\n            kwargs=kwargs or {},\n        )\n        self.daemon = True\n\n    def _run(self):\n        pass\n", "path": "web3/utils/compat/compat_stdlib.py"}], "after_files": [{"content": "import collections\n\nimport gevent\nfrom gevent.pywsgi import (  # noqa: F401\n    WSGIServer,\n)\nfrom gevent import (  # noqa: F401\n    getcurrent,\n    subprocess,\n    socket,\n    threading,\n)\n\nimport pylru\n\nfrom geventhttpclient import HTTPClient\n\nfrom web3.utils.six import urlparse\n\n\n_client_cache = pylru.lrucache(8)\n\n\nsleep = gevent.sleep\nspawn = gevent.spawn\nGreenletThread = gevent.Greenlet\n\n\nclass ClassicThread(object):\n    def __init__(self, threadid):\n        self.ident = threadid\n\n\ndef get_current_thread():\n    threadid = id(getcurrent())\n    return ClassicThread(threadid)\n\n\nthreading.current_thread = get_current_thread\n\n\nclass Timeout(gevent.Timeout):\n    def check(self):\n        pass\n\n    def sleep(self, seconds):\n        gevent.sleep(seconds)\n\n\ndef make_server(host, port, application, *args, **kwargs):\n    server = WSGIServer((host, port), application, *args, **kwargs)\n    return server\n\n\ndef _get_client(host, port, **kwargs):\n    ordered_kwargs = collections.OrderedDict(sorted(kwargs.items()))\n    cache_key = '{0}:{1}:{2}'.format(\n        host,\n        port,\n        ':'.join((\n            \"{0}={1}\".format(str(key), str(value))\n            for key, value in ordered_kwargs.items()\n        ))\n    )\n    if cache_key not in _client_cache:\n        _client_cache[cache_key] = HTTPClient(host, port, **kwargs)\n    return _client_cache[cache_key]\n\n\ndef make_post_request(endpoint_uri, data, **kwargs):\n    url_parts = urlparse(endpoint_uri)\n\n    host, _, port = url_parts.netloc.partition(':')\n\n    if not port:\n        if url_parts.scheme == 'http':\n            port = 80\n        elif url_parts.scheme == 'https':\n            port = 443\n        else:\n            raise ValueError(\"Unsupported scheme: '{0}'\".format(url_parts.scheme))\n\n    kwargs.setdefault('ssl', url_parts.scheme == 'https')\n    kwargs.setdefault('connection_timeout', 10)\n    kwargs.setdefault('network_timeout', 10)\n    kwargs.setdefault('concurrency', 10)\n\n    client = _get_client(host, port, **kwargs)\n    response = client.post(url_parts.path, body=data)\n    response_body = response.read()\n\n    return response_body\n", "path": "web3/utils/compat/compat_gevent.py"}, {"content": "import functools\nimport warnings\n\nfrom web3.utils.compat import (\n    threading,\n)\n\n\nclass combomethod(object):\n    def __init__(self, method):\n        self.method = method\n\n    def __get__(self, obj=None, objtype=None):\n        @functools.wraps(self.method)\n        def _wrapper(*args, **kwargs):\n            if obj is not None:\n                return self.method(obj, *args, **kwargs)\n            else:\n                return self.method(objtype, *args, **kwargs)\n        return _wrapper\n\n\ndef reject_recursive_repeats(to_wrap):\n    '''\n    Prevent simple cycles by returning None when called recursively with same instance\n    '''\n    to_wrap.__already_called = {}\n\n    @functools.wraps(to_wrap)\n    def wrapped(*args):\n        arg_instances = tuple(map(id, args))\n        thread_id = threading.current_thread().ident\n        thread_local_args = (thread_id,) + arg_instances\n        if thread_local_args in to_wrap.__already_called:\n            raise ValueError('Recursively called %s with %r' % (to_wrap, args))\n        to_wrap.__already_called[thread_local_args] = True\n        wrapped_val = to_wrap(*args)\n        del to_wrap.__already_called[thread_local_args]\n        return wrapped_val\n    return wrapped\n\n\ndef deprecated_for(replace_message):\n    '''\n    Decorate a deprecated function, with info about what to use instead, like:\n\n    @deprecated_for(\"toBytes()\")\n    def toAscii(arg):\n        ...\n    '''\n    def decorator(to_wrap):\n        @functools.wraps(to_wrap)\n        def wrapper(*args, **kwargs):\n            warnings.simplefilter('always', DeprecationWarning)\n            warnings.warn(\n                \"%s is deprecated in favor of %s\" % (to_wrap.__name__, replace_message),\n                category=DeprecationWarning,\n                stacklevel=2)\n            warnings.simplefilter('default', DeprecationWarning)\n            return to_wrap(*args, **kwargs)\n        return wrapper\n    return decorator\n", "path": "web3/utils/decorators.py"}, {"content": "\"\"\"\nA minimal implementation of the various gevent APIs used within this codebase.\n\"\"\"\nimport time\nimport threading\nimport subprocess  # noqa: F401\nimport socket  # noqa: F401\nfrom wsgiref.simple_server import make_server  # noqa: F401\n\n\nsleep = time.sleep\n\n\nclass Timeout(Exception):\n    \"\"\"\n    A limited subset of the `gevent.Timeout` context manager.\n    \"\"\"\n    seconds = None\n    exception = None\n    begun_at = None\n    is_running = None\n\n    def __init__(self, seconds=None, exception=None, *args, **kwargs):\n        self.seconds = seconds\n        self.exception = exception\n\n    def __enter__(self):\n        self.start()\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        return False\n\n    def __str__(self):\n        if self.seconds is None:\n            return ''\n        return \"{0} seconds\".format(self.seconds)\n\n    @property\n    def expire_at(self):\n        if self.seconds is None:\n            raise ValueError(\"Timeouts with `seconds == None` do not have an expiration time\")\n        elif self.begun_at is None:\n            raise ValueError(\"Timeout has not been started\")\n        return self.begun_at + self.seconds\n\n    def start(self):\n        if self.is_running is not None:\n            raise ValueError(\"Timeout has already been started\")\n        self.begun_at = time.time()\n        self.is_running = True\n\n    def check(self):\n        if self.is_running is None:\n            raise ValueError(\"Timeout has not been started\")\n        elif self.is_running is False:\n            raise ValueError(\"Timeout has already been cancelled\")\n        elif self.seconds is None:\n            return\n        elif time.time() > self.expire_at:\n            self.is_running = False\n            if isinstance(self.exception, type):\n                raise self.exception(str(self))\n            elif isinstance(self.exception, Exception):\n                raise self.exception\n            else:\n                raise self\n\n    def cancel(self):\n        self.is_running = False\n\n    def sleep(self, seconds):\n        time.sleep(seconds)\n        self.check()\n\n\nclass empty(object):\n    pass\n\n\nclass ThreadWithReturn(threading.Thread):\n    def __init__(self, target=None, args=None, kwargs=None):\n        super(ThreadWithReturn, self).__init__(\n            target=target,\n            args=args or tuple(),\n            kwargs=kwargs or {},\n        )\n        self.target = target\n        self.args = args\n        self.kwargs = kwargs\n\n    def run(self):\n        self._return = self.target(*self.args, **self.kwargs)\n\n    def get(self, timeout=None):\n        self.join(timeout)\n        try:\n            return self._return\n        except AttributeError:\n            raise RuntimeError(\"Something went wrong.  No `_return` property was set\")\n\n\ndef spawn(target, *args, **kwargs):\n    thread = ThreadWithReturn(\n        target=target,\n        args=args,\n        kwargs=kwargs,\n    )\n    thread.daemon = True\n    thread.start()\n    return thread\n\n\nclass GreenletThread(threading.Thread):\n    def __init__(self, target=None, args=None, kwargs=None):\n        if target is None:\n            target = self._run\n        super(GreenletThread, self).__init__(\n            target=target,\n            args=args or tuple(),\n            kwargs=kwargs or {},\n        )\n        self.daemon = True\n\n    def _run(self):\n        pass\n", "path": "web3/utils/compat/compat_stdlib.py"}]}