We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
gethdev AutoProvider does not consider the WEB3_PROVIDER_URI environment variable
* Version: 5.13.0
* Python: 3.8.5
* OS: Linux (Ubuntu 20.04.1 LTS)

### What was wrong?

When using `web3.auto.gethdev`, the `WEB3_PROVIDER_URI` environment variable does not appear to be honored.

```
$ export WEB3_PROVIDER_URI=file:///path/to/node/geth.ipc

$ python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from web3.auto.gethdev import w3
>>> w3.eth.filter({'fromBlock': 'latest'})

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/<path>/.local/lib/python3.8/site-packages/web3/eth.py", line 491, in filter
    _filter_id = self.web3.manager.request_blocking(
  File "/<path>/.local/lib/python3.8/site-packages/web3/manager.py", line 154, in request_blocking
    response = self._make_request(method, params)
  File "/<path>/.local/lib/python3.8/site-packages/web3/manager.py", line 133, in _make_request
    return request_func(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py", line 74, in apply_formatters
    response = make_request(method, formatted_params)
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/gas_price_strategy.py", line 34, in middleware
    return make_request(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py", line 74, in apply_formatters
    response = make_request(method, formatted_params)
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/attrdict.py", line 33, in middleware
    response = make_request(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py", line 74, in apply_formatters
    response = make_request(method, formatted_params)
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/normalize_errors.py", line 25, in middleware
    result = make_request(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py", line 76, in apply_formatters
    response = make_request(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py", line 74, in apply_formatters
    response = make_request(method, formatted_params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
  File "/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py", line 76, in apply_formatters
    response = make_request(method, params)
  File "/<path>/.local/lib/python3.8/site-packages/web3/providers/ipc.py", line 234, in make_request
    with self._lock, self._socket as sock:
  File "/<path>/.local/lib/python3.8/site-packages/web3/providers/ipc.py", line 55, in __enter__
    raise FileNotFoundError("cannot connect to IPC socket at path: %r" % self.ipc_path)
FileNotFoundError: cannot connect to IPC socket at path: None
```

### How can it be fixed?

Apply this environment variable to the gethdev autoprovider.

--- 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/providers/ipc.py`
Content:
```
1 from json import (
2     JSONDecodeError,
3 )
4 import logging
5 import os
6 from pathlib import (
7     Path,
8 )
9 import socket
10 import sys
11 import threading
12 from types import (
13     TracebackType,
14 )
15 from typing import (
16     Any,
17     Type,
18     Union,
19 )
20 
21 from web3._utils.threads import (
22     Timeout,
23 )
24 from web3.types import (
25     RPCEndpoint,
26     RPCResponse,
27 )
28 
29 from .base import (
30     JSONBaseProvider,
31 )
32 
33 
34 def get_ipc_socket(ipc_path: str, timeout: float = 0.1) -> socket.socket:
35     if sys.platform == 'win32':
36         # On Windows named pipe is used. Simulate socket with it.
37         from web3._utils.windows import NamedPipe
38 
39         return NamedPipe(ipc_path)
40     else:
41         sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
42         sock.connect(ipc_path)
43         sock.settimeout(timeout)
44         return sock
45 
46 
47 class PersistantSocket:
48     sock = None
49 
50     def __init__(self, ipc_path: str) -> None:
51         self.ipc_path = ipc_path
52 
53     def __enter__(self) -> socket.socket:
54         if not self.ipc_path:
55             raise FileNotFoundError("cannot connect to IPC socket at path: %r" % self.ipc_path)
56 
57         if not self.sock:
58             self.sock = self._open()
59         return self.sock
60 
61     def __exit__(
62         self, exc_type: Type[BaseException], exc_value: BaseException, traceback: TracebackType
63     ) -> None:
64         # only close the socket if there was an error
65         if exc_value is not None:
66             try:
67                 self.sock.close()
68             except Exception:
69                 pass
70             self.sock = None
71 
72     def _open(self) -> socket.socket:
73         return get_ipc_socket(self.ipc_path)
74 
75     def reset(self) -> socket.socket:
76         self.sock.close()
77         self.sock = self._open()
78         return self.sock
79 
80 
81 # type ignored b/c missing return statement is by design here
82 def get_default_ipc_path() -> str:  # type: ignore
83     if sys.platform == 'darwin':
84         ipc_path = os.path.expanduser(os.path.join(
85             "~",
86             "Library",
87             "Ethereum",
88             "geth.ipc"
89         ))
90         if os.path.exists(ipc_path):
91             return ipc_path
92 
93         ipc_path = os.path.expanduser(os.path.join(
94             "~",
95             "Library",
96             "Application Support",
97             "io.parity.ethereum",
98             "jsonrpc.ipc"
99         ))
100         if os.path.exists(ipc_path):
101             return ipc_path
102 
103         base_trinity_path = Path('~').expanduser() / '.local' / 'share' / 'trinity'
104         ipc_path = str(base_trinity_path / 'mainnet' / 'ipcs-eth1' / 'jsonrpc.ipc')
105         if Path(ipc_path).exists():
106             return str(ipc_path)
107 
108     elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):
109         ipc_path = os.path.expanduser(os.path.join(
110             "~",
111             ".ethereum",
112             "geth.ipc"
113         ))
114         if os.path.exists(ipc_path):
115             return ipc_path
116 
117         ipc_path = os.path.expanduser(os.path.join(
118             "~",
119             ".local",
120             "share",
121             "io.parity.ethereum",
122             "jsonrpc.ipc"
123         ))
124         if os.path.exists(ipc_path):
125             return ipc_path
126 
127         base_trinity_path = Path('~').expanduser() / '.local' / 'share' / 'trinity'
128         ipc_path = str(base_trinity_path / 'mainnet' / 'ipcs-eth1' / 'jsonrpc.ipc')
129         if Path(ipc_path).exists():
130             return str(ipc_path)
131 
132     elif sys.platform == 'win32':
133         ipc_path = os.path.join(
134             "\\\\",
135             ".",
136             "pipe",
137             "geth.ipc"
138         )
139         if os.path.exists(ipc_path):
140             return ipc_path
141 
142         ipc_path = os.path.join(
143             "\\\\",
144             ".",
145             "pipe",
146             "jsonrpc.ipc"
147         )
148         if os.path.exists(ipc_path):
149             return ipc_path
150 
151     else:
152         raise ValueError(
153             "Unsupported platform '{0}'.  Only darwin/linux/win32/freebsd are "
154             "supported.  You must specify the ipc_path".format(sys.platform)
155         )
156 
157 
158 # type ignored b/c missing return statement is by design here
159 def get_dev_ipc_path() -> str:  # type: ignore
160     if sys.platform == 'darwin':
161         tmpdir = os.environ.get('TMPDIR', '')
162         ipc_path = os.path.expanduser(os.path.join(
163             tmpdir,
164             "geth.ipc"
165         ))
166         if os.path.exists(ipc_path):
167             return ipc_path
168 
169     elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):
170         ipc_path = os.path.expanduser(os.path.join(
171             "/tmp",
172             "geth.ipc"
173         ))
174         if os.path.exists(ipc_path):
175             return ipc_path
176 
177     elif sys.platform == 'win32':
178         ipc_path = os.path.join(
179             "\\\\",
180             ".",
181             "pipe",
182             "geth.ipc"
183         )
184         if os.path.exists(ipc_path):
185             return ipc_path
186 
187         ipc_path = os.path.join(
188             "\\\\",
189             ".",
190             "pipe",
191             "jsonrpc.ipc"
192         )
193         if os.path.exists(ipc_path):
194             return ipc_path
195 
196     else:
197         raise ValueError(
198             "Unsupported platform '{0}'.  Only darwin/linux/win32/freebsd are "
199             "supported.  You must specify the ipc_path".format(sys.platform)
200         )
201 
202 
203 class IPCProvider(JSONBaseProvider):
204     logger = logging.getLogger("web3.providers.IPCProvider")
205     _socket = None
206 
207     def __init__(
208         self,
209         ipc_path: Union[str, Path] = None,
210         timeout: int = 10,
211         *args: Any,
212         **kwargs: Any,
213     ) -> None:
214         if ipc_path is None:
215             self.ipc_path = get_default_ipc_path()
216         elif isinstance(ipc_path, str) or isinstance(ipc_path, Path):
217             self.ipc_path = str(Path(ipc_path).expanduser().resolve())
218         else:
219             raise TypeError("ipc_path must be of type string or pathlib.Path")
220 
221         self.timeout = timeout
222         self._lock = threading.Lock()
223         self._socket = PersistantSocket(self.ipc_path)
224         super().__init__()
225 
226     def __str__(self) -> str:
227         return f"<{self.__class__.__name__} {self.ipc_path}>"
228 
229     def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
230         self.logger.debug("Making request IPC. Path: %s, Method: %s",
231                           self.ipc_path, method)
232         request = self.encode_rpc_request(method, params)
233 
234         with self._lock, self._socket as sock:
235             try:
236                 sock.sendall(request)
237             except BrokenPipeError:
238                 # one extra attempt, then give up
239                 sock = self._socket.reset()
240                 sock.sendall(request)
241 
242             raw_response = b""
243             with Timeout(self.timeout) as timeout:
244                 while True:
245                     try:
246                         raw_response += sock.recv(4096)
247                     except socket.timeout:
248                         timeout.sleep(0)
249                         continue
250                     if raw_response == b"":
251                         timeout.sleep(0)
252                     elif has_valid_json_rpc_ending(raw_response):
253                         try:
254                             response = self.decode_rpc_response(raw_response)
255                         except JSONDecodeError:
256                             timeout.sleep(0)
257                             continue
258                         else:
259                             return response
260                     else:
261                         timeout.sleep(0)
262                         continue
263 
264 
265 # A valid JSON RPC response can only end in } or ] http://www.jsonrpc.org/specification
266 def has_valid_json_rpc_ending(raw_response: bytes) -> bool:
267     stripped_raw_response = raw_response.rstrip()
268     for valid_ending in [b"}", b"]"]:
269         if stripped_raw_response.endswith(valid_ending):
270             return True
271     else:
272         return False
273
```
--- 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/providers/ipc.py b/web3/providers/ipc.py
--- a/web3/providers/ipc.py
+++ b/web3/providers/ipc.py
@@ -157,7 +157,11 @@
 
 # type ignored b/c missing return statement is by design here
 def get_dev_ipc_path() -> str:  # type: ignore
-    if sys.platform == 'darwin':
+    if os.environ.get('WEB3_PROVIDER_URI', ''):
+        ipc_path = os.environ.get('WEB3_PROVIDER_URI')
+        if os.path.exists(ipc_path):
+            return ipc_path
+    elif sys.platform == 'darwin':
         tmpdir = os.environ.get('TMPDIR', '')
         ipc_path = os.path.expanduser(os.path.join(
             tmpdir,

{"golden_diff": "diff --git a/web3/providers/ipc.py b/web3/providers/ipc.py\n--- a/web3/providers/ipc.py\n+++ b/web3/providers/ipc.py\n@@ -157,7 +157,11 @@\n \n # type ignored b/c missing return statement is by design here\n def get_dev_ipc_path() -> str:  # type: ignore\n-    if sys.platform == 'darwin':\n+    if os.environ.get('WEB3_PROVIDER_URI', ''):\n+        ipc_path = os.environ.get('WEB3_PROVIDER_URI')\n+        if os.path.exists(ipc_path):\n+            return ipc_path\n+    elif sys.platform == 'darwin':\n         tmpdir = os.environ.get('TMPDIR', '')\n         ipc_path = os.path.expanduser(os.path.join(\n             tmpdir,\n", "issue": "gethdev AutoProvider does not consider the WEB3_PROVIDER_URI environment variable\n* Version: 5.13.0\r\n* Python: 3.8.5\r\n* OS: Linux (Ubuntu 20.04.1 LTS)\r\n\r\n### What was wrong?\r\n\r\nWhen using `web3.auto.gethdev`, the `WEB3_PROVIDER_URI` environment variable does not appear to be honored.\r\n\r\n```\r\n$ export WEB3_PROVIDER_URI=file:///path/to/node/geth.ipc\r\n\r\n$ python3\r\nPython 3.8.5 (default, Jul 28 2020, 12:59:40)\r\n[GCC 9.3.0] on linux\r\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\r\n>>> from web3.auto.gethdev import w3\r\n>>> w3.eth.filter({'fromBlock': 'latest'})\r\n\r\nTraceback (most recent call last):\r\n  File \"<stdin>\", line 1, in <module>\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/eth.py\", line 491, in filter\r\n    _filter_id = self.web3.manager.request_blocking(\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/manager.py\", line 154, in request_blocking\r\n    response = self._make_request(method, params)\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/manager.py\", line 133, in _make_request\r\n    return request_func(method, params)\r\n  File \"cytoolz/functoolz.pyx\", line 250, in cytoolz.functoolz.curry.__call__\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py\", line 74, in apply_formatters\r\n    response = make_request(method, formatted_params)\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/gas_price_strategy.py\", line 34, in middleware\r\n    return make_request(method, params)\r\n  File \"cytoolz/functoolz.pyx\", line 250, in cytoolz.functoolz.curry.__call__\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py\", line 74, in apply_formatters\r\n    response = make_request(method, formatted_params)\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/attrdict.py\", line 33, in middleware\r\n    response = make_request(method, params)\r\n  File \"cytoolz/functoolz.pyx\", line 250, in cytoolz.functoolz.curry.__call__\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py\", line 74, in apply_formatters\r\n    response = make_request(method, formatted_params)\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/normalize_errors.py\", line 25, in middleware\r\n    result = make_request(method, params)\r\n  File \"cytoolz/functoolz.pyx\", line 250, in cytoolz.functoolz.curry.__call__\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py\", line 76, in apply_formatters\r\n    response = make_request(method, params)\r\n  File \"cytoolz/functoolz.pyx\", line 250, in cytoolz.functoolz.curry.__call__\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py\", line 74, in apply_formatters\r\n    response = make_request(method, formatted_params)\r\n  File \"cytoolz/functoolz.pyx\", line 250, in cytoolz.functoolz.curry.__call__\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/middleware/formatting.py\", line 76, in apply_formatters\r\n    response = make_request(method, params)\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/providers/ipc.py\", line 234, in make_request\r\n    with self._lock, self._socket as sock:\r\n  File \"/<path>/.local/lib/python3.8/site-packages/web3/providers/ipc.py\", line 55, in __enter__\r\n    raise FileNotFoundError(\"cannot connect to IPC socket at path: %r\" % self.ipc_path)\r\nFileNotFoundError: cannot connect to IPC socket at path: None\r\n```\r\n\r\n### How can it be fixed?\r\n\r\nApply this environment variable to the gethdev autoprovider.\n", "before_files": [{"content": "from json import (\n    JSONDecodeError,\n)\nimport logging\nimport os\nfrom pathlib import (\n    Path,\n)\nimport socket\nimport sys\nimport threading\nfrom types import (\n    TracebackType,\n)\nfrom typing import (\n    Any,\n    Type,\n    Union,\n)\n\nfrom web3._utils.threads import (\n    Timeout,\n)\nfrom web3.types import (\n    RPCEndpoint,\n    RPCResponse,\n)\n\nfrom .base import (\n    JSONBaseProvider,\n)\n\n\ndef get_ipc_socket(ipc_path: str, timeout: float = 0.1) -> socket.socket:\n    if sys.platform == 'win32':\n        # On Windows named pipe is used. Simulate socket with it.\n        from web3._utils.windows import NamedPipe\n\n        return NamedPipe(ipc_path)\n    else:\n        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n        sock.connect(ipc_path)\n        sock.settimeout(timeout)\n        return sock\n\n\nclass PersistantSocket:\n    sock = None\n\n    def __init__(self, ipc_path: str) -> None:\n        self.ipc_path = ipc_path\n\n    def __enter__(self) -> socket.socket:\n        if not self.ipc_path:\n            raise FileNotFoundError(\"cannot connect to IPC socket at path: %r\" % self.ipc_path)\n\n        if not self.sock:\n            self.sock = self._open()\n        return self.sock\n\n    def __exit__(\n        self, exc_type: Type[BaseException], exc_value: BaseException, traceback: TracebackType\n    ) -> None:\n        # only close the socket if there was an error\n        if exc_value is not None:\n            try:\n                self.sock.close()\n            except Exception:\n                pass\n            self.sock = None\n\n    def _open(self) -> socket.socket:\n        return get_ipc_socket(self.ipc_path)\n\n    def reset(self) -> socket.socket:\n        self.sock.close()\n        self.sock = self._open()\n        return self.sock\n\n\n# type ignored b/c missing return statement is by design here\ndef get_default_ipc_path() -> str:  # type: ignore\n    if sys.platform == 'darwin':\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \"Library\",\n            \"Ethereum\",\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \"Library\",\n            \"Application Support\",\n            \"io.parity.ethereum\",\n            \"jsonrpc.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        base_trinity_path = Path('~').expanduser() / '.local' / 'share' / 'trinity'\n        ipc_path = str(base_trinity_path / 'mainnet' / 'ipcs-eth1' / 'jsonrpc.ipc')\n        if Path(ipc_path).exists():\n            return str(ipc_path)\n\n    elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \".ethereum\",\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \".local\",\n            \"share\",\n            \"io.parity.ethereum\",\n            \"jsonrpc.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        base_trinity_path = Path('~').expanduser() / '.local' / 'share' / 'trinity'\n        ipc_path = str(base_trinity_path / 'mainnet' / 'ipcs-eth1' / 'jsonrpc.ipc')\n        if Path(ipc_path).exists():\n            return str(ipc_path)\n\n    elif sys.platform == 'win32':\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"geth.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"jsonrpc.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    else:\n        raise ValueError(\n            \"Unsupported platform '{0}'.  Only darwin/linux/win32/freebsd are \"\n            \"supported.  You must specify the ipc_path\".format(sys.platform)\n        )\n\n\n# type ignored b/c missing return statement is by design here\ndef get_dev_ipc_path() -> str:  # type: ignore\n    if sys.platform == 'darwin':\n        tmpdir = os.environ.get('TMPDIR', '')\n        ipc_path = os.path.expanduser(os.path.join(\n            tmpdir,\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):\n        ipc_path = os.path.expanduser(os.path.join(\n            \"/tmp\",\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    elif sys.platform == 'win32':\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"geth.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"jsonrpc.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    else:\n        raise ValueError(\n            \"Unsupported platform '{0}'.  Only darwin/linux/win32/freebsd are \"\n            \"supported.  You must specify the ipc_path\".format(sys.platform)\n        )\n\n\nclass IPCProvider(JSONBaseProvider):\n    logger = logging.getLogger(\"web3.providers.IPCProvider\")\n    _socket = None\n\n    def __init__(\n        self,\n        ipc_path: Union[str, Path] = None,\n        timeout: int = 10,\n        *args: Any,\n        **kwargs: Any,\n    ) -> None:\n        if ipc_path is None:\n            self.ipc_path = get_default_ipc_path()\n        elif isinstance(ipc_path, str) or isinstance(ipc_path, Path):\n            self.ipc_path = str(Path(ipc_path).expanduser().resolve())\n        else:\n            raise TypeError(\"ipc_path must be of type string or pathlib.Path\")\n\n        self.timeout = timeout\n        self._lock = threading.Lock()\n        self._socket = PersistantSocket(self.ipc_path)\n        super().__init__()\n\n    def __str__(self) -> str:\n        return f\"<{self.__class__.__name__} {self.ipc_path}>\"\n\n    def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:\n        self.logger.debug(\"Making request IPC. Path: %s, Method: %s\",\n                          self.ipc_path, method)\n        request = self.encode_rpc_request(method, params)\n\n        with self._lock, self._socket as sock:\n            try:\n                sock.sendall(request)\n            except BrokenPipeError:\n                # one extra attempt, then give up\n                sock = self._socket.reset()\n                sock.sendall(request)\n\n            raw_response = b\"\"\n            with Timeout(self.timeout) as timeout:\n                while True:\n                    try:\n                        raw_response += sock.recv(4096)\n                    except socket.timeout:\n                        timeout.sleep(0)\n                        continue\n                    if raw_response == b\"\":\n                        timeout.sleep(0)\n                    elif has_valid_json_rpc_ending(raw_response):\n                        try:\n                            response = self.decode_rpc_response(raw_response)\n                        except JSONDecodeError:\n                            timeout.sleep(0)\n                            continue\n                        else:\n                            return response\n                    else:\n                        timeout.sleep(0)\n                        continue\n\n\n# A valid JSON RPC response can only end in } or ] http://www.jsonrpc.org/specification\ndef has_valid_json_rpc_ending(raw_response: bytes) -> bool:\n    stripped_raw_response = raw_response.rstrip()\n    for valid_ending in [b\"}\", b\"]\"]:\n        if stripped_raw_response.endswith(valid_ending):\n            return True\n    else:\n        return False\n", "path": "web3/providers/ipc.py"}], "after_files": [{"content": "from json import (\n    JSONDecodeError,\n)\nimport logging\nimport os\nfrom pathlib import (\n    Path,\n)\nimport socket\nimport sys\nimport threading\nfrom types import (\n    TracebackType,\n)\nfrom typing import (\n    Any,\n    Type,\n    Union,\n)\n\nfrom web3._utils.threads import (\n    Timeout,\n)\nfrom web3.types import (\n    RPCEndpoint,\n    RPCResponse,\n)\n\nfrom .base import (\n    JSONBaseProvider,\n)\n\n\ndef get_ipc_socket(ipc_path: str, timeout: float = 0.1) -> socket.socket:\n    if sys.platform == 'win32':\n        # On Windows named pipe is used. Simulate socket with it.\n        from web3._utils.windows import NamedPipe\n\n        return NamedPipe(ipc_path)\n    else:\n        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n        sock.connect(ipc_path)\n        sock.settimeout(timeout)\n        return sock\n\n\nclass PersistantSocket:\n    sock = None\n\n    def __init__(self, ipc_path: str) -> None:\n        self.ipc_path = ipc_path\n\n    def __enter__(self) -> socket.socket:\n        if not self.ipc_path:\n            raise FileNotFoundError(\"cannot connect to IPC socket at path: %r\" % self.ipc_path)\n\n        if not self.sock:\n            self.sock = self._open()\n        return self.sock\n\n    def __exit__(\n        self, exc_type: Type[BaseException], exc_value: BaseException, traceback: TracebackType\n    ) -> None:\n        # only close the socket if there was an error\n        if exc_value is not None:\n            try:\n                self.sock.close()\n            except Exception:\n                pass\n            self.sock = None\n\n    def _open(self) -> socket.socket:\n        return get_ipc_socket(self.ipc_path)\n\n    def reset(self) -> socket.socket:\n        self.sock.close()\n        self.sock = self._open()\n        return self.sock\n\n\n# type ignored b/c missing return statement is by design here\ndef get_default_ipc_path() -> str:  # type: ignore\n    if sys.platform == 'darwin':\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \"Library\",\n            \"Ethereum\",\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \"Library\",\n            \"Application Support\",\n            \"io.parity.ethereum\",\n            \"jsonrpc.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        base_trinity_path = Path('~').expanduser() / '.local' / 'share' / 'trinity'\n        ipc_path = str(base_trinity_path / 'mainnet' / 'ipcs-eth1' / 'jsonrpc.ipc')\n        if Path(ipc_path).exists():\n            return str(ipc_path)\n\n    elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \".ethereum\",\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.expanduser(os.path.join(\n            \"~\",\n            \".local\",\n            \"share\",\n            \"io.parity.ethereum\",\n            \"jsonrpc.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        base_trinity_path = Path('~').expanduser() / '.local' / 'share' / 'trinity'\n        ipc_path = str(base_trinity_path / 'mainnet' / 'ipcs-eth1' / 'jsonrpc.ipc')\n        if Path(ipc_path).exists():\n            return str(ipc_path)\n\n    elif sys.platform == 'win32':\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"geth.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"jsonrpc.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    else:\n        raise ValueError(\n            \"Unsupported platform '{0}'.  Only darwin/linux/win32/freebsd are \"\n            \"supported.  You must specify the ipc_path\".format(sys.platform)\n        )\n\n\n# type ignored b/c missing return statement is by design here\ndef get_dev_ipc_path() -> str:  # type: ignore\n    if os.environ.get('WEB3_PROVIDER_URI', ''):\n        ipc_path = os.environ.get('WEB3_PROVIDER_URI')\n        if os.path.exists(ipc_path):\n            return ipc_path\n    elif sys.platform == 'darwin':\n        tmpdir = os.environ.get('TMPDIR', '')\n        ipc_path = os.path.expanduser(os.path.join(\n            tmpdir,\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):\n        ipc_path = os.path.expanduser(os.path.join(\n            \"/tmp\",\n            \"geth.ipc\"\n        ))\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    elif sys.platform == 'win32':\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"geth.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n        ipc_path = os.path.join(\n            \"\\\\\\\\\",\n            \".\",\n            \"pipe\",\n            \"jsonrpc.ipc\"\n        )\n        if os.path.exists(ipc_path):\n            return ipc_path\n\n    else:\n        raise ValueError(\n            \"Unsupported platform '{0}'.  Only darwin/linux/win32/freebsd are \"\n            \"supported.  You must specify the ipc_path\".format(sys.platform)\n        )\n\n\nclass IPCProvider(JSONBaseProvider):\n    logger = logging.getLogger(\"web3.providers.IPCProvider\")\n    _socket = None\n\n    def __init__(\n        self,\n        ipc_path: Union[str, Path] = None,\n        timeout: int = 10,\n        *args: Any,\n        **kwargs: Any,\n    ) -> None:\n        if ipc_path is None:\n            self.ipc_path = get_default_ipc_path()\n        elif isinstance(ipc_path, str) or isinstance(ipc_path, Path):\n            self.ipc_path = str(Path(ipc_path).expanduser().resolve())\n        else:\n            raise TypeError(\"ipc_path must be of type string or pathlib.Path\")\n\n        self.timeout = timeout\n        self._lock = threading.Lock()\n        self._socket = PersistantSocket(self.ipc_path)\n        super().__init__()\n\n    def __str__(self) -> str:\n        return f\"<{self.__class__.__name__} {self.ipc_path}>\"\n\n    def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:\n        self.logger.debug(\"Making request IPC. Path: %s, Method: %s\",\n                          self.ipc_path, method)\n        request = self.encode_rpc_request(method, params)\n\n        with self._lock, self._socket as sock:\n            try:\n                sock.sendall(request)\n            except BrokenPipeError:\n                # one extra attempt, then give up\n                sock = self._socket.reset()\n                sock.sendall(request)\n\n            raw_response = b\"\"\n            with Timeout(self.timeout) as timeout:\n                while True:\n                    try:\n                        raw_response += sock.recv(4096)\n                    except socket.timeout:\n                        timeout.sleep(0)\n                        continue\n                    if raw_response == b\"\":\n                        timeout.sleep(0)\n                    elif has_valid_json_rpc_ending(raw_response):\n                        try:\n                            response = self.decode_rpc_response(raw_response)\n                        except JSONDecodeError:\n                            timeout.sleep(0)\n                            continue\n                        else:\n                            return response\n                    else:\n                        timeout.sleep(0)\n                        continue\n\n\n# A valid JSON RPC response can only end in } or ] http://www.jsonrpc.org/specification\ndef has_valid_json_rpc_ending(raw_response: bytes) -> bool:\n    stripped_raw_response = raw_response.rstrip()\n    for valid_ending in [b\"}\", b\"]\"]:\n        if stripped_raw_response.endswith(valid_ending):\n            return True\n    else:\n        return False\n", "path": "web3/providers/ipc.py"}]}