We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Need to fix bpo-29692
Someone recently found some bugs in some subtle `contextlib.contextmanager` corner cases. The fixes are here: https://github.com/python/cpython/pull/949/files ([discussion](https://bugs.python.org/issue29692))

`trio._util.acontextmanager` is a fork of `contextlib.contextmanager`, and has the same bugs. We should import those fixes.

--- 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 from functools import wraps
6 
7 import async_generator
8 
9 # There's a dependency loop here... _core is allowed to use this file (in fact
10 # it's the *only* file in the main trio/ package it's allowed to use), but
11 # UnLock needs yield_briefly so it also has to import _core. Possibly we
12 # should split this file into two: one for true generic low-level utility
13 # code, and one for higher level helpers?
14 from . import _core
15 
16 __all__ = ["signal_raise", "aiter_compat", "acontextmanager", "UnLock"]
17 
18 # Equivalent to the C function raise(), which Python doesn't wrap
19 if os.name == "nt":
20     # On windows, os.kill exists but is really weird.
21     #
22     # If you give it CTRL_C_EVENT or CTRL_BREAK_EVENT, it tries to deliver
23     # those using GenerateConsoleCtrlEvent. But I found that when I tried
24     # to run my test normally, it would freeze waiting... unless I added
25     # print statements, in which case the test suddenly worked. So I guess
26     # these signals are only delivered if/when you access the console? I
27     # don't really know what was going on there. From reading the
28     # GenerateConsoleCtrlEvent docs I don't know how it worked at all.
29     #
30     # I later spent a bunch of time trying to make GenerateConsoleCtrlEvent
31     # work for creating synthetic control-C events, and... failed
32     # utterly. There are lots of details in the code and comments
33     # removed/added at this commit:
34     #     https://github.com/python-trio/trio/commit/95843654173e3e826c34d70a90b369ba6edf2c23
35     #
36     # OTOH, if you pass os.kill any *other* signal number... then CPython
37     # just calls TerminateProcess (wtf).
38     #
39     # So, anyway, os.kill is not so useful for testing purposes. Instead
40     # we use raise():
41     #
42     #   https://msdn.microsoft.com/en-us/library/dwwzkt4c.aspx
43     #
44     # Have to import cffi inside the 'if os.name' block because we don't
45     # depend on cffi on non-Windows platforms. (It would be easy to switch
46     # this to ctypes though if we ever remove the cffi dependency.)
47     #
48     # Some more information:
49     #   https://bugs.python.org/issue26350
50     #
51     # Anyway, we use this for two things:
52     # - redelivering unhandled signals
53     # - generating synthetic signals for tests
54     # and for both of those purposes, 'raise' works fine.
55     import cffi
56     _ffi = cffi.FFI()
57     _ffi.cdef("int raise(int);")
58     _lib = _ffi.dlopen("api-ms-win-crt-runtime-l1-1-0.dll")
59     signal_raise = getattr(_lib, "raise")
60 else:
61     def signal_raise(signum):
62         os.kill(os.getpid(), signum)
63 
64 
65 # Decorator to handle the change to __aiter__ in 3.5.2
66 def aiter_compat(aiter_impl):
67     if sys.version_info < (3, 5, 2):
68         @wraps(aiter_impl)
69         async def __aiter__(*args, **kwargs):
70             return aiter_impl(*args, **kwargs)
71         return __aiter__
72     else:
73         return aiter_impl
74 
75 
76 # Very much derived from the one in contextlib, by copy/pasting and then
77 # asyncifying everything. (Also I dropped the obscure support for using
78 # context managers as function decorators. It could be re-added; I just
79 # couldn't be bothered.)
80 # So this is a derivative work licensed under the PSF License, which requires
81 # the following notice:
82 #
83 # Copyright © 2001-2017 Python Software Foundation; All Rights Reserved
84 class _AsyncGeneratorContextManager:
85     def __init__(self, func, args, kwds):
86         self._func_name = func.__name__
87         self._agen = func(*args, **kwds).__aiter__()
88 
89     async def __aenter__(self):
90         if sys.version_info < (3, 5, 2):
91             self._agen = await self._agen
92         try:
93             return await self._agen.asend(None)
94         except StopAsyncIteration:
95             raise RuntimeError("async generator didn't yield") from None
96 
97     async def __aexit__(self, type, value, traceback):
98         if type is None:
99             try:
100                 await self._agen.asend(None)
101             except StopAsyncIteration:
102                 return
103             else:
104                 raise RuntimeError("async generator didn't stop")
105         else:
106             if value is None:
107                 # Need to force instantiation so we can reliably
108                 # tell if we get the same exception back
109                 value = type()
110             try:
111                 await self._agen.athrow(type, value, traceback)
112                 raise RuntimeError("async generator didn't stop after athrow()")
113             except StopAsyncIteration as exc:
114                 # Suppress StopIteration *unless* it's the same exception that
115                 # was passed to throw().  This prevents a StopIteration
116                 # raised inside the "with" statement from being suppressed.
117                 return (exc is not value)
118             except RuntimeError as exc:
119                 # Don't re-raise the passed in exception. (issue27112)
120                 if exc is value:
121                     return False
122                 # Likewise, avoid suppressing if a StopIteration exception
123                 # was passed to throw() and later wrapped into a RuntimeError
124                 # (see PEP 479).
125                 if exc.__cause__ is value:
126                     return False
127                 raise
128             except:
129                 # only re-raise if it's *not* the exception that was
130                 # passed to throw(), because __exit__() must not raise
131                 # an exception unless __exit__() itself failed.  But throw()
132                 # has to raise the exception to signal propagation, so this
133                 # fixes the impedance mismatch between the throw() protocol
134                 # and the __exit__() protocol.
135                 #
136                 if sys.exc_info()[1] is not value:
137                     raise
138 
139     def __enter__(self):
140         raise RuntimeError("use 'async with {func_name}(...)', not 'with {func_name}(...)'".format(func_name=self._func_name))
141 
142     def __exit__(self):  # pragma: no cover
143         assert False, """Never called, but should be defined"""
144 
145 
146 def acontextmanager(func):
147     """Like @contextmanager, but async."""
148     if not async_generator.isasyncgenfunction(func):
149         raise TypeError(
150             "must be an async generator (native or from async_generator; "
151             "if using @async_generator then @acontextmanager must be on top.")
152     @wraps(func)
153     def helper(*args, **kwds):
154         return _AsyncGeneratorContextManager(func, args, kwds)
155     # A hint for sphinxcontrib-trio:
156     helper.__returns_acontextmanager__ = True
157     return helper
158 
159 
160 class _UnLockSync:
161     def __init__(self, exc, *args):
162         self._exc = exc
163         self._args = args
164         self._held = False
165 
166     def __enter__(self):
167         if self._held:
168             raise self._exc(*self._args)
169         else:
170             self._held = True
171 
172     def __exit__(self, *args):
173         self._held = False
174 
175 
176 class UnLock:
177     """An unnecessary lock.
178 
179     Use as an async context manager; if two tasks enter it at the same
180     time then the second one raises an error. You can use it when there are
181     two pieces of code that *would* collide and need a lock if they ever were
182     called at the same time, but that should never happen.
183 
184     We use this in particular for things like, making sure that two different
185     tasks don't call sendall simultaneously on the same stream.
186 
187     This executes a checkpoint on entry. That's the only reason it's async.
188 
189     """
190     def __init__(self, exc, *args):
191         self.sync = _UnLockSync(exc, *args)
192 
193     async def __aenter__(self):
194         await _core.yield_briefly()
195         return self.sync.__enter__()
196 
197     async def __aexit__(self, *args):
198         return self.sync.__exit__()
199 
200 
201 def async_wraps(cls, wrapped_cls, attr_name):
202     """Similar to wraps, but for async wrappers of non-async functions.
203 
204     """
205     def decorator(func):
206         func.__name__ = attr_name
207         func.__qualname__ = '.'.join((cls.__qualname__,
208                                       attr_name))
209 
210         func.__doc__ = """Like :meth:`~{}.{}.{}`, but async.
211 
212         """.format(wrapped_cls.__module__,
213                    wrapped_cls.__qualname__,
214                    attr_name)
215 
216         return func
217     return decorator
218
```
--- 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
@@ -99,7 +99,7 @@
             try:
                 await self._agen.asend(None)
             except StopAsyncIteration:
-                return
+                return False
             else:
                 raise RuntimeError("async generator didn't stop")
         else:
@@ -122,7 +122,7 @@
                 # Likewise, avoid suppressing if a StopIteration exception
                 # was passed to throw() and later wrapped into a RuntimeError
                 # (see PEP 479).
-                if exc.__cause__ is value:
+                if isinstance(value, (StopIteration, StopAsyncIteration)) and exc.__cause__ is value:
                     return False
                 raise
             except:
@@ -133,8 +133,9 @@
                 # fixes the impedance mismatch between the throw() protocol
                 # and the __exit__() protocol.
                 #
-                if sys.exc_info()[1] is not value:
-                    raise
+                if sys.exc_info()[1] is value:
+                    return False
+                raise
 
     def __enter__(self):
         raise RuntimeError("use 'async with {func_name}(...)', not 'with {func_name}(...)'".format(func_name=self._func_name))

{"golden_diff": "diff --git a/trio/_util.py b/trio/_util.py\n--- a/trio/_util.py\n+++ b/trio/_util.py\n@@ -99,7 +99,7 @@\n             try:\n                 await self._agen.asend(None)\n             except StopAsyncIteration:\n-                return\n+                return False\n             else:\n                 raise RuntimeError(\"async generator didn't stop\")\n         else:\n@@ -122,7 +122,7 @@\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 exc.__cause__ is value:\n+                if isinstance(value, (StopIteration, StopAsyncIteration)) and exc.__cause__ is value:\n                     return False\n                 raise\n             except:\n@@ -133,8 +133,9 @@\n                 # fixes the impedance mismatch between the throw() protocol\n                 # and the __exit__() protocol.\n                 #\n-                if sys.exc_info()[1] is not value:\n-                    raise\n+                if sys.exc_info()[1] is value:\n+                    return False\n+                raise\n \n     def __enter__(self):\n         raise RuntimeError(\"use 'async with {func_name}(...)', not 'with {func_name}(...)'\".format(func_name=self._func_name))\n", "issue": "Need to fix bpo-29692\nSomeone recently found some bugs in some subtle `contextlib.contextmanager` corner cases. The fixes are here: https://github.com/python/cpython/pull/949/files ([discussion](https://bugs.python.org/issue29692))\r\n\r\n`trio._util.acontextmanager` is a fork of `contextlib.contextmanager`, and has the same bugs. We should import those fixes.\n", "before_files": [{"content": "# Little utilities we use internally\n\nimport os\nimport sys\nfrom functools import wraps\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# UnLock needs yield_briefly so it also has to import _core. Possibly we\n# should split this file into two: one for true generic low-level utility\n# code, and one for higher level helpers?\nfrom . import _core\n\n__all__ = [\"signal_raise\", \"aiter_compat\", \"acontextmanager\", \"UnLock\"]\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    _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    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        @wraps(aiter_impl)\n        async def __aiter__(*args, **kwargs):\n            return aiter_impl(*args, **kwargs)\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\n            else:\n                raise RuntimeError(\"async generator didn't stop\")\n        else:\n            if value is None:\n                # Need to force instantiation so we can reliably\n                # tell if we get the same exception back\n                value = type()\n            try:\n                await self._agen.athrow(type, value, traceback)\n                raise RuntimeError(\"async generator didn't stop after athrow()\")\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 exc.__cause__ is value:\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 not value:\n                    raise\n\n    def __enter__(self):\n        raise RuntimeError(\"use 'async with {func_name}(...)', not 'with {func_name}(...)'\".format(func_name=self._func_name))\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    @wraps(func)\n    def helper(*args, **kwds):\n        return _AsyncGeneratorContextManager(func, args, kwds)\n    # A hint for sphinxcontrib-trio:\n    helper.__returns_acontextmanager__ = True\n    return helper\n\n\nclass _UnLockSync:\n    def __init__(self, exc, *args):\n        self._exc = exc\n        self._args = args\n        self._held = False\n\n    def __enter__(self):\n        if self._held:\n            raise self._exc(*self._args)\n        else:\n            self._held = True\n\n    def __exit__(self, *args):\n        self._held = False\n\n\nclass UnLock:\n    \"\"\"An unnecessary lock.\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    \"\"\"\n    def __init__(self, exc, *args):\n        self.sync = _UnLockSync(exc, *args)\n\n    async def __aenter__(self):\n        await _core.yield_briefly()\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    def decorator(func):\n        func.__name__ = attr_name\n        func.__qualname__ = '.'.join((cls.__qualname__,\n                                      attr_name))\n\n        func.__doc__ = \"\"\"Like :meth:`~{}.{}.{}`, but async.\n\n        \"\"\".format(wrapped_cls.__module__,\n                   wrapped_cls.__qualname__,\n                   attr_name)\n\n        return func\n    return decorator\n", "path": "trio/_util.py"}], "after_files": [{"content": "# Little utilities we use internally\n\nimport os\nimport sys\nfrom functools import wraps\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# UnLock needs yield_briefly so it also has to import _core. Possibly we\n# should split this file into two: one for true generic low-level utility\n# code, and one for higher level helpers?\nfrom . import _core\n\n__all__ = [\"signal_raise\", \"aiter_compat\", \"acontextmanager\", \"UnLock\"]\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    _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    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        @wraps(aiter_impl)\n        async def __aiter__(*args, **kwargs):\n            return aiter_impl(*args, **kwargs)\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            if value is None:\n                # Need to force instantiation so we can reliably\n                # tell if we get the same exception back\n                value = type()\n            try:\n                await self._agen.athrow(type, value, traceback)\n                raise RuntimeError(\"async generator didn't stop after athrow()\")\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 isinstance(value, (StopIteration, StopAsyncIteration)) and exc.__cause__ is value:\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(\"use 'async with {func_name}(...)', not 'with {func_name}(...)'\".format(func_name=self._func_name))\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    @wraps(func)\n    def helper(*args, **kwds):\n        return _AsyncGeneratorContextManager(func, args, kwds)\n    # A hint for sphinxcontrib-trio:\n    helper.__returns_acontextmanager__ = True\n    return helper\n\n\nclass _UnLockSync:\n    def __init__(self, exc, *args):\n        self._exc = exc\n        self._args = args\n        self._held = False\n\n    def __enter__(self):\n        if self._held:\n            raise self._exc(*self._args)\n        else:\n            self._held = True\n\n    def __exit__(self, *args):\n        self._held = False\n\n\nclass UnLock:\n    \"\"\"An unnecessary lock.\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    \"\"\"\n    def __init__(self, exc, *args):\n        self.sync = _UnLockSync(exc, *args)\n\n    async def __aenter__(self):\n        await _core.yield_briefly()\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    def decorator(func):\n        func.__name__ = attr_name\n        func.__qualname__ = '.'.join((cls.__qualname__,\n                                      attr_name))\n\n        func.__doc__ = \"\"\"Like :meth:`~{}.{}.{}`, but async.\n\n        \"\"\".format(wrapped_cls.__module__,\n                   wrapped_cls.__qualname__,\n                   attr_name)\n\n        return func\n    return decorator\n", "path": "trio/_util.py"}]}