diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/python/prompt-toolkit/py3/prompt_toolkit/eventloop/async_context_manager.py | |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/eventloop/async_context_manager.py')
| -rw-r--r-- | contrib/python/prompt-toolkit/py3/prompt_toolkit/eventloop/async_context_manager.py | 132 | 
1 files changed, 132 insertions, 0 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/eventloop/async_context_manager.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/eventloop/async_context_manager.py new file mode 100644 index 00000000000..173751ab06a --- /dev/null +++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/eventloop/async_context_manager.py @@ -0,0 +1,132 @@ +""" +@asynccontextmanager code, copied from Python 3.7's contextlib. +For usage in Python 3.6. +Types have been added to this file, just enough to make Mypy happy. +""" +# mypy: allow-untyped-defs +import abc +from functools import wraps +from typing import TYPE_CHECKING, AsyncContextManager, AsyncIterator, Callable, TypeVar + +import _collections_abc + +__all__ = ["asynccontextmanager"] + + +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__")  # type: ignore +        return NotImplemented + + +class _GeneratorContextManagerBase: +    """Shared functionality for @contextmanager and @asynccontextmanager.""" + +    def __init__(self, func, args, kwds): +        self.gen = func(*args, **kwds) +        self.func, self.args, self.kwds = func, args, kwds +        # Issue 19330: ensure context manager instances have good docstrings +        doc = getattr(func, "__doc__", None) +        if doc is None: +            doc = type(self).__doc__ +        self.__doc__ = doc +        # Unfortunately, this still doesn't provide good help output when +        # inspecting the created context manager instances, since pydoc +        # currently bypasses the instance docstring and shows the docstring +        # for the class instead. +        # See http://bugs.python.org/issue19404 for more details. + + +class _AsyncGeneratorContextManager( +    _GeneratorContextManagerBase, AbstractAsyncContextManager +): +    """Helper for @asynccontextmanager.""" + +    async def __aenter__(self): +        try: +            return await self.gen.__anext__() +        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__() +            except StopAsyncIteration: +                return +            else: +                raise RuntimeError("generator didn't stop") +        else: +            if value is None: +                value = typ() +            # See _GeneratorContextManager.__exit__ for comments on subtleties +            # in this implementation +            try: +                await self.gen.athrow(typ, value, traceback) +                raise RuntimeError("generator didn't stop after athrow()") +            except StopAsyncIteration as exc: +                return exc is not value +            except RuntimeError as exc: +                if exc is value: +                    return False +                # Avoid suppressing if a StopIteration exception +                # was passed to throw() and later wrapped into a RuntimeError +                # (see PEP 479 for sync generators; async generators also +                # have this behavior). But do this only if the exception wrapped +                # by the RuntimeError is actully Stop(Async)Iteration (see +                # issue29692). +                if isinstance(value, (StopIteration, StopAsyncIteration)): +                    if exc.__cause__ is value: +                        return False +                raise +            except BaseException as exc: +                if exc is not value: +                    raise + + +_T = TypeVar("_T") + + +def asynccontextmanager( +    func: Callable[..., AsyncIterator[_T]] +) -> Callable[..., AsyncContextManager[_T]]: +    """@asynccontextmanager decorator. +    Typical usage: +        @asynccontextmanager +        async def some_async_generator(<arguments>): +            <setup> +            try: +                yield <value> +            finally: +                <cleanup> +    This makes this: +        async with some_async_generator(<arguments>) as <variable>: +            <body> +    equivalent to this: +        <setup> +        try: +            <variable> = <value> +            <body> +        finally: +            <cleanup> +    """ + +    @wraps(func) +    def helper(*args, **kwds): +        return _AsyncGeneratorContextManager(func, args, kwds)  # type: ignore + +    return helper  | 
