We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add tests for fspath


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `trio/_util.py`
Content:
```
1 # Little utilities we use internally
2 
3 import os
4 import sys
5 import pathlib
6 from functools import wraps
7 import typing as t
8 
9 import async_generator
10 
11 # There's a dependency loop here... _core is allowed to use this file (in fact
12 # it's the *only* file in the main trio/ package it's allowed to use), but
13 # ConflictDetector needs checkpoint so it also has to import
14 # _core. Possibly we should split this file into two: one for true generic
15 # low-level utility code, and one for higher level helpers?
16 from . import _core
17 
18 __all__ = [
19     "signal_raise", "aiter_compat", "acontextmanager", "ConflictDetector",
20     "fixup_module_metadata", "fspath"
21 ]
22 
23 # Equivalent to the C function raise(), which Python doesn't wrap
24 if os.name == "nt":
25     # On windows, os.kill exists but is really weird.
26     #
27     # If you give it CTRL_C_EVENT or CTRL_BREAK_EVENT, it tries to deliver
28     # those using GenerateConsoleCtrlEvent. But I found that when I tried
29     # to run my test normally, it would freeze waiting... unless I added
30     # print statements, in which case the test suddenly worked. So I guess
31     # these signals are only delivered if/when you access the console? I
32     # don't really know what was going on there. From reading the
33     # GenerateConsoleCtrlEvent docs I don't know how it worked at all.
34     #
35     # I later spent a bunch of time trying to make GenerateConsoleCtrlEvent
36     # work for creating synthetic control-C events, and... failed
37     # utterly. There are lots of details in the code and comments
38     # removed/added at this commit:
39     #     https://github.com/python-trio/trio/commit/95843654173e3e826c34d70a90b369ba6edf2c23
40     #
41     # OTOH, if you pass os.kill any *other* signal number... then CPython
42     # just calls TerminateProcess (wtf).
43     #
44     # So, anyway, os.kill is not so useful for testing purposes. Instead
45     # we use raise():
46     #
47     #   https://msdn.microsoft.com/en-us/library/dwwzkt4c.aspx
48     #
49     # Have to import cffi inside the 'if os.name' block because we don't
50     # depend on cffi on non-Windows platforms. (It would be easy to switch
51     # this to ctypes though if we ever remove the cffi dependency.)
52     #
53     # Some more information:
54     #   https://bugs.python.org/issue26350
55     #
56     # Anyway, we use this for two things:
57     # - redelivering unhandled signals
58     # - generating synthetic signals for tests
59     # and for both of those purposes, 'raise' works fine.
60     import cffi
61 
62     _ffi = cffi.FFI()
63     _ffi.cdef("int raise(int);")
64     _lib = _ffi.dlopen("api-ms-win-crt-runtime-l1-1-0.dll")
65     signal_raise = getattr(_lib, "raise")
66 else:
67 
68     def signal_raise(signum):
69         os.kill(os.getpid(), signum)
70 
71 
72 # Decorator to handle the change to __aiter__ in 3.5.2
73 def aiter_compat(aiter_impl):
74     if sys.version_info < (3, 5, 2):
75 
76         @wraps(aiter_impl)
77         async def __aiter__(*args, **kwargs):
78             return aiter_impl(*args, **kwargs)
79 
80         return __aiter__
81     else:
82         return aiter_impl
83 
84 
85 # Very much derived from the one in contextlib, by copy/pasting and then
86 # asyncifying everything. (Also I dropped the obscure support for using
87 # context managers as function decorators. It could be re-added; I just
88 # couldn't be bothered.)
89 # So this is a derivative work licensed under the PSF License, which requires
90 # the following notice:
91 #
92 # Copyright © 2001-2017 Python Software Foundation; All Rights Reserved
93 class _AsyncGeneratorContextManager:
94     def __init__(self, func, args, kwds):
95         self._func_name = func.__name__
96         self._agen = func(*args, **kwds).__aiter__()
97 
98     async def __aenter__(self):
99         if sys.version_info < (3, 5, 2):
100             self._agen = await self._agen
101         try:
102             return await self._agen.asend(None)
103         except StopAsyncIteration:
104             raise RuntimeError("async generator didn't yield") from None
105 
106     async def __aexit__(self, type, value, traceback):
107         if type is None:
108             try:
109                 await self._agen.asend(None)
110             except StopAsyncIteration:
111                 return False
112             else:
113                 raise RuntimeError("async generator didn't stop")
114         else:
115             # It used to be possible to have type != None, value == None:
116             #    https://bugs.python.org/issue1705170
117             # but AFAICT this can't happen anymore.
118             assert value is not None
119             try:
120                 await self._agen.athrow(type, value, traceback)
121                 raise RuntimeError(
122                     "async generator didn't stop after athrow()"
123                 )
124             except StopAsyncIteration as exc:
125                 # Suppress StopIteration *unless* it's the same exception that
126                 # was passed to throw().  This prevents a StopIteration
127                 # raised inside the "with" statement from being suppressed.
128                 return (exc is not value)
129             except RuntimeError as exc:
130                 # Don't re-raise the passed in exception. (issue27112)
131                 if exc is value:
132                     return False
133                 # Likewise, avoid suppressing if a StopIteration exception
134                 # was passed to throw() and later wrapped into a RuntimeError
135                 # (see PEP 479).
136                 if (
137                     isinstance(value,
138                                (StopIteration, StopAsyncIteration))
139                     and exc.__cause__ is value
140                 ):
141                     return False
142                 raise
143             except:
144                 # only re-raise if it's *not* the exception that was
145                 # passed to throw(), because __exit__() must not raise
146                 # an exception unless __exit__() itself failed.  But throw()
147                 # has to raise the exception to signal propagation, so this
148                 # fixes the impedance mismatch between the throw() protocol
149                 # and the __exit__() protocol.
150                 #
151                 if sys.exc_info()[1] is value:
152                     return False
153                 raise
154 
155     def __enter__(self):
156         raise RuntimeError(
157             "use 'async with {func_name}(...)', not 'with {func_name}(...)'".
158             format(func_name=self._func_name)
159         )
160 
161     def __exit__(self):  # pragma: no cover
162         assert False, """Never called, but should be defined"""
163 
164 
165 def acontextmanager(func):
166     """Like @contextmanager, but async."""
167     if not async_generator.isasyncgenfunction(func):
168         raise TypeError(
169             "must be an async generator (native or from async_generator; "
170             "if using @async_generator then @acontextmanager must be on top."
171         )
172 
173     @wraps(func)
174     def helper(*args, **kwds):
175         return _AsyncGeneratorContextManager(func, args, kwds)
176 
177     # A hint for sphinxcontrib-trio:
178     helper.__returns_acontextmanager__ = True
179     return helper
180 
181 
182 class _ConflictDetectorSync:
183     def __init__(self, msg):
184         self._msg = msg
185         self._held = False
186 
187     def __enter__(self):
188         if self._held:
189             raise _core.ResourceBusyError(self._msg)
190         else:
191             self._held = True
192 
193     def __exit__(self, *args):
194         self._held = False
195 
196 
197 class ConflictDetector:
198     """Detect when two tasks are about to perform operations that would
199     conflict.
200 
201     Use as an async context manager; if two tasks enter it at the same
202     time then the second one raises an error. You can use it when there are
203     two pieces of code that *would* collide and need a lock if they ever were
204     called at the same time, but that should never happen.
205 
206     We use this in particular for things like, making sure that two different
207     tasks don't call sendall simultaneously on the same stream.
208 
209     This executes a checkpoint on entry. That's the only reason it's async.
210 
211     To use from sync code, do ``with cd.sync``; this is just like ``async with
212     cd`` except that it doesn't execute a checkpoint.
213 
214     """
215 
216     def __init__(self, msg):
217         self.sync = _ConflictDetectorSync(msg)
218 
219     async def __aenter__(self):
220         await _core.checkpoint()
221         return self.sync.__enter__()
222 
223     async def __aexit__(self, *args):
224         return self.sync.__exit__()
225 
226 
227 def async_wraps(cls, wrapped_cls, attr_name):
228     """Similar to wraps, but for async wrappers of non-async functions.
229 
230     """
231 
232     def decorator(func):
233         func.__name__ = attr_name
234         func.__qualname__ = '.'.join((cls.__qualname__, attr_name))
235 
236         func.__doc__ = """Like :meth:`~{}.{}.{}`, but async.
237 
238         """.format(
239             wrapped_cls.__module__, wrapped_cls.__qualname__, attr_name
240         )
241 
242         return func
243 
244     return decorator
245 
246 
247 def fixup_module_metadata(module_name, namespace):
248     def fix_one(obj):
249         mod = getattr(obj, "__module__", None)
250         if mod is not None and mod.startswith("trio."):
251             obj.__module__ = module_name
252             if isinstance(obj, type):
253                 for attr_value in obj.__dict__.values():
254                     fix_one(attr_value)
255 
256     for objname in namespace["__all__"]:
257         obj = namespace[objname]
258         fix_one(obj)
259 
260 
261 # This is based on the PEP 519 fspath implementation.
262 # The function has been adapted to work with pathlib objects on python 3.5
263 # The input typehint is removed as there is no os.PathLike on 3.5.
264 # See: https://www.python.org/dev/peps/pep-0519/#os
265 
266 
267 def fspath(path) -> t.Union[str, bytes]:
268     """Return the string representation of the path.
269 
270     If str or bytes is passed in, it is returned unchanged. If a pre-python 3.6
271     pathlib object is passed, its string representation is returned. If
272     __fspath__() returns something other than str or bytes then TypeError is
273     raised. If this function is given something that is not str, bytes,
274     pathlib.PurePath or os.PathLike then TypeError is raised.
275     """
276     if isinstance(path, (str, bytes)):
277         return path
278 
279     # Work from the object's type to match method resolution of other magic
280     # methods.
281     path_type = type(path)
282     try:
283         path = path_type.__fspath__(path)
284     except AttributeError:
285         if hasattr(path_type, '__fspath__'):
286             raise
287         # On python 3.5 pathlib objects don't have an __fspath__ method.
288         # but we still want to get their string representation.
289         if isinstance(path, pathlib.PurePath):
290             return str(path)
291     else:
292         if isinstance(path, (str, bytes)):
293             return path
294         else:
295             raise TypeError(
296                 "expected __fspath__() to return str or bytes, "
297                 "not " + type(path).__name__
298             )
299 
300     raise TypeError(
301         "expected str, bytes or os.PathLike object, not " + path_type.__name__
302     )
303 
304 
305 if hasattr(os, "fspath"):
306     fspath = os.fspath
307
```
--- 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/trio/_util.py b/trio/_util.py
--- a/trio/_util.py
+++ b/trio/_util.py
@@ -258,48 +258,60 @@
         fix_one(obj)
 
 
-# This is based on the PEP 519 fspath implementation.
-# The function has been adapted to work with pathlib objects on python 3.5
+# os.fspath is defined on Python 3.6+ but we need to support Python 3.5 too
+# This is why we provide our own implementation. On Python 3.6+ we use the
+# StdLib's version and on Python 3.5 our own version.
+# Our own implementation implementation is based on PEP 519 while it has also
+# been adapted to work with pathlib objects on python 3.5
 # The input typehint is removed as there is no os.PathLike on 3.5.
 # See: https://www.python.org/dev/peps/pep-0519/#os
 
 
 def fspath(path) -> t.Union[str, bytes]:
-    """Return the string representation of the path.
-
-    If str or bytes is passed in, it is returned unchanged. If a pre-python 3.6
-    pathlib object is passed, its string representation is returned. If
-    __fspath__() returns something other than str or bytes then TypeError is
-    raised. If this function is given something that is not str, bytes,
-    pathlib.PurePath or os.PathLike then TypeError is raised.
+    """Return the path representation of a path-like object.
+
+    Returns
+    -------
+    - If str or bytes is passed in, it is returned unchanged.
+    - If the os.PathLike interface is implemented it is used to get the path
+      representation.
+    - If the python version is 3.5 or earlier and a pathlib object is passed,
+      the object's string representation is returned.
+
+    Raises
+    ------
+    - Regardless of the input, if the path representation (e.g. the value
+      returned from __fspath__) is not str or bytes, TypeError is raised.
+    - If the provided path is not str, bytes, pathlib.PurePath or os.PathLike,
+      TypeError is raised.
     """
     if isinstance(path, (str, bytes)):
         return path
-
     # Work from the object's type to match method resolution of other magic
     # methods.
     path_type = type(path)
+    # On python 3.5, pathlib objects don't have the __fspath__ method,
+    # but we still want to get their string representation.
+    if issubclass(path_type, pathlib.PurePath):
+        return str(path)
     try:
-        path = path_type.__fspath__(path)
+        path_repr = path_type.__fspath__(path)
     except AttributeError:
         if hasattr(path_type, '__fspath__'):
             raise
-        # On python 3.5 pathlib objects don't have an __fspath__ method.
-        # but we still want to get their string representation.
-        if isinstance(path, pathlib.PurePath):
-            return str(path)
-    else:
-        if isinstance(path, (str, bytes)):
-            return path
         else:
             raise TypeError(
-                "expected __fspath__() to return str or bytes, "
-                "not " + type(path).__name__
+                "expected str, bytes or os.PathLike object, "
+                "not " + path_type.__name__
             )
-
-    raise TypeError(
-        "expected str, bytes or os.PathLike object, not " + path_type.__name__
-    )
+    if isinstance(path_repr, (str, bytes)):
+        return path_repr
+    else:
+        raise TypeError(
+            "expected {}.__fspath__() to return str or bytes, "
+            "not {}".format(path_type.__name__,
+                            type(path_repr).__name__)
+        )
 
 
 if hasattr(os, "fspath"):

{"golden_diff": "diff --git a/trio/_util.py b/trio/_util.py\n--- a/trio/_util.py\n+++ b/trio/_util.py\n@@ -258,48 +258,60 @@\n         fix_one(obj)\n \n \n-# This is based on the PEP 519 fspath implementation.\n-# The function has been adapted to work with pathlib objects on python 3.5\n+# os.fspath is defined on Python 3.6+ but we need to support Python 3.5 too\n+# This is why we provide our own implementation. On Python 3.6+ we use the\n+# StdLib's version and on Python 3.5 our own version.\n+# Our own implementation implementation is based on PEP 519 while it has also\n+# been adapted to work with pathlib objects on python 3.5\n # The input typehint is removed as there is no os.PathLike on 3.5.\n # See: https://www.python.org/dev/peps/pep-0519/#os\n \n \n def fspath(path) -> t.Union[str, bytes]:\n-    \"\"\"Return the string representation of the path.\n-\n-    If str or bytes is passed in, it is returned unchanged. If a pre-python 3.6\n-    pathlib object is passed, its string representation is returned. If\n-    __fspath__() returns something other than str or bytes then TypeError is\n-    raised. If this function is given something that is not str, bytes,\n-    pathlib.PurePath or os.PathLike then TypeError is raised.\n+    \"\"\"Return the path representation of a path-like object.\n+\n+    Returns\n+    -------\n+    - If str or bytes is passed in, it is returned unchanged.\n+    - If the os.PathLike interface is implemented it is used to get the path\n+      representation.\n+    - If the python version is 3.5 or earlier and a pathlib object is passed,\n+      the object's string representation is returned.\n+\n+    Raises\n+    ------\n+    - Regardless of the input, if the path representation (e.g. the value\n+      returned from __fspath__) is not str or bytes, TypeError is raised.\n+    - If the provided path is not str, bytes, pathlib.PurePath or os.PathLike,\n+      TypeError is raised.\n     \"\"\"\n     if isinstance(path, (str, bytes)):\n         return path\n-\n     # Work from the object's type to match method resolution of other magic\n     # methods.\n     path_type = type(path)\n+    # On python 3.5, pathlib objects don't have the __fspath__ method,\n+    # but we still want to get their string representation.\n+    if issubclass(path_type, pathlib.PurePath):\n+        return str(path)\n     try:\n-        path = path_type.__fspath__(path)\n+        path_repr = path_type.__fspath__(path)\n     except AttributeError:\n         if hasattr(path_type, '__fspath__'):\n             raise\n-        # On python 3.5 pathlib objects don't have an __fspath__ method.\n-        # but we still want to get their string representation.\n-        if isinstance(path, pathlib.PurePath):\n-            return str(path)\n-    else:\n-        if isinstance(path, (str, bytes)):\n-            return path\n         else:\n             raise TypeError(\n-                \"expected __fspath__() to return str or bytes, \"\n-                \"not \" + type(path).__name__\n+                \"expected str, bytes or os.PathLike object, \"\n+                \"not \" + path_type.__name__\n             )\n-\n-    raise TypeError(\n-        \"expected str, bytes or os.PathLike object, not \" + path_type.__name__\n-    )\n+    if isinstance(path_repr, (str, bytes)):\n+        return path_repr\n+    else:\n+        raise TypeError(\n+            \"expected {}.__fspath__() to return str or bytes, \"\n+            \"not {}\".format(path_type.__name__,\n+                            type(path_repr).__name__)\n+        )\n \n \n if hasattr(os, \"fspath\"):\n", "issue": "Add tests for fspath\n\n", "before_files": [{"content": "# Little utilities we use internally\n\nimport os\nimport sys\nimport pathlib\nfrom functools import wraps\nimport typing as t\n\nimport async_generator\n\n# There's a dependency loop here... _core is allowed to use this file (in fact\n# it's the *only* file in the main trio/ package it's allowed to use), but\n# ConflictDetector needs checkpoint so it also has to import\n# _core. Possibly we should split this file into two: one for true generic\n# low-level utility code, and one for higher level helpers?\nfrom . import _core\n\n__all__ = [\n    \"signal_raise\", \"aiter_compat\", \"acontextmanager\", \"ConflictDetector\",\n    \"fixup_module_metadata\", \"fspath\"\n]\n\n# Equivalent to the C function raise(), which Python doesn't wrap\nif os.name == \"nt\":\n    # On windows, os.kill exists but is really weird.\n    #\n    # If you give it CTRL_C_EVENT or CTRL_BREAK_EVENT, it tries to deliver\n    # those using GenerateConsoleCtrlEvent. But I found that when I tried\n    # to run my test normally, it would freeze waiting... unless I added\n    # print statements, in which case the test suddenly worked. So I guess\n    # these signals are only delivered if/when you access the console? I\n    # don't really know what was going on there. From reading the\n    # GenerateConsoleCtrlEvent docs I don't know how it worked at all.\n    #\n    # I later spent a bunch of time trying to make GenerateConsoleCtrlEvent\n    # work for creating synthetic control-C events, and... failed\n    # utterly. There are lots of details in the code and comments\n    # removed/added at this commit:\n    #     https://github.com/python-trio/trio/commit/95843654173e3e826c34d70a90b369ba6edf2c23\n    #\n    # OTOH, if you pass os.kill any *other* signal number... then CPython\n    # just calls TerminateProcess (wtf).\n    #\n    # So, anyway, os.kill is not so useful for testing purposes. Instead\n    # we use raise():\n    #\n    #   https://msdn.microsoft.com/en-us/library/dwwzkt4c.aspx\n    #\n    # Have to import cffi inside the 'if os.name' block because we don't\n    # depend on cffi on non-Windows platforms. (It would be easy to switch\n    # this to ctypes though if we ever remove the cffi dependency.)\n    #\n    # Some more information:\n    #   https://bugs.python.org/issue26350\n    #\n    # Anyway, we use this for two things:\n    # - redelivering unhandled signals\n    # - generating synthetic signals for tests\n    # and for both of those purposes, 'raise' works fine.\n    import cffi\n\n    _ffi = cffi.FFI()\n    _ffi.cdef(\"int raise(int);\")\n    _lib = _ffi.dlopen(\"api-ms-win-crt-runtime-l1-1-0.dll\")\n    signal_raise = getattr(_lib, \"raise\")\nelse:\n\n    def signal_raise(signum):\n        os.kill(os.getpid(), signum)\n\n\n# Decorator to handle the change to __aiter__ in 3.5.2\ndef aiter_compat(aiter_impl):\n    if sys.version_info < (3, 5, 2):\n\n        @wraps(aiter_impl)\n        async def __aiter__(*args, **kwargs):\n            return aiter_impl(*args, **kwargs)\n\n        return __aiter__\n    else:\n        return aiter_impl\n\n\n# Very much derived from the one in contextlib, by copy/pasting and then\n# asyncifying everything. (Also I dropped the obscure support for using\n# context managers as function decorators. It could be re-added; I just\n# couldn't be bothered.)\n# So this is a derivative work licensed under the PSF License, which requires\n# the following notice:\n#\n# Copyright \u00a9 2001-2017 Python Software Foundation; All Rights Reserved\nclass _AsyncGeneratorContextManager:\n    def __init__(self, func, args, kwds):\n        self._func_name = func.__name__\n        self._agen = func(*args, **kwds).__aiter__()\n\n    async def __aenter__(self):\n        if sys.version_info < (3, 5, 2):\n            self._agen = await self._agen\n        try:\n            return await self._agen.asend(None)\n        except StopAsyncIteration:\n            raise RuntimeError(\"async generator didn't yield\") from None\n\n    async def __aexit__(self, type, value, traceback):\n        if type is None:\n            try:\n                await self._agen.asend(None)\n            except StopAsyncIteration:\n                return False\n            else:\n                raise RuntimeError(\"async generator didn't stop\")\n        else:\n            # It used to be possible to have type != None, value == None:\n            #    https://bugs.python.org/issue1705170\n            # but AFAICT this can't happen anymore.\n            assert value is not None\n            try:\n                await self._agen.athrow(type, value, traceback)\n                raise RuntimeError(\n                    \"async generator didn't stop after athrow()\"\n                )\n            except StopAsyncIteration as exc:\n                # Suppress StopIteration *unless* it's the same exception that\n                # was passed to throw().  This prevents a StopIteration\n                # raised inside the \"with\" statement from being suppressed.\n                return (exc is not value)\n            except RuntimeError as exc:\n                # Don't re-raise the passed in exception. (issue27112)\n                if exc is value:\n                    return False\n                # Likewise, avoid suppressing if a StopIteration exception\n                # was passed to throw() and later wrapped into a RuntimeError\n                # (see PEP 479).\n                if (\n                    isinstance(value,\n                               (StopIteration, StopAsyncIteration))\n                    and exc.__cause__ is value\n                ):\n                    return False\n                raise\n            except:\n                # only re-raise if it's *not* the exception that was\n                # passed to throw(), because __exit__() must not raise\n                # an exception unless __exit__() itself failed.  But throw()\n                # has to raise the exception to signal propagation, so this\n                # fixes the impedance mismatch between the throw() protocol\n                # and the __exit__() protocol.\n                #\n                if sys.exc_info()[1] is value:\n                    return False\n                raise\n\n    def __enter__(self):\n        raise RuntimeError(\n            \"use 'async with {func_name}(...)', not 'with {func_name}(...)'\".\n            format(func_name=self._func_name)\n        )\n\n    def __exit__(self):  # pragma: no cover\n        assert False, \"\"\"Never called, but should be defined\"\"\"\n\n\ndef acontextmanager(func):\n    \"\"\"Like @contextmanager, but async.\"\"\"\n    if not async_generator.isasyncgenfunction(func):\n        raise TypeError(\n            \"must be an async generator (native or from async_generator; \"\n            \"if using @async_generator then @acontextmanager must be on top.\"\n        )\n\n    @wraps(func)\n    def helper(*args, **kwds):\n        return _AsyncGeneratorContextManager(func, args, kwds)\n\n    # A hint for sphinxcontrib-trio:\n    helper.__returns_acontextmanager__ = True\n    return helper\n\n\nclass _ConflictDetectorSync:\n    def __init__(self, msg):\n        self._msg = msg\n        self._held = False\n\n    def __enter__(self):\n        if self._held:\n            raise _core.ResourceBusyError(self._msg)\n        else:\n            self._held = True\n\n    def __exit__(self, *args):\n        self._held = False\n\n\nclass ConflictDetector:\n    \"\"\"Detect when two tasks are about to perform operations that would\n    conflict.\n\n    Use as an async context manager; if two tasks enter it at the same\n    time then the second one raises an error. You can use it when there are\n    two pieces of code that *would* collide and need a lock if they ever were\n    called at the same time, but that should never happen.\n\n    We use this in particular for things like, making sure that two different\n    tasks don't call sendall simultaneously on the same stream.\n\n    This executes a checkpoint on entry. That's the only reason it's async.\n\n    To use from sync code, do ``with cd.sync``; this is just like ``async with\n    cd`` except that it doesn't execute a checkpoint.\n\n    \"\"\"\n\n    def __init__(self, msg):\n        self.sync = _ConflictDetectorSync(msg)\n\n    async def __aenter__(self):\n        await _core.checkpoint()\n        return self.sync.__enter__()\n\n    async def __aexit__(self, *args):\n        return self.sync.__exit__()\n\n\ndef async_wraps(cls, wrapped_cls, attr_name):\n    \"\"\"Similar to wraps, but for async wrappers of non-async functions.\n\n    \"\"\"\n\n    def decorator(func):\n        func.__name__ = attr_name\n        func.__qualname__ = '.'.join((cls.__qualname__, attr_name))\n\n        func.__doc__ = \"\"\"Like :meth:`~{}.{}.{}`, but async.\n\n        \"\"\".format(\n            wrapped_cls.__module__, wrapped_cls.__qualname__, attr_name\n        )\n\n        return func\n\n    return decorator\n\n\ndef fixup_module_metadata(module_name, namespace):\n    def fix_one(obj):\n        mod = getattr(obj, \"__module__\", None)\n        if mod is not None and mod.startswith(\"trio.\"):\n            obj.__module__ = module_name\n            if isinstance(obj, type):\n                for attr_value in obj.__dict__.values():\n                    fix_one(attr_value)\n\n    for objname in namespace[\"__all__\"]:\n        obj = namespace[objname]\n        fix_one(obj)\n\n\n# This is based on the PEP 519 fspath implementation.\n# The function has been adapted to work with pathlib objects on python 3.5\n# The input typehint is removed as there is no os.PathLike on 3.5.\n# See: https://www.python.org/dev/peps/pep-0519/#os\n\n\ndef fspath(path) -> t.Union[str, bytes]:\n    \"\"\"Return the string representation of the path.\n\n    If str or bytes is passed in, it is returned unchanged. If a pre-python 3.6\n    pathlib object is passed, its string representation is returned. If\n    __fspath__() returns something other than str or bytes then TypeError is\n    raised. If this function is given something that is not str, bytes,\n    pathlib.PurePath or os.PathLike then TypeError is raised.\n    \"\"\"\n    if isinstance(path, (str, bytes)):\n        return path\n\n    # Work from the object's type to match method resolution of other magic\n    # methods.\n    path_type = type(path)\n    try:\n        path = path_type.__fspath__(path)\n    except AttributeError:\n        if hasattr(path_type, '__fspath__'):\n            raise\n        # On python 3.5 pathlib objects don't have an __fspath__ method.\n        # but we still want to get their string representation.\n        if isinstance(path, pathlib.PurePath):\n            return str(path)\n    else:\n        if isinstance(path, (str, bytes)):\n            return path\n        else:\n            raise TypeError(\n                \"expected __fspath__() to return str or bytes, \"\n                \"not \" + type(path).__name__\n            )\n\n    raise TypeError(\n        \"expected str, bytes or os.PathLike object, not \" + path_type.__name__\n    )\n\n\nif hasattr(os, \"fspath\"):\n    fspath = os.fspath\n", "path": "trio/_util.py"}], "after_files": [{"content": "# Little utilities we use internally\n\nimport os\nimport sys\nimport pathlib\nfrom functools import wraps\nimport typing as t\n\nimport async_generator\n\n# There's a dependency loop here... _core is allowed to use this file (in fact\n# it's the *only* file in the main trio/ package it's allowed to use), but\n# ConflictDetector needs checkpoint so it also has to import\n# _core. Possibly we should split this file into two: one for true generic\n# low-level utility code, and one for higher level helpers?\nfrom . import _core\n\n__all__ = [\n    \"signal_raise\", \"aiter_compat\", \"acontextmanager\", \"ConflictDetector\",\n    \"fixup_module_metadata\", \"fspath\"\n]\n\n# Equivalent to the C function raise(), which Python doesn't wrap\nif os.name == \"nt\":\n    # On windows, os.kill exists but is really weird.\n    #\n    # If you give it CTRL_C_EVENT or CTRL_BREAK_EVENT, it tries to deliver\n    # those using GenerateConsoleCtrlEvent. But I found that when I tried\n    # to run my test normally, it would freeze waiting... unless I added\n    # print statements, in which case the test suddenly worked. So I guess\n    # these signals are only delivered if/when you access the console? I\n    # don't really know what was going on there. From reading the\n    # GenerateConsoleCtrlEvent docs I don't know how it worked at all.\n    #\n    # I later spent a bunch of time trying to make GenerateConsoleCtrlEvent\n    # work for creating synthetic control-C events, and... failed\n    # utterly. There are lots of details in the code and comments\n    # removed/added at this commit:\n    #     https://github.com/python-trio/trio/commit/95843654173e3e826c34d70a90b369ba6edf2c23\n    #\n    # OTOH, if you pass os.kill any *other* signal number... then CPython\n    # just calls TerminateProcess (wtf).\n    #\n    # So, anyway, os.kill is not so useful for testing purposes. Instead\n    # we use raise():\n    #\n    #   https://msdn.microsoft.com/en-us/library/dwwzkt4c.aspx\n    #\n    # Have to import cffi inside the 'if os.name' block because we don't\n    # depend on cffi on non-Windows platforms. (It would be easy to switch\n    # this to ctypes though if we ever remove the cffi dependency.)\n    #\n    # Some more information:\n    #   https://bugs.python.org/issue26350\n    #\n    # Anyway, we use this for two things:\n    # - redelivering unhandled signals\n    # - generating synthetic signals for tests\n    # and for both of those purposes, 'raise' works fine.\n    import cffi\n\n    _ffi = cffi.FFI()\n    _ffi.cdef(\"int raise(int);\")\n    _lib = _ffi.dlopen(\"api-ms-win-crt-runtime-l1-1-0.dll\")\n    signal_raise = getattr(_lib, \"raise\")\nelse:\n\n    def signal_raise(signum):\n        os.kill(os.getpid(), signum)\n\n\n# Decorator to handle the change to __aiter__ in 3.5.2\ndef aiter_compat(aiter_impl):\n    if sys.version_info < (3, 5, 2):\n\n        @wraps(aiter_impl)\n        async def __aiter__(*args, **kwargs):\n            return aiter_impl(*args, **kwargs)\n\n        return __aiter__\n    else:\n        return aiter_impl\n\n\n# Very much derived from the one in contextlib, by copy/pasting and then\n# asyncifying everything. (Also I dropped the obscure support for using\n# context managers as function decorators. It could be re-added; I just\n# couldn't be bothered.)\n# So this is a derivative work licensed under the PSF License, which requires\n# the following notice:\n#\n# Copyright \u00a9 2001-2017 Python Software Foundation; All Rights Reserved\nclass _AsyncGeneratorContextManager:\n    def __init__(self, func, args, kwds):\n        self._func_name = func.__name__\n        self._agen = func(*args, **kwds).__aiter__()\n\n    async def __aenter__(self):\n        if sys.version_info < (3, 5, 2):\n            self._agen = await self._agen\n        try:\n            return await self._agen.asend(None)\n        except StopAsyncIteration:\n            raise RuntimeError(\"async generator didn't yield\") from None\n\n    async def __aexit__(self, type, value, traceback):\n        if type is None:\n            try:\n                await self._agen.asend(None)\n            except StopAsyncIteration:\n                return False\n            else:\n                raise RuntimeError(\"async generator didn't stop\")\n        else:\n            # It used to be possible to have type != None, value == None:\n            #    https://bugs.python.org/issue1705170\n            # but AFAICT this can't happen anymore.\n            assert value is not None\n            try:\n                await self._agen.athrow(type, value, traceback)\n                raise RuntimeError(\n                    \"async generator didn't stop after athrow()\"\n                )\n            except StopAsyncIteration as exc:\n                # Suppress StopIteration *unless* it's the same exception that\n                # was passed to throw().  This prevents a StopIteration\n                # raised inside the \"with\" statement from being suppressed.\n                return (exc is not value)\n            except RuntimeError as exc:\n                # Don't re-raise the passed in exception. (issue27112)\n                if exc is value:\n                    return False\n                # Likewise, avoid suppressing if a StopIteration exception\n                # was passed to throw() and later wrapped into a RuntimeError\n                # (see PEP 479).\n                if (\n                    isinstance(value,\n                               (StopIteration, StopAsyncIteration))\n                    and exc.__cause__ is value\n                ):\n                    return False\n                raise\n            except:\n                # only re-raise if it's *not* the exception that was\n                # passed to throw(), because __exit__() must not raise\n                # an exception unless __exit__() itself failed.  But throw()\n                # has to raise the exception to signal propagation, so this\n                # fixes the impedance mismatch between the throw() protocol\n                # and the __exit__() protocol.\n                #\n                if sys.exc_info()[1] is value:\n                    return False\n                raise\n\n    def __enter__(self):\n        raise RuntimeError(\n            \"use 'async with {func_name}(...)', not 'with {func_name}(...)'\".\n            format(func_name=self._func_name)\n        )\n\n    def __exit__(self):  # pragma: no cover\n        assert False, \"\"\"Never called, but should be defined\"\"\"\n\n\ndef acontextmanager(func):\n    \"\"\"Like @contextmanager, but async.\"\"\"\n    if not async_generator.isasyncgenfunction(func):\n        raise TypeError(\n            \"must be an async generator (native or from async_generator; \"\n            \"if using @async_generator then @acontextmanager must be on top.\"\n        )\n\n    @wraps(func)\n    def helper(*args, **kwds):\n        return _AsyncGeneratorContextManager(func, args, kwds)\n\n    # A hint for sphinxcontrib-trio:\n    helper.__returns_acontextmanager__ = True\n    return helper\n\n\nclass _ConflictDetectorSync:\n    def __init__(self, msg):\n        self._msg = msg\n        self._held = False\n\n    def __enter__(self):\n        if self._held:\n            raise _core.ResourceBusyError(self._msg)\n        else:\n            self._held = True\n\n    def __exit__(self, *args):\n        self._held = False\n\n\nclass ConflictDetector:\n    \"\"\"Detect when two tasks are about to perform operations that would\n    conflict.\n\n    Use as an async context manager; if two tasks enter it at the same\n    time then the second one raises an error. You can use it when there are\n    two pieces of code that *would* collide and need a lock if they ever were\n    called at the same time, but that should never happen.\n\n    We use this in particular for things like, making sure that two different\n    tasks don't call sendall simultaneously on the same stream.\n\n    This executes a checkpoint on entry. That's the only reason it's async.\n\n    To use from sync code, do ``with cd.sync``; this is just like ``async with\n    cd`` except that it doesn't execute a checkpoint.\n\n    \"\"\"\n\n    def __init__(self, msg):\n        self.sync = _ConflictDetectorSync(msg)\n\n    async def __aenter__(self):\n        await _core.checkpoint()\n        return self.sync.__enter__()\n\n    async def __aexit__(self, *args):\n        return self.sync.__exit__()\n\n\ndef async_wraps(cls, wrapped_cls, attr_name):\n    \"\"\"Similar to wraps, but for async wrappers of non-async functions.\n\n    \"\"\"\n\n    def decorator(func):\n        func.__name__ = attr_name\n        func.__qualname__ = '.'.join((cls.__qualname__, attr_name))\n\n        func.__doc__ = \"\"\"Like :meth:`~{}.{}.{}`, but async.\n\n        \"\"\".format(\n            wrapped_cls.__module__, wrapped_cls.__qualname__, attr_name\n        )\n\n        return func\n\n    return decorator\n\n\ndef fixup_module_metadata(module_name, namespace):\n    def fix_one(obj):\n        mod = getattr(obj, \"__module__\", None)\n        if mod is not None and mod.startswith(\"trio.\"):\n            obj.__module__ = module_name\n            if isinstance(obj, type):\n                for attr_value in obj.__dict__.values():\n                    fix_one(attr_value)\n\n    for objname in namespace[\"__all__\"]:\n        obj = namespace[objname]\n        fix_one(obj)\n\n\n# os.fspath is defined on Python 3.6+ but we need to support Python 3.5 too\n# This is why we provide our own implementation. On Python 3.6+ we use the\n# StdLib's version and on Python 3.5 our own version.\n# Our own implementation implementation is based on PEP 519 while it has also\n# been adapted to work with pathlib objects on python 3.5\n# The input typehint is removed as there is no os.PathLike on 3.5.\n# See: https://www.python.org/dev/peps/pep-0519/#os\n\n\ndef fspath(path) -> t.Union[str, bytes]:\n    \"\"\"Return the path representation of a path-like object.\n\n    Returns\n    -------\n    - If str or bytes is passed in, it is returned unchanged.\n    - If the os.PathLike interface is implemented it is used to get the path\n      representation.\n    - If the python version is 3.5 or earlier and a pathlib object is passed,\n      the object's string representation is returned.\n\n    Raises\n    ------\n    - Regardless of the input, if the path representation (e.g. the value\n      returned from __fspath__) is not str or bytes, TypeError is raised.\n    - If the provided path is not str, bytes, pathlib.PurePath or os.PathLike,\n      TypeError is raised.\n    \"\"\"\n    if isinstance(path, (str, bytes)):\n        return path\n    # Work from the object's type to match method resolution of other magic\n    # methods.\n    path_type = type(path)\n    # On python 3.5, pathlib objects don't have the __fspath__ method,\n    # but we still want to get their string representation.\n    if issubclass(path_type, pathlib.PurePath):\n        return str(path)\n    try:\n        path_repr = path_type.__fspath__(path)\n    except AttributeError:\n        if hasattr(path_type, '__fspath__'):\n            raise\n        else:\n            raise TypeError(\n                \"expected str, bytes or os.PathLike object, \"\n                \"not \" + path_type.__name__\n            )\n    if isinstance(path_repr, (str, bytes)):\n        return path_repr\n    else:\n        raise TypeError(\n            \"expected {}.__fspath__() to return str or bytes, \"\n            \"not {}\".format(path_type.__name__,\n                            type(path_repr).__name__)\n        )\n\n\nif hasattr(os, \"fspath\"):\n    fspath = os.fspath\n", "path": "trio/_util.py"}]}