summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Lib/contextlib.py
diff options
context:
space:
mode:
authorshadchin <[email protected]>2022-04-18 12:39:32 +0300
committershadchin <[email protected]>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Lib/contextlib.py
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff)
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Lib/contextlib.py')
-rw-r--r--contrib/tools/python3/src/Lib/contextlib.py64
1 files changed, 57 insertions, 7 deletions
diff --git a/contrib/tools/python3/src/Lib/contextlib.py b/contrib/tools/python3/src/Lib/contextlib.py
index 4e8f5f75939..c63a8492e2d 100644
--- a/contrib/tools/python3/src/Lib/contextlib.py
+++ b/contrib/tools/python3/src/Lib/contextlib.py
@@ -9,7 +9,7 @@ from types import MethodType, GenericAlias
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
"AbstractContextManager", "AbstractAsyncContextManager",
"AsyncExitStack", "ContextDecorator", "ExitStack",
- "redirect_stdout", "redirect_stderr", "suppress"]
+ "redirect_stdout", "redirect_stderr", "suppress", "aclosing"]
class AbstractContextManager(abc.ABC):
@@ -80,6 +80,22 @@ class ContextDecorator(object):
return inner
+class AsyncContextDecorator(object):
+ "A base class or mixin that enables async context managers to work as decorators."
+
+ def _recreate_cm(self):
+ """Return a recreated instance of self.
+ """
+ return self
+
+ def __call__(self, func):
+ @wraps(func)
+ async def inner(*args, **kwds):
+ async with self._recreate_cm():
+ return await func(*args, **kwds)
+ return inner
+
+
class _GeneratorContextManagerBase:
"""Shared functionality for @contextmanager and @asynccontextmanager."""
@@ -168,9 +184,11 @@ class _GeneratorContextManager(
return False
raise RuntimeError("generator didn't stop after throw()")
-
-class _AsyncGeneratorContextManager(_GeneratorContextManagerBase,
- AbstractAsyncContextManager):
+class _AsyncGeneratorContextManager(
+ _GeneratorContextManagerBase,
+ AbstractAsyncContextManager,
+ AsyncContextDecorator,
+):
"""Helper for @asynccontextmanager decorator."""
async def __aenter__(self):
@@ -178,14 +196,14 @@ class _AsyncGeneratorContextManager(_GeneratorContextManagerBase,
# they are only needed for recreation, which is not possible anymore
del self.args, self.kwds, self.func
try:
- return await self.gen.__anext__()
+ return await anext(self.gen)
except StopAsyncIteration:
raise RuntimeError("generator didn't yield") from None
async def __aexit__(self, typ, value, traceback):
if typ is None:
try:
- await self.gen.__anext__()
+ await anext(self.gen)
except StopAsyncIteration:
return False
else:
@@ -322,6 +340,32 @@ class closing(AbstractContextManager):
self.thing.close()
+class aclosing(AbstractAsyncContextManager):
+ """Async context manager for safely finalizing an asynchronously cleaned-up
+ resource such as an async generator, calling its ``aclose()`` method.
+
+ Code like this:
+
+ async with aclosing(<module>.fetch(<arguments>)) as agen:
+ <block>
+
+ is equivalent to this:
+
+ agen = <module>.fetch(<arguments>)
+ try:
+ <block>
+ finally:
+ await agen.aclose()
+
+ """
+ def __init__(self, thing):
+ self.thing = thing
+ async def __aenter__(self):
+ return self.thing
+ async def __aexit__(self, *exc_info):
+ await self.thing.aclose()
+
+
class _RedirectStream(AbstractContextManager):
_stream = None
@@ -674,7 +718,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
return received_exc and suppressed_exc
-class nullcontext(AbstractContextManager):
+class nullcontext(AbstractContextManager, AbstractAsyncContextManager):
"""Context manager that does no additional processing.
Used as a stand-in for a normal context manager, when a particular
@@ -693,3 +737,9 @@ class nullcontext(AbstractContextManager):
def __exit__(self, *excinfo):
pass
+
+ async def __aenter__(self):
+ return self.enter_result
+
+ async def __aexit__(self, *excinfo):
+ pass