bpo-30241: implement contextlib.AbstractAsyncContextManager (#1412)
This commit is contained in:
parent
bfbf04ef18
commit
176baa326b
|
@ -29,6 +29,17 @@ Functions and classes provided:
|
||||||
.. versionadded:: 3.6
|
.. versionadded:: 3.6
|
||||||
|
|
||||||
|
|
||||||
|
.. class:: AbstractAsyncContextManager
|
||||||
|
|
||||||
|
An :term:`abstract base class` for classes that implement
|
||||||
|
:meth:`object.__aenter__` and :meth:`object.__aexit__`. A default
|
||||||
|
implementation for :meth:`object.__aenter__` is provided which returns
|
||||||
|
``self`` while :meth:`object.__aexit__` is an abstract method which by default
|
||||||
|
returns ``None``. See also the definition of
|
||||||
|
:ref:`async-context-managers`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.7
|
||||||
|
|
||||||
|
|
||||||
.. decorator:: contextmanager
|
.. decorator:: contextmanager
|
||||||
|
|
||||||
|
|
|
@ -306,8 +306,9 @@ is a list of strings, not bytes.
|
||||||
contextlib
|
contextlib
|
||||||
----------
|
----------
|
||||||
|
|
||||||
:func:`contextlib.asynccontextmanager` has been added. (Contributed by
|
:func:`~contextlib.asynccontextmanager` and
|
||||||
Jelle Zijlstra in :issue:`29679`.)
|
:class:`~contextlib.AbstractAsyncContextManager` have been added. (Contributed
|
||||||
|
by Jelle Zijlstra in :issue:`29679` and :issue:`30241`.)
|
||||||
|
|
||||||
cProfile
|
cProfile
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -6,7 +6,8 @@ from collections import deque
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
|
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
|
||||||
"AbstractContextManager", "ContextDecorator", "ExitStack",
|
"AbstractContextManager", "AbstractAsyncContextManager",
|
||||||
|
"ContextDecorator", "ExitStack",
|
||||||
"redirect_stdout", "redirect_stderr", "suppress"]
|
"redirect_stdout", "redirect_stderr", "suppress"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,6 +31,27 @@ class AbstractContextManager(abc.ABC):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractAsyncContextManager(abc.ABC):
|
||||||
|
|
||||||
|
"""An abstract base class for asynchronous context managers."""
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
"""Return `self` upon entering the runtime context."""
|
||||||
|
return self
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
async def __aexit__(self, exc_type, exc_value, traceback):
|
||||||
|
"""Raise any exception triggered within the runtime context."""
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __subclasshook__(cls, C):
|
||||||
|
if cls is AbstractAsyncContextManager:
|
||||||
|
return _collections_abc._check_methods(C, "__aenter__",
|
||||||
|
"__aexit__")
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
|
||||||
class ContextDecorator(object):
|
class ContextDecorator(object):
|
||||||
"A base class or mixin that enables context managers to work as decorators."
|
"A base class or mixin that enables context managers to work as decorators."
|
||||||
|
|
||||||
|
@ -136,7 +158,8 @@ class _GeneratorContextManager(_GeneratorContextManagerBase,
|
||||||
raise RuntimeError("generator didn't stop after throw()")
|
raise RuntimeError("generator didn't stop after throw()")
|
||||||
|
|
||||||
|
|
||||||
class _AsyncGeneratorContextManager(_GeneratorContextManagerBase):
|
class _AsyncGeneratorContextManager(_GeneratorContextManagerBase,
|
||||||
|
AbstractAsyncContextManager):
|
||||||
"""Helper for @asynccontextmanager."""
|
"""Helper for @asynccontextmanager."""
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager, AbstractAsyncContextManager
|
||||||
import functools
|
import functools
|
||||||
from test import support
|
from test import support
|
||||||
import unittest
|
import unittest
|
||||||
|
@ -20,6 +20,53 @@ def _async_test(func):
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class TestAbstractAsyncContextManager(unittest.TestCase):
|
||||||
|
|
||||||
|
@_async_test
|
||||||
|
async def test_enter(self):
|
||||||
|
class DefaultEnter(AbstractAsyncContextManager):
|
||||||
|
async def __aexit__(self, *args):
|
||||||
|
await super().__aexit__(*args)
|
||||||
|
|
||||||
|
manager = DefaultEnter()
|
||||||
|
self.assertIs(await manager.__aenter__(), manager)
|
||||||
|
|
||||||
|
async with manager as context:
|
||||||
|
self.assertIs(manager, context)
|
||||||
|
|
||||||
|
def test_exit_is_abstract(self):
|
||||||
|
class MissingAexit(AbstractAsyncContextManager):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
MissingAexit()
|
||||||
|
|
||||||
|
def test_structural_subclassing(self):
|
||||||
|
class ManagerFromScratch:
|
||||||
|
async def __aenter__(self):
|
||||||
|
return self
|
||||||
|
async def __aexit__(self, exc_type, exc_value, traceback):
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.assertTrue(issubclass(ManagerFromScratch, AbstractAsyncContextManager))
|
||||||
|
|
||||||
|
class DefaultEnter(AbstractAsyncContextManager):
|
||||||
|
async def __aexit__(self, *args):
|
||||||
|
await super().__aexit__(*args)
|
||||||
|
|
||||||
|
self.assertTrue(issubclass(DefaultEnter, AbstractAsyncContextManager))
|
||||||
|
|
||||||
|
class NoneAenter(ManagerFromScratch):
|
||||||
|
__aenter__ = None
|
||||||
|
|
||||||
|
self.assertFalse(issubclass(NoneAenter, AbstractAsyncContextManager))
|
||||||
|
|
||||||
|
class NoneAexit(ManagerFromScratch):
|
||||||
|
__aexit__ = None
|
||||||
|
|
||||||
|
self.assertFalse(issubclass(NoneAexit, AbstractAsyncContextManager))
|
||||||
|
|
||||||
|
|
||||||
class AsyncContextManagerTestCase(unittest.TestCase):
|
class AsyncContextManagerTestCase(unittest.TestCase):
|
||||||
|
|
||||||
@_async_test
|
@_async_test
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add contextlib.AbstractAsyncContextManager. Patch by Jelle Zijlstra.
|
Loading…
Reference in New Issue