From 178695b7aee7a7aacd49a3086060e06347d1e556 Mon Sep 17 00:00:00 2001 From: Kazantcev Andrey <45011689+heckad@users.noreply.github.com> Date: Thu, 5 Nov 2020 11:52:24 +0300 Subject: bpo-40816 Add AsyncContextDecorator class (GH-20516) Co-authored-by: Yury Selivanov --- Lib/contextlib.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'Lib/contextlib.py') diff --git a/Lib/contextlib.py b/Lib/contextlib.py index 82ddc1497d..56b4968118 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -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.""" @@ -167,9 +183,16 @@ class _GeneratorContextManager(_GeneratorContextManagerBase, class _AsyncGeneratorContextManager(_GeneratorContextManagerBase, - AbstractAsyncContextManager): + AbstractAsyncContextManager, + AsyncContextDecorator): """Helper for @asynccontextmanager.""" + def _recreate_cm(self): + # _AGCM instances are one-shot context managers, so the + # ACM must be recreated each time a decorated function is + # called + return self.__class__(self.func, self.args, self.kwds) + async def __aenter__(self): try: return await self.gen.__anext__() -- cgit v1.2.1 From a117167d8dc8fa673a4646f509551c7950f824e5 Mon Sep 17 00:00:00 2001 From: Tom Gringauz Date: Mon, 9 Nov 2020 14:34:07 +0200 Subject: bpo-41543: contextlib.nullcontext can fill in for an async context manager (GH-21870) Co-authored-by: Andrew Svetlov --- Lib/contextlib.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Lib/contextlib.py') diff --git a/Lib/contextlib.py b/Lib/contextlib.py index 56b4968118..a0b523c96f 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -704,7 +704,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 @@ -723,3 +723,9 @@ class nullcontext(AbstractContextManager): def __exit__(self, *excinfo): pass + + async def __aenter__(self): + return self.enter_result + + async def __aexit__(self, *excinfo): + pass -- cgit v1.2.1 From d0d4a450679bfc90eae7be4fdb5499e87f661b3e Mon Sep 17 00:00:00 2001 From: Tom Gringauz Date: Wed, 18 Nov 2020 01:18:05 +0200 Subject: bpo-42395: Add aclosing to __all__ (GH-23356) Automerge-Triggered-By: GH:asvetlov --- Lib/contextlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/contextlib.py') diff --git a/Lib/contextlib.py b/Lib/contextlib.py index a0b523c96f..eb5946145b 100644 --- a/Lib/contextlib.py +++ b/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): -- cgit v1.2.1