xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/contextlib.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Utilities for with-statement contexts.  See PEP 343."""
2*cda5da8dSAndroid Build Coastguard Workerimport abc
3*cda5da8dSAndroid Build Coastguard Workerimport os
4*cda5da8dSAndroid Build Coastguard Workerimport sys
5*cda5da8dSAndroid Build Coastguard Workerimport _collections_abc
6*cda5da8dSAndroid Build Coastguard Workerfrom collections import deque
7*cda5da8dSAndroid Build Coastguard Workerfrom functools import wraps
8*cda5da8dSAndroid Build Coastguard Workerfrom types import MethodType, GenericAlias
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Worker__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
11*cda5da8dSAndroid Build Coastguard Worker           "AbstractContextManager", "AbstractAsyncContextManager",
12*cda5da8dSAndroid Build Coastguard Worker           "AsyncExitStack", "ContextDecorator", "ExitStack",
13*cda5da8dSAndroid Build Coastguard Worker           "redirect_stdout", "redirect_stderr", "suppress", "aclosing",
14*cda5da8dSAndroid Build Coastguard Worker           "chdir"]
15*cda5da8dSAndroid Build Coastguard Worker
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Workerclass AbstractContextManager(abc.ABC):
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Worker    """An abstract base class for context managers."""
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard Worker    __class_getitem__ = classmethod(GenericAlias)
22*cda5da8dSAndroid Build Coastguard Worker
23*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
24*cda5da8dSAndroid Build Coastguard Worker        """Return `self` upon entering the runtime context."""
25*cda5da8dSAndroid Build Coastguard Worker        return self
26*cda5da8dSAndroid Build Coastguard Worker
27*cda5da8dSAndroid Build Coastguard Worker    @abc.abstractmethod
28*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, exc_type, exc_value, traceback):
29*cda5da8dSAndroid Build Coastguard Worker        """Raise any exception triggered within the runtime context."""
30*cda5da8dSAndroid Build Coastguard Worker        return None
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker    @classmethod
33*cda5da8dSAndroid Build Coastguard Worker    def __subclasshook__(cls, C):
34*cda5da8dSAndroid Build Coastguard Worker        if cls is AbstractContextManager:
35*cda5da8dSAndroid Build Coastguard Worker            return _collections_abc._check_methods(C, "__enter__", "__exit__")
36*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
37*cda5da8dSAndroid Build Coastguard Worker
38*cda5da8dSAndroid Build Coastguard Worker
39*cda5da8dSAndroid Build Coastguard Workerclass AbstractAsyncContextManager(abc.ABC):
40*cda5da8dSAndroid Build Coastguard Worker
41*cda5da8dSAndroid Build Coastguard Worker    """An abstract base class for asynchronous context managers."""
42*cda5da8dSAndroid Build Coastguard Worker
43*cda5da8dSAndroid Build Coastguard Worker    __class_getitem__ = classmethod(GenericAlias)
44*cda5da8dSAndroid Build Coastguard Worker
45*cda5da8dSAndroid Build Coastguard Worker    async def __aenter__(self):
46*cda5da8dSAndroid Build Coastguard Worker        """Return `self` upon entering the runtime context."""
47*cda5da8dSAndroid Build Coastguard Worker        return self
48*cda5da8dSAndroid Build Coastguard Worker
49*cda5da8dSAndroid Build Coastguard Worker    @abc.abstractmethod
50*cda5da8dSAndroid Build Coastguard Worker    async def __aexit__(self, exc_type, exc_value, traceback):
51*cda5da8dSAndroid Build Coastguard Worker        """Raise any exception triggered within the runtime context."""
52*cda5da8dSAndroid Build Coastguard Worker        return None
53*cda5da8dSAndroid Build Coastguard Worker
54*cda5da8dSAndroid Build Coastguard Worker    @classmethod
55*cda5da8dSAndroid Build Coastguard Worker    def __subclasshook__(cls, C):
56*cda5da8dSAndroid Build Coastguard Worker        if cls is AbstractAsyncContextManager:
57*cda5da8dSAndroid Build Coastguard Worker            return _collections_abc._check_methods(C, "__aenter__",
58*cda5da8dSAndroid Build Coastguard Worker                                                   "__aexit__")
59*cda5da8dSAndroid Build Coastguard Worker        return NotImplemented
60*cda5da8dSAndroid Build Coastguard Worker
61*cda5da8dSAndroid Build Coastguard Worker
62*cda5da8dSAndroid Build Coastguard Workerclass ContextDecorator(object):
63*cda5da8dSAndroid Build Coastguard Worker    "A base class or mixin that enables context managers to work as decorators."
64*cda5da8dSAndroid Build Coastguard Worker
65*cda5da8dSAndroid Build Coastguard Worker    def _recreate_cm(self):
66*cda5da8dSAndroid Build Coastguard Worker        """Return a recreated instance of self.
67*cda5da8dSAndroid Build Coastguard Worker
68*cda5da8dSAndroid Build Coastguard Worker        Allows an otherwise one-shot context manager like
69*cda5da8dSAndroid Build Coastguard Worker        _GeneratorContextManager to support use as
70*cda5da8dSAndroid Build Coastguard Worker        a decorator via implicit recreation.
71*cda5da8dSAndroid Build Coastguard Worker
72*cda5da8dSAndroid Build Coastguard Worker        This is a private interface just for _GeneratorContextManager.
73*cda5da8dSAndroid Build Coastguard Worker        See issue #11647 for details.
74*cda5da8dSAndroid Build Coastguard Worker        """
75*cda5da8dSAndroid Build Coastguard Worker        return self
76*cda5da8dSAndroid Build Coastguard Worker
77*cda5da8dSAndroid Build Coastguard Worker    def __call__(self, func):
78*cda5da8dSAndroid Build Coastguard Worker        @wraps(func)
79*cda5da8dSAndroid Build Coastguard Worker        def inner(*args, **kwds):
80*cda5da8dSAndroid Build Coastguard Worker            with self._recreate_cm():
81*cda5da8dSAndroid Build Coastguard Worker                return func(*args, **kwds)
82*cda5da8dSAndroid Build Coastguard Worker        return inner
83*cda5da8dSAndroid Build Coastguard Worker
84*cda5da8dSAndroid Build Coastguard Worker
85*cda5da8dSAndroid Build Coastguard Workerclass AsyncContextDecorator(object):
86*cda5da8dSAndroid Build Coastguard Worker    "A base class or mixin that enables async context managers to work as decorators."
87*cda5da8dSAndroid Build Coastguard Worker
88*cda5da8dSAndroid Build Coastguard Worker    def _recreate_cm(self):
89*cda5da8dSAndroid Build Coastguard Worker        """Return a recreated instance of self.
90*cda5da8dSAndroid Build Coastguard Worker        """
91*cda5da8dSAndroid Build Coastguard Worker        return self
92*cda5da8dSAndroid Build Coastguard Worker
93*cda5da8dSAndroid Build Coastguard Worker    def __call__(self, func):
94*cda5da8dSAndroid Build Coastguard Worker        @wraps(func)
95*cda5da8dSAndroid Build Coastguard Worker        async def inner(*args, **kwds):
96*cda5da8dSAndroid Build Coastguard Worker            async with self._recreate_cm():
97*cda5da8dSAndroid Build Coastguard Worker                return await func(*args, **kwds)
98*cda5da8dSAndroid Build Coastguard Worker        return inner
99*cda5da8dSAndroid Build Coastguard Worker
100*cda5da8dSAndroid Build Coastguard Worker
101*cda5da8dSAndroid Build Coastguard Workerclass _GeneratorContextManagerBase:
102*cda5da8dSAndroid Build Coastguard Worker    """Shared functionality for @contextmanager and @asynccontextmanager."""
103*cda5da8dSAndroid Build Coastguard Worker
104*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, func, args, kwds):
105*cda5da8dSAndroid Build Coastguard Worker        self.gen = func(*args, **kwds)
106*cda5da8dSAndroid Build Coastguard Worker        self.func, self.args, self.kwds = func, args, kwds
107*cda5da8dSAndroid Build Coastguard Worker        # Issue 19330: ensure context manager instances have good docstrings
108*cda5da8dSAndroid Build Coastguard Worker        doc = getattr(func, "__doc__", None)
109*cda5da8dSAndroid Build Coastguard Worker        if doc is None:
110*cda5da8dSAndroid Build Coastguard Worker            doc = type(self).__doc__
111*cda5da8dSAndroid Build Coastguard Worker        self.__doc__ = doc
112*cda5da8dSAndroid Build Coastguard Worker        # Unfortunately, this still doesn't provide good help output when
113*cda5da8dSAndroid Build Coastguard Worker        # inspecting the created context manager instances, since pydoc
114*cda5da8dSAndroid Build Coastguard Worker        # currently bypasses the instance docstring and shows the docstring
115*cda5da8dSAndroid Build Coastguard Worker        # for the class instead.
116*cda5da8dSAndroid Build Coastguard Worker        # See http://bugs.python.org/issue19404 for more details.
117*cda5da8dSAndroid Build Coastguard Worker
118*cda5da8dSAndroid Build Coastguard Worker    def _recreate_cm(self):
119*cda5da8dSAndroid Build Coastguard Worker        # _GCMB instances are one-shot context managers, so the
120*cda5da8dSAndroid Build Coastguard Worker        # CM must be recreated each time a decorated function is
121*cda5da8dSAndroid Build Coastguard Worker        # called
122*cda5da8dSAndroid Build Coastguard Worker        return self.__class__(self.func, self.args, self.kwds)
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Worker
125*cda5da8dSAndroid Build Coastguard Workerclass _GeneratorContextManager(
126*cda5da8dSAndroid Build Coastguard Worker    _GeneratorContextManagerBase,
127*cda5da8dSAndroid Build Coastguard Worker    AbstractContextManager,
128*cda5da8dSAndroid Build Coastguard Worker    ContextDecorator,
129*cda5da8dSAndroid Build Coastguard Worker):
130*cda5da8dSAndroid Build Coastguard Worker    """Helper for @contextmanager decorator."""
131*cda5da8dSAndroid Build Coastguard Worker
132*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
133*cda5da8dSAndroid Build Coastguard Worker        # do not keep args and kwds alive unnecessarily
134*cda5da8dSAndroid Build Coastguard Worker        # they are only needed for recreation, which is not possible anymore
135*cda5da8dSAndroid Build Coastguard Worker        del self.args, self.kwds, self.func
136*cda5da8dSAndroid Build Coastguard Worker        try:
137*cda5da8dSAndroid Build Coastguard Worker            return next(self.gen)
138*cda5da8dSAndroid Build Coastguard Worker        except StopIteration:
139*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError("generator didn't yield") from None
140*cda5da8dSAndroid Build Coastguard Worker
141*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, typ, value, traceback):
142*cda5da8dSAndroid Build Coastguard Worker        if typ is None:
143*cda5da8dSAndroid Build Coastguard Worker            try:
144*cda5da8dSAndroid Build Coastguard Worker                next(self.gen)
145*cda5da8dSAndroid Build Coastguard Worker            except StopIteration:
146*cda5da8dSAndroid Build Coastguard Worker                return False
147*cda5da8dSAndroid Build Coastguard Worker            else:
148*cda5da8dSAndroid Build Coastguard Worker                raise RuntimeError("generator didn't stop")
149*cda5da8dSAndroid Build Coastguard Worker        else:
150*cda5da8dSAndroid Build Coastguard Worker            if value is None:
151*cda5da8dSAndroid Build Coastguard Worker                # Need to force instantiation so we can reliably
152*cda5da8dSAndroid Build Coastguard Worker                # tell if we get the same exception back
153*cda5da8dSAndroid Build Coastguard Worker                value = typ()
154*cda5da8dSAndroid Build Coastguard Worker            try:
155*cda5da8dSAndroid Build Coastguard Worker                self.gen.throw(typ, value, traceback)
156*cda5da8dSAndroid Build Coastguard Worker            except StopIteration as exc:
157*cda5da8dSAndroid Build Coastguard Worker                # Suppress StopIteration *unless* it's the same exception that
158*cda5da8dSAndroid Build Coastguard Worker                # was passed to throw().  This prevents a StopIteration
159*cda5da8dSAndroid Build Coastguard Worker                # raised inside the "with" statement from being suppressed.
160*cda5da8dSAndroid Build Coastguard Worker                return exc is not value
161*cda5da8dSAndroid Build Coastguard Worker            except RuntimeError as exc:
162*cda5da8dSAndroid Build Coastguard Worker                # Don't re-raise the passed in exception. (issue27122)
163*cda5da8dSAndroid Build Coastguard Worker                if exc is value:
164*cda5da8dSAndroid Build Coastguard Worker                    exc.__traceback__ = traceback
165*cda5da8dSAndroid Build Coastguard Worker                    return False
166*cda5da8dSAndroid Build Coastguard Worker                # Avoid suppressing if a StopIteration exception
167*cda5da8dSAndroid Build Coastguard Worker                # was passed to throw() and later wrapped into a RuntimeError
168*cda5da8dSAndroid Build Coastguard Worker                # (see PEP 479 for sync generators; async generators also
169*cda5da8dSAndroid Build Coastguard Worker                # have this behavior). But do this only if the exception wrapped
170*cda5da8dSAndroid Build Coastguard Worker                # by the RuntimeError is actually Stop(Async)Iteration (see
171*cda5da8dSAndroid Build Coastguard Worker                # issue29692).
172*cda5da8dSAndroid Build Coastguard Worker                if (
173*cda5da8dSAndroid Build Coastguard Worker                    isinstance(value, StopIteration)
174*cda5da8dSAndroid Build Coastguard Worker                    and exc.__cause__ is value
175*cda5da8dSAndroid Build Coastguard Worker                ):
176*cda5da8dSAndroid Build Coastguard Worker                    value.__traceback__ = traceback
177*cda5da8dSAndroid Build Coastguard Worker                    return False
178*cda5da8dSAndroid Build Coastguard Worker                raise
179*cda5da8dSAndroid Build Coastguard Worker            except BaseException as exc:
180*cda5da8dSAndroid Build Coastguard Worker                # only re-raise if it's *not* the exception that was
181*cda5da8dSAndroid Build Coastguard Worker                # passed to throw(), because __exit__() must not raise
182*cda5da8dSAndroid Build Coastguard Worker                # an exception unless __exit__() itself failed.  But throw()
183*cda5da8dSAndroid Build Coastguard Worker                # has to raise the exception to signal propagation, so this
184*cda5da8dSAndroid Build Coastguard Worker                # fixes the impedance mismatch between the throw() protocol
185*cda5da8dSAndroid Build Coastguard Worker                # and the __exit__() protocol.
186*cda5da8dSAndroid Build Coastguard Worker                if exc is not value:
187*cda5da8dSAndroid Build Coastguard Worker                    raise
188*cda5da8dSAndroid Build Coastguard Worker                exc.__traceback__ = traceback
189*cda5da8dSAndroid Build Coastguard Worker                return False
190*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError("generator didn't stop after throw()")
191*cda5da8dSAndroid Build Coastguard Worker
192*cda5da8dSAndroid Build Coastguard Workerclass _AsyncGeneratorContextManager(
193*cda5da8dSAndroid Build Coastguard Worker    _GeneratorContextManagerBase,
194*cda5da8dSAndroid Build Coastguard Worker    AbstractAsyncContextManager,
195*cda5da8dSAndroid Build Coastguard Worker    AsyncContextDecorator,
196*cda5da8dSAndroid Build Coastguard Worker):
197*cda5da8dSAndroid Build Coastguard Worker    """Helper for @asynccontextmanager decorator."""
198*cda5da8dSAndroid Build Coastguard Worker
199*cda5da8dSAndroid Build Coastguard Worker    async def __aenter__(self):
200*cda5da8dSAndroid Build Coastguard Worker        # do not keep args and kwds alive unnecessarily
201*cda5da8dSAndroid Build Coastguard Worker        # they are only needed for recreation, which is not possible anymore
202*cda5da8dSAndroid Build Coastguard Worker        del self.args, self.kwds, self.func
203*cda5da8dSAndroid Build Coastguard Worker        try:
204*cda5da8dSAndroid Build Coastguard Worker            return await anext(self.gen)
205*cda5da8dSAndroid Build Coastguard Worker        except StopAsyncIteration:
206*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError("generator didn't yield") from None
207*cda5da8dSAndroid Build Coastguard Worker
208*cda5da8dSAndroid Build Coastguard Worker    async def __aexit__(self, typ, value, traceback):
209*cda5da8dSAndroid Build Coastguard Worker        if typ is None:
210*cda5da8dSAndroid Build Coastguard Worker            try:
211*cda5da8dSAndroid Build Coastguard Worker                await anext(self.gen)
212*cda5da8dSAndroid Build Coastguard Worker            except StopAsyncIteration:
213*cda5da8dSAndroid Build Coastguard Worker                return False
214*cda5da8dSAndroid Build Coastguard Worker            else:
215*cda5da8dSAndroid Build Coastguard Worker                raise RuntimeError("generator didn't stop")
216*cda5da8dSAndroid Build Coastguard Worker        else:
217*cda5da8dSAndroid Build Coastguard Worker            if value is None:
218*cda5da8dSAndroid Build Coastguard Worker                # Need to force instantiation so we can reliably
219*cda5da8dSAndroid Build Coastguard Worker                # tell if we get the same exception back
220*cda5da8dSAndroid Build Coastguard Worker                value = typ()
221*cda5da8dSAndroid Build Coastguard Worker            try:
222*cda5da8dSAndroid Build Coastguard Worker                await self.gen.athrow(typ, value, traceback)
223*cda5da8dSAndroid Build Coastguard Worker            except StopAsyncIteration as exc:
224*cda5da8dSAndroid Build Coastguard Worker                # Suppress StopIteration *unless* it's the same exception that
225*cda5da8dSAndroid Build Coastguard Worker                # was passed to throw().  This prevents a StopIteration
226*cda5da8dSAndroid Build Coastguard Worker                # raised inside the "with" statement from being suppressed.
227*cda5da8dSAndroid Build Coastguard Worker                return exc is not value
228*cda5da8dSAndroid Build Coastguard Worker            except RuntimeError as exc:
229*cda5da8dSAndroid Build Coastguard Worker                # Don't re-raise the passed in exception. (issue27122)
230*cda5da8dSAndroid Build Coastguard Worker                if exc is value:
231*cda5da8dSAndroid Build Coastguard Worker                    exc.__traceback__ = traceback
232*cda5da8dSAndroid Build Coastguard Worker                    return False
233*cda5da8dSAndroid Build Coastguard Worker                # Avoid suppressing if a Stop(Async)Iteration exception
234*cda5da8dSAndroid Build Coastguard Worker                # was passed to athrow() and later wrapped into a RuntimeError
235*cda5da8dSAndroid Build Coastguard Worker                # (see PEP 479 for sync generators; async generators also
236*cda5da8dSAndroid Build Coastguard Worker                # have this behavior). But do this only if the exception wrapped
237*cda5da8dSAndroid Build Coastguard Worker                # by the RuntimeError is actually Stop(Async)Iteration (see
238*cda5da8dSAndroid Build Coastguard Worker                # issue29692).
239*cda5da8dSAndroid Build Coastguard Worker                if (
240*cda5da8dSAndroid Build Coastguard Worker                    isinstance(value, (StopIteration, StopAsyncIteration))
241*cda5da8dSAndroid Build Coastguard Worker                    and exc.__cause__ is value
242*cda5da8dSAndroid Build Coastguard Worker                ):
243*cda5da8dSAndroid Build Coastguard Worker                    value.__traceback__ = traceback
244*cda5da8dSAndroid Build Coastguard Worker                    return False
245*cda5da8dSAndroid Build Coastguard Worker                raise
246*cda5da8dSAndroid Build Coastguard Worker            except BaseException as exc:
247*cda5da8dSAndroid Build Coastguard Worker                # only re-raise if it's *not* the exception that was
248*cda5da8dSAndroid Build Coastguard Worker                # passed to throw(), because __exit__() must not raise
249*cda5da8dSAndroid Build Coastguard Worker                # an exception unless __exit__() itself failed.  But throw()
250*cda5da8dSAndroid Build Coastguard Worker                # has to raise the exception to signal propagation, so this
251*cda5da8dSAndroid Build Coastguard Worker                # fixes the impedance mismatch between the throw() protocol
252*cda5da8dSAndroid Build Coastguard Worker                # and the __exit__() protocol.
253*cda5da8dSAndroid Build Coastguard Worker                if exc is not value:
254*cda5da8dSAndroid Build Coastguard Worker                    raise
255*cda5da8dSAndroid Build Coastguard Worker                exc.__traceback__ = traceback
256*cda5da8dSAndroid Build Coastguard Worker                return False
257*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError("generator didn't stop after athrow()")
258*cda5da8dSAndroid Build Coastguard Worker
259*cda5da8dSAndroid Build Coastguard Worker
260*cda5da8dSAndroid Build Coastguard Workerdef contextmanager(func):
261*cda5da8dSAndroid Build Coastguard Worker    """@contextmanager decorator.
262*cda5da8dSAndroid Build Coastguard Worker
263*cda5da8dSAndroid Build Coastguard Worker    Typical usage:
264*cda5da8dSAndroid Build Coastguard Worker
265*cda5da8dSAndroid Build Coastguard Worker        @contextmanager
266*cda5da8dSAndroid Build Coastguard Worker        def some_generator(<arguments>):
267*cda5da8dSAndroid Build Coastguard Worker            <setup>
268*cda5da8dSAndroid Build Coastguard Worker            try:
269*cda5da8dSAndroid Build Coastguard Worker                yield <value>
270*cda5da8dSAndroid Build Coastguard Worker            finally:
271*cda5da8dSAndroid Build Coastguard Worker                <cleanup>
272*cda5da8dSAndroid Build Coastguard Worker
273*cda5da8dSAndroid Build Coastguard Worker    This makes this:
274*cda5da8dSAndroid Build Coastguard Worker
275*cda5da8dSAndroid Build Coastguard Worker        with some_generator(<arguments>) as <variable>:
276*cda5da8dSAndroid Build Coastguard Worker            <body>
277*cda5da8dSAndroid Build Coastguard Worker
278*cda5da8dSAndroid Build Coastguard Worker    equivalent to this:
279*cda5da8dSAndroid Build Coastguard Worker
280*cda5da8dSAndroid Build Coastguard Worker        <setup>
281*cda5da8dSAndroid Build Coastguard Worker        try:
282*cda5da8dSAndroid Build Coastguard Worker            <variable> = <value>
283*cda5da8dSAndroid Build Coastguard Worker            <body>
284*cda5da8dSAndroid Build Coastguard Worker        finally:
285*cda5da8dSAndroid Build Coastguard Worker            <cleanup>
286*cda5da8dSAndroid Build Coastguard Worker    """
287*cda5da8dSAndroid Build Coastguard Worker    @wraps(func)
288*cda5da8dSAndroid Build Coastguard Worker    def helper(*args, **kwds):
289*cda5da8dSAndroid Build Coastguard Worker        return _GeneratorContextManager(func, args, kwds)
290*cda5da8dSAndroid Build Coastguard Worker    return helper
291*cda5da8dSAndroid Build Coastguard Worker
292*cda5da8dSAndroid Build Coastguard Worker
293*cda5da8dSAndroid Build Coastguard Workerdef asynccontextmanager(func):
294*cda5da8dSAndroid Build Coastguard Worker    """@asynccontextmanager decorator.
295*cda5da8dSAndroid Build Coastguard Worker
296*cda5da8dSAndroid Build Coastguard Worker    Typical usage:
297*cda5da8dSAndroid Build Coastguard Worker
298*cda5da8dSAndroid Build Coastguard Worker        @asynccontextmanager
299*cda5da8dSAndroid Build Coastguard Worker        async def some_async_generator(<arguments>):
300*cda5da8dSAndroid Build Coastguard Worker            <setup>
301*cda5da8dSAndroid Build Coastguard Worker            try:
302*cda5da8dSAndroid Build Coastguard Worker                yield <value>
303*cda5da8dSAndroid Build Coastguard Worker            finally:
304*cda5da8dSAndroid Build Coastguard Worker                <cleanup>
305*cda5da8dSAndroid Build Coastguard Worker
306*cda5da8dSAndroid Build Coastguard Worker    This makes this:
307*cda5da8dSAndroid Build Coastguard Worker
308*cda5da8dSAndroid Build Coastguard Worker        async with some_async_generator(<arguments>) as <variable>:
309*cda5da8dSAndroid Build Coastguard Worker            <body>
310*cda5da8dSAndroid Build Coastguard Worker
311*cda5da8dSAndroid Build Coastguard Worker    equivalent to this:
312*cda5da8dSAndroid Build Coastguard Worker
313*cda5da8dSAndroid Build Coastguard Worker        <setup>
314*cda5da8dSAndroid Build Coastguard Worker        try:
315*cda5da8dSAndroid Build Coastguard Worker            <variable> = <value>
316*cda5da8dSAndroid Build Coastguard Worker            <body>
317*cda5da8dSAndroid Build Coastguard Worker        finally:
318*cda5da8dSAndroid Build Coastguard Worker            <cleanup>
319*cda5da8dSAndroid Build Coastguard Worker    """
320*cda5da8dSAndroid Build Coastguard Worker    @wraps(func)
321*cda5da8dSAndroid Build Coastguard Worker    def helper(*args, **kwds):
322*cda5da8dSAndroid Build Coastguard Worker        return _AsyncGeneratorContextManager(func, args, kwds)
323*cda5da8dSAndroid Build Coastguard Worker    return helper
324*cda5da8dSAndroid Build Coastguard Worker
325*cda5da8dSAndroid Build Coastguard Worker
326*cda5da8dSAndroid Build Coastguard Workerclass closing(AbstractContextManager):
327*cda5da8dSAndroid Build Coastguard Worker    """Context to automatically close something at the end of a block.
328*cda5da8dSAndroid Build Coastguard Worker
329*cda5da8dSAndroid Build Coastguard Worker    Code like this:
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Worker        with closing(<module>.open(<arguments>)) as f:
332*cda5da8dSAndroid Build Coastguard Worker            <block>
333*cda5da8dSAndroid Build Coastguard Worker
334*cda5da8dSAndroid Build Coastguard Worker    is equivalent to this:
335*cda5da8dSAndroid Build Coastguard Worker
336*cda5da8dSAndroid Build Coastguard Worker        f = <module>.open(<arguments>)
337*cda5da8dSAndroid Build Coastguard Worker        try:
338*cda5da8dSAndroid Build Coastguard Worker            <block>
339*cda5da8dSAndroid Build Coastguard Worker        finally:
340*cda5da8dSAndroid Build Coastguard Worker            f.close()
341*cda5da8dSAndroid Build Coastguard Worker
342*cda5da8dSAndroid Build Coastguard Worker    """
343*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, thing):
344*cda5da8dSAndroid Build Coastguard Worker        self.thing = thing
345*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
346*cda5da8dSAndroid Build Coastguard Worker        return self.thing
347*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, *exc_info):
348*cda5da8dSAndroid Build Coastguard Worker        self.thing.close()
349*cda5da8dSAndroid Build Coastguard Worker
350*cda5da8dSAndroid Build Coastguard Worker
351*cda5da8dSAndroid Build Coastguard Workerclass aclosing(AbstractAsyncContextManager):
352*cda5da8dSAndroid Build Coastguard Worker    """Async context manager for safely finalizing an asynchronously cleaned-up
353*cda5da8dSAndroid Build Coastguard Worker    resource such as an async generator, calling its ``aclose()`` method.
354*cda5da8dSAndroid Build Coastguard Worker
355*cda5da8dSAndroid Build Coastguard Worker    Code like this:
356*cda5da8dSAndroid Build Coastguard Worker
357*cda5da8dSAndroid Build Coastguard Worker        async with aclosing(<module>.fetch(<arguments>)) as agen:
358*cda5da8dSAndroid Build Coastguard Worker            <block>
359*cda5da8dSAndroid Build Coastguard Worker
360*cda5da8dSAndroid Build Coastguard Worker    is equivalent to this:
361*cda5da8dSAndroid Build Coastguard Worker
362*cda5da8dSAndroid Build Coastguard Worker        agen = <module>.fetch(<arguments>)
363*cda5da8dSAndroid Build Coastguard Worker        try:
364*cda5da8dSAndroid Build Coastguard Worker            <block>
365*cda5da8dSAndroid Build Coastguard Worker        finally:
366*cda5da8dSAndroid Build Coastguard Worker            await agen.aclose()
367*cda5da8dSAndroid Build Coastguard Worker
368*cda5da8dSAndroid Build Coastguard Worker    """
369*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, thing):
370*cda5da8dSAndroid Build Coastguard Worker        self.thing = thing
371*cda5da8dSAndroid Build Coastguard Worker    async def __aenter__(self):
372*cda5da8dSAndroid Build Coastguard Worker        return self.thing
373*cda5da8dSAndroid Build Coastguard Worker    async def __aexit__(self, *exc_info):
374*cda5da8dSAndroid Build Coastguard Worker        await self.thing.aclose()
375*cda5da8dSAndroid Build Coastguard Worker
376*cda5da8dSAndroid Build Coastguard Worker
377*cda5da8dSAndroid Build Coastguard Workerclass _RedirectStream(AbstractContextManager):
378*cda5da8dSAndroid Build Coastguard Worker
379*cda5da8dSAndroid Build Coastguard Worker    _stream = None
380*cda5da8dSAndroid Build Coastguard Worker
381*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, new_target):
382*cda5da8dSAndroid Build Coastguard Worker        self._new_target = new_target
383*cda5da8dSAndroid Build Coastguard Worker        # We use a list of old targets to make this CM re-entrant
384*cda5da8dSAndroid Build Coastguard Worker        self._old_targets = []
385*cda5da8dSAndroid Build Coastguard Worker
386*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
387*cda5da8dSAndroid Build Coastguard Worker        self._old_targets.append(getattr(sys, self._stream))
388*cda5da8dSAndroid Build Coastguard Worker        setattr(sys, self._stream, self._new_target)
389*cda5da8dSAndroid Build Coastguard Worker        return self._new_target
390*cda5da8dSAndroid Build Coastguard Worker
391*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, exctype, excinst, exctb):
392*cda5da8dSAndroid Build Coastguard Worker        setattr(sys, self._stream, self._old_targets.pop())
393*cda5da8dSAndroid Build Coastguard Worker
394*cda5da8dSAndroid Build Coastguard Worker
395*cda5da8dSAndroid Build Coastguard Workerclass redirect_stdout(_RedirectStream):
396*cda5da8dSAndroid Build Coastguard Worker    """Context manager for temporarily redirecting stdout to another file.
397*cda5da8dSAndroid Build Coastguard Worker
398*cda5da8dSAndroid Build Coastguard Worker        # How to send help() to stderr
399*cda5da8dSAndroid Build Coastguard Worker        with redirect_stdout(sys.stderr):
400*cda5da8dSAndroid Build Coastguard Worker            help(dir)
401*cda5da8dSAndroid Build Coastguard Worker
402*cda5da8dSAndroid Build Coastguard Worker        # How to write help() to a file
403*cda5da8dSAndroid Build Coastguard Worker        with open('help.txt', 'w') as f:
404*cda5da8dSAndroid Build Coastguard Worker            with redirect_stdout(f):
405*cda5da8dSAndroid Build Coastguard Worker                help(pow)
406*cda5da8dSAndroid Build Coastguard Worker    """
407*cda5da8dSAndroid Build Coastguard Worker
408*cda5da8dSAndroid Build Coastguard Worker    _stream = "stdout"
409*cda5da8dSAndroid Build Coastguard Worker
410*cda5da8dSAndroid Build Coastguard Worker
411*cda5da8dSAndroid Build Coastguard Workerclass redirect_stderr(_RedirectStream):
412*cda5da8dSAndroid Build Coastguard Worker    """Context manager for temporarily redirecting stderr to another file."""
413*cda5da8dSAndroid Build Coastguard Worker
414*cda5da8dSAndroid Build Coastguard Worker    _stream = "stderr"
415*cda5da8dSAndroid Build Coastguard Worker
416*cda5da8dSAndroid Build Coastguard Worker
417*cda5da8dSAndroid Build Coastguard Workerclass suppress(AbstractContextManager):
418*cda5da8dSAndroid Build Coastguard Worker    """Context manager to suppress specified exceptions
419*cda5da8dSAndroid Build Coastguard Worker
420*cda5da8dSAndroid Build Coastguard Worker    After the exception is suppressed, execution proceeds with the next
421*cda5da8dSAndroid Build Coastguard Worker    statement following the with statement.
422*cda5da8dSAndroid Build Coastguard Worker
423*cda5da8dSAndroid Build Coastguard Worker         with suppress(FileNotFoundError):
424*cda5da8dSAndroid Build Coastguard Worker             os.remove(somefile)
425*cda5da8dSAndroid Build Coastguard Worker         # Execution still resumes here if the file was already removed
426*cda5da8dSAndroid Build Coastguard Worker    """
427*cda5da8dSAndroid Build Coastguard Worker
428*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, *exceptions):
429*cda5da8dSAndroid Build Coastguard Worker        self._exceptions = exceptions
430*cda5da8dSAndroid Build Coastguard Worker
431*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
432*cda5da8dSAndroid Build Coastguard Worker        pass
433*cda5da8dSAndroid Build Coastguard Worker
434*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, exctype, excinst, exctb):
435*cda5da8dSAndroid Build Coastguard Worker        # Unlike isinstance and issubclass, CPython exception handling
436*cda5da8dSAndroid Build Coastguard Worker        # currently only looks at the concrete type hierarchy (ignoring
437*cda5da8dSAndroid Build Coastguard Worker        # the instance and subclass checking hooks). While Guido considers
438*cda5da8dSAndroid Build Coastguard Worker        # that a bug rather than a feature, it's a fairly hard one to fix
439*cda5da8dSAndroid Build Coastguard Worker        # due to various internal implementation details. suppress provides
440*cda5da8dSAndroid Build Coastguard Worker        # the simpler issubclass based semantics, rather than trying to
441*cda5da8dSAndroid Build Coastguard Worker        # exactly reproduce the limitations of the CPython interpreter.
442*cda5da8dSAndroid Build Coastguard Worker        #
443*cda5da8dSAndroid Build Coastguard Worker        # See http://bugs.python.org/issue12029 for more details
444*cda5da8dSAndroid Build Coastguard Worker        return exctype is not None and issubclass(exctype, self._exceptions)
445*cda5da8dSAndroid Build Coastguard Worker
446*cda5da8dSAndroid Build Coastguard Worker
447*cda5da8dSAndroid Build Coastguard Workerclass _BaseExitStack:
448*cda5da8dSAndroid Build Coastguard Worker    """A base class for ExitStack and AsyncExitStack."""
449*cda5da8dSAndroid Build Coastguard Worker
450*cda5da8dSAndroid Build Coastguard Worker    @staticmethod
451*cda5da8dSAndroid Build Coastguard Worker    def _create_exit_wrapper(cm, cm_exit):
452*cda5da8dSAndroid Build Coastguard Worker        return MethodType(cm_exit, cm)
453*cda5da8dSAndroid Build Coastguard Worker
454*cda5da8dSAndroid Build Coastguard Worker    @staticmethod
455*cda5da8dSAndroid Build Coastguard Worker    def _create_cb_wrapper(callback, /, *args, **kwds):
456*cda5da8dSAndroid Build Coastguard Worker        def _exit_wrapper(exc_type, exc, tb):
457*cda5da8dSAndroid Build Coastguard Worker            callback(*args, **kwds)
458*cda5da8dSAndroid Build Coastguard Worker        return _exit_wrapper
459*cda5da8dSAndroid Build Coastguard Worker
460*cda5da8dSAndroid Build Coastguard Worker    def __init__(self):
461*cda5da8dSAndroid Build Coastguard Worker        self._exit_callbacks = deque()
462*cda5da8dSAndroid Build Coastguard Worker
463*cda5da8dSAndroid Build Coastguard Worker    def pop_all(self):
464*cda5da8dSAndroid Build Coastguard Worker        """Preserve the context stack by transferring it to a new instance."""
465*cda5da8dSAndroid Build Coastguard Worker        new_stack = type(self)()
466*cda5da8dSAndroid Build Coastguard Worker        new_stack._exit_callbacks = self._exit_callbacks
467*cda5da8dSAndroid Build Coastguard Worker        self._exit_callbacks = deque()
468*cda5da8dSAndroid Build Coastguard Worker        return new_stack
469*cda5da8dSAndroid Build Coastguard Worker
470*cda5da8dSAndroid Build Coastguard Worker    def push(self, exit):
471*cda5da8dSAndroid Build Coastguard Worker        """Registers a callback with the standard __exit__ method signature.
472*cda5da8dSAndroid Build Coastguard Worker
473*cda5da8dSAndroid Build Coastguard Worker        Can suppress exceptions the same way __exit__ method can.
474*cda5da8dSAndroid Build Coastguard Worker        Also accepts any object with an __exit__ method (registering a call
475*cda5da8dSAndroid Build Coastguard Worker        to the method instead of the object itself).
476*cda5da8dSAndroid Build Coastguard Worker        """
477*cda5da8dSAndroid Build Coastguard Worker        # We use an unbound method rather than a bound method to follow
478*cda5da8dSAndroid Build Coastguard Worker        # the standard lookup behaviour for special methods.
479*cda5da8dSAndroid Build Coastguard Worker        _cb_type = type(exit)
480*cda5da8dSAndroid Build Coastguard Worker
481*cda5da8dSAndroid Build Coastguard Worker        try:
482*cda5da8dSAndroid Build Coastguard Worker            exit_method = _cb_type.__exit__
483*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
484*cda5da8dSAndroid Build Coastguard Worker            # Not a context manager, so assume it's a callable.
485*cda5da8dSAndroid Build Coastguard Worker            self._push_exit_callback(exit)
486*cda5da8dSAndroid Build Coastguard Worker        else:
487*cda5da8dSAndroid Build Coastguard Worker            self._push_cm_exit(exit, exit_method)
488*cda5da8dSAndroid Build Coastguard Worker        return exit  # Allow use as a decorator.
489*cda5da8dSAndroid Build Coastguard Worker
490*cda5da8dSAndroid Build Coastguard Worker    def enter_context(self, cm):
491*cda5da8dSAndroid Build Coastguard Worker        """Enters the supplied context manager.
492*cda5da8dSAndroid Build Coastguard Worker
493*cda5da8dSAndroid Build Coastguard Worker        If successful, also pushes its __exit__ method as a callback and
494*cda5da8dSAndroid Build Coastguard Worker        returns the result of the __enter__ method.
495*cda5da8dSAndroid Build Coastguard Worker        """
496*cda5da8dSAndroid Build Coastguard Worker        # We look up the special methods on the type to match the with
497*cda5da8dSAndroid Build Coastguard Worker        # statement.
498*cda5da8dSAndroid Build Coastguard Worker        cls = type(cm)
499*cda5da8dSAndroid Build Coastguard Worker        try:
500*cda5da8dSAndroid Build Coastguard Worker            _enter = cls.__enter__
501*cda5da8dSAndroid Build Coastguard Worker            _exit = cls.__exit__
502*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
503*cda5da8dSAndroid Build Coastguard Worker            raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
504*cda5da8dSAndroid Build Coastguard Worker                            f"not support the context manager protocol") from None
505*cda5da8dSAndroid Build Coastguard Worker        result = _enter(cm)
506*cda5da8dSAndroid Build Coastguard Worker        self._push_cm_exit(cm, _exit)
507*cda5da8dSAndroid Build Coastguard Worker        return result
508*cda5da8dSAndroid Build Coastguard Worker
509*cda5da8dSAndroid Build Coastguard Worker    def callback(self, callback, /, *args, **kwds):
510*cda5da8dSAndroid Build Coastguard Worker        """Registers an arbitrary callback and arguments.
511*cda5da8dSAndroid Build Coastguard Worker
512*cda5da8dSAndroid Build Coastguard Worker        Cannot suppress exceptions.
513*cda5da8dSAndroid Build Coastguard Worker        """
514*cda5da8dSAndroid Build Coastguard Worker        _exit_wrapper = self._create_cb_wrapper(callback, *args, **kwds)
515*cda5da8dSAndroid Build Coastguard Worker
516*cda5da8dSAndroid Build Coastguard Worker        # We changed the signature, so using @wraps is not appropriate, but
517*cda5da8dSAndroid Build Coastguard Worker        # setting __wrapped__ may still help with introspection.
518*cda5da8dSAndroid Build Coastguard Worker        _exit_wrapper.__wrapped__ = callback
519*cda5da8dSAndroid Build Coastguard Worker        self._push_exit_callback(_exit_wrapper)
520*cda5da8dSAndroid Build Coastguard Worker        return callback  # Allow use as a decorator
521*cda5da8dSAndroid Build Coastguard Worker
522*cda5da8dSAndroid Build Coastguard Worker    def _push_cm_exit(self, cm, cm_exit):
523*cda5da8dSAndroid Build Coastguard Worker        """Helper to correctly register callbacks to __exit__ methods."""
524*cda5da8dSAndroid Build Coastguard Worker        _exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
525*cda5da8dSAndroid Build Coastguard Worker        self._push_exit_callback(_exit_wrapper, True)
526*cda5da8dSAndroid Build Coastguard Worker
527*cda5da8dSAndroid Build Coastguard Worker    def _push_exit_callback(self, callback, is_sync=True):
528*cda5da8dSAndroid Build Coastguard Worker        self._exit_callbacks.append((is_sync, callback))
529*cda5da8dSAndroid Build Coastguard Worker
530*cda5da8dSAndroid Build Coastguard Worker
531*cda5da8dSAndroid Build Coastguard Worker# Inspired by discussions on http://bugs.python.org/issue13585
532*cda5da8dSAndroid Build Coastguard Workerclass ExitStack(_BaseExitStack, AbstractContextManager):
533*cda5da8dSAndroid Build Coastguard Worker    """Context manager for dynamic management of a stack of exit callbacks.
534*cda5da8dSAndroid Build Coastguard Worker
535*cda5da8dSAndroid Build Coastguard Worker    For example:
536*cda5da8dSAndroid Build Coastguard Worker        with ExitStack() as stack:
537*cda5da8dSAndroid Build Coastguard Worker            files = [stack.enter_context(open(fname)) for fname in filenames]
538*cda5da8dSAndroid Build Coastguard Worker            # All opened files will automatically be closed at the end of
539*cda5da8dSAndroid Build Coastguard Worker            # the with statement, even if attempts to open files later
540*cda5da8dSAndroid Build Coastguard Worker            # in the list raise an exception.
541*cda5da8dSAndroid Build Coastguard Worker    """
542*cda5da8dSAndroid Build Coastguard Worker
543*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
544*cda5da8dSAndroid Build Coastguard Worker        return self
545*cda5da8dSAndroid Build Coastguard Worker
546*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, *exc_details):
547*cda5da8dSAndroid Build Coastguard Worker        received_exc = exc_details[0] is not None
548*cda5da8dSAndroid Build Coastguard Worker
549*cda5da8dSAndroid Build Coastguard Worker        # We manipulate the exception state so it behaves as though
550*cda5da8dSAndroid Build Coastguard Worker        # we were actually nesting multiple with statements
551*cda5da8dSAndroid Build Coastguard Worker        frame_exc = sys.exc_info()[1]
552*cda5da8dSAndroid Build Coastguard Worker        def _fix_exception_context(new_exc, old_exc):
553*cda5da8dSAndroid Build Coastguard Worker            # Context may not be correct, so find the end of the chain
554*cda5da8dSAndroid Build Coastguard Worker            while 1:
555*cda5da8dSAndroid Build Coastguard Worker                exc_context = new_exc.__context__
556*cda5da8dSAndroid Build Coastguard Worker                if exc_context is None or exc_context is old_exc:
557*cda5da8dSAndroid Build Coastguard Worker                    # Context is already set correctly (see issue 20317)
558*cda5da8dSAndroid Build Coastguard Worker                    return
559*cda5da8dSAndroid Build Coastguard Worker                if exc_context is frame_exc:
560*cda5da8dSAndroid Build Coastguard Worker                    break
561*cda5da8dSAndroid Build Coastguard Worker                new_exc = exc_context
562*cda5da8dSAndroid Build Coastguard Worker            # Change the end of the chain to point to the exception
563*cda5da8dSAndroid Build Coastguard Worker            # we expect it to reference
564*cda5da8dSAndroid Build Coastguard Worker            new_exc.__context__ = old_exc
565*cda5da8dSAndroid Build Coastguard Worker
566*cda5da8dSAndroid Build Coastguard Worker        # Callbacks are invoked in LIFO order to match the behaviour of
567*cda5da8dSAndroid Build Coastguard Worker        # nested context managers
568*cda5da8dSAndroid Build Coastguard Worker        suppressed_exc = False
569*cda5da8dSAndroid Build Coastguard Worker        pending_raise = False
570*cda5da8dSAndroid Build Coastguard Worker        while self._exit_callbacks:
571*cda5da8dSAndroid Build Coastguard Worker            is_sync, cb = self._exit_callbacks.pop()
572*cda5da8dSAndroid Build Coastguard Worker            assert is_sync
573*cda5da8dSAndroid Build Coastguard Worker            try:
574*cda5da8dSAndroid Build Coastguard Worker                if cb(*exc_details):
575*cda5da8dSAndroid Build Coastguard Worker                    suppressed_exc = True
576*cda5da8dSAndroid Build Coastguard Worker                    pending_raise = False
577*cda5da8dSAndroid Build Coastguard Worker                    exc_details = (None, None, None)
578*cda5da8dSAndroid Build Coastguard Worker            except:
579*cda5da8dSAndroid Build Coastguard Worker                new_exc_details = sys.exc_info()
580*cda5da8dSAndroid Build Coastguard Worker                # simulate the stack of exceptions by setting the context
581*cda5da8dSAndroid Build Coastguard Worker                _fix_exception_context(new_exc_details[1], exc_details[1])
582*cda5da8dSAndroid Build Coastguard Worker                pending_raise = True
583*cda5da8dSAndroid Build Coastguard Worker                exc_details = new_exc_details
584*cda5da8dSAndroid Build Coastguard Worker        if pending_raise:
585*cda5da8dSAndroid Build Coastguard Worker            try:
586*cda5da8dSAndroid Build Coastguard Worker                # bare "raise exc_details[1]" replaces our carefully
587*cda5da8dSAndroid Build Coastguard Worker                # set-up context
588*cda5da8dSAndroid Build Coastguard Worker                fixed_ctx = exc_details[1].__context__
589*cda5da8dSAndroid Build Coastguard Worker                raise exc_details[1]
590*cda5da8dSAndroid Build Coastguard Worker            except BaseException:
591*cda5da8dSAndroid Build Coastguard Worker                exc_details[1].__context__ = fixed_ctx
592*cda5da8dSAndroid Build Coastguard Worker                raise
593*cda5da8dSAndroid Build Coastguard Worker        return received_exc and suppressed_exc
594*cda5da8dSAndroid Build Coastguard Worker
595*cda5da8dSAndroid Build Coastguard Worker    def close(self):
596*cda5da8dSAndroid Build Coastguard Worker        """Immediately unwind the context stack."""
597*cda5da8dSAndroid Build Coastguard Worker        self.__exit__(None, None, None)
598*cda5da8dSAndroid Build Coastguard Worker
599*cda5da8dSAndroid Build Coastguard Worker
600*cda5da8dSAndroid Build Coastguard Worker# Inspired by discussions on https://bugs.python.org/issue29302
601*cda5da8dSAndroid Build Coastguard Workerclass AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
602*cda5da8dSAndroid Build Coastguard Worker    """Async context manager for dynamic management of a stack of exit
603*cda5da8dSAndroid Build Coastguard Worker    callbacks.
604*cda5da8dSAndroid Build Coastguard Worker
605*cda5da8dSAndroid Build Coastguard Worker    For example:
606*cda5da8dSAndroid Build Coastguard Worker        async with AsyncExitStack() as stack:
607*cda5da8dSAndroid Build Coastguard Worker            connections = [await stack.enter_async_context(get_connection())
608*cda5da8dSAndroid Build Coastguard Worker                for i in range(5)]
609*cda5da8dSAndroid Build Coastguard Worker            # All opened connections will automatically be released at the
610*cda5da8dSAndroid Build Coastguard Worker            # end of the async with statement, even if attempts to open a
611*cda5da8dSAndroid Build Coastguard Worker            # connection later in the list raise an exception.
612*cda5da8dSAndroid Build Coastguard Worker    """
613*cda5da8dSAndroid Build Coastguard Worker
614*cda5da8dSAndroid Build Coastguard Worker    @staticmethod
615*cda5da8dSAndroid Build Coastguard Worker    def _create_async_exit_wrapper(cm, cm_exit):
616*cda5da8dSAndroid Build Coastguard Worker        return MethodType(cm_exit, cm)
617*cda5da8dSAndroid Build Coastguard Worker
618*cda5da8dSAndroid Build Coastguard Worker    @staticmethod
619*cda5da8dSAndroid Build Coastguard Worker    def _create_async_cb_wrapper(callback, /, *args, **kwds):
620*cda5da8dSAndroid Build Coastguard Worker        async def _exit_wrapper(exc_type, exc, tb):
621*cda5da8dSAndroid Build Coastguard Worker            await callback(*args, **kwds)
622*cda5da8dSAndroid Build Coastguard Worker        return _exit_wrapper
623*cda5da8dSAndroid Build Coastguard Worker
624*cda5da8dSAndroid Build Coastguard Worker    async def enter_async_context(self, cm):
625*cda5da8dSAndroid Build Coastguard Worker        """Enters the supplied async context manager.
626*cda5da8dSAndroid Build Coastguard Worker
627*cda5da8dSAndroid Build Coastguard Worker        If successful, also pushes its __aexit__ method as a callback and
628*cda5da8dSAndroid Build Coastguard Worker        returns the result of the __aenter__ method.
629*cda5da8dSAndroid Build Coastguard Worker        """
630*cda5da8dSAndroid Build Coastguard Worker        cls = type(cm)
631*cda5da8dSAndroid Build Coastguard Worker        try:
632*cda5da8dSAndroid Build Coastguard Worker            _enter = cls.__aenter__
633*cda5da8dSAndroid Build Coastguard Worker            _exit = cls.__aexit__
634*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
635*cda5da8dSAndroid Build Coastguard Worker            raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
636*cda5da8dSAndroid Build Coastguard Worker                            f"not support the asynchronous context manager protocol"
637*cda5da8dSAndroid Build Coastguard Worker                           ) from None
638*cda5da8dSAndroid Build Coastguard Worker        result = await _enter(cm)
639*cda5da8dSAndroid Build Coastguard Worker        self._push_async_cm_exit(cm, _exit)
640*cda5da8dSAndroid Build Coastguard Worker        return result
641*cda5da8dSAndroid Build Coastguard Worker
642*cda5da8dSAndroid Build Coastguard Worker    def push_async_exit(self, exit):
643*cda5da8dSAndroid Build Coastguard Worker        """Registers a coroutine function with the standard __aexit__ method
644*cda5da8dSAndroid Build Coastguard Worker        signature.
645*cda5da8dSAndroid Build Coastguard Worker
646*cda5da8dSAndroid Build Coastguard Worker        Can suppress exceptions the same way __aexit__ method can.
647*cda5da8dSAndroid Build Coastguard Worker        Also accepts any object with an __aexit__ method (registering a call
648*cda5da8dSAndroid Build Coastguard Worker        to the method instead of the object itself).
649*cda5da8dSAndroid Build Coastguard Worker        """
650*cda5da8dSAndroid Build Coastguard Worker        _cb_type = type(exit)
651*cda5da8dSAndroid Build Coastguard Worker        try:
652*cda5da8dSAndroid Build Coastguard Worker            exit_method = _cb_type.__aexit__
653*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
654*cda5da8dSAndroid Build Coastguard Worker            # Not an async context manager, so assume it's a coroutine function
655*cda5da8dSAndroid Build Coastguard Worker            self._push_exit_callback(exit, False)
656*cda5da8dSAndroid Build Coastguard Worker        else:
657*cda5da8dSAndroid Build Coastguard Worker            self._push_async_cm_exit(exit, exit_method)
658*cda5da8dSAndroid Build Coastguard Worker        return exit  # Allow use as a decorator
659*cda5da8dSAndroid Build Coastguard Worker
660*cda5da8dSAndroid Build Coastguard Worker    def push_async_callback(self, callback, /, *args, **kwds):
661*cda5da8dSAndroid Build Coastguard Worker        """Registers an arbitrary coroutine function and arguments.
662*cda5da8dSAndroid Build Coastguard Worker
663*cda5da8dSAndroid Build Coastguard Worker        Cannot suppress exceptions.
664*cda5da8dSAndroid Build Coastguard Worker        """
665*cda5da8dSAndroid Build Coastguard Worker        _exit_wrapper = self._create_async_cb_wrapper(callback, *args, **kwds)
666*cda5da8dSAndroid Build Coastguard Worker
667*cda5da8dSAndroid Build Coastguard Worker        # We changed the signature, so using @wraps is not appropriate, but
668*cda5da8dSAndroid Build Coastguard Worker        # setting __wrapped__ may still help with introspection.
669*cda5da8dSAndroid Build Coastguard Worker        _exit_wrapper.__wrapped__ = callback
670*cda5da8dSAndroid Build Coastguard Worker        self._push_exit_callback(_exit_wrapper, False)
671*cda5da8dSAndroid Build Coastguard Worker        return callback  # Allow use as a decorator
672*cda5da8dSAndroid Build Coastguard Worker
673*cda5da8dSAndroid Build Coastguard Worker    async def aclose(self):
674*cda5da8dSAndroid Build Coastguard Worker        """Immediately unwind the context stack."""
675*cda5da8dSAndroid Build Coastguard Worker        await self.__aexit__(None, None, None)
676*cda5da8dSAndroid Build Coastguard Worker
677*cda5da8dSAndroid Build Coastguard Worker    def _push_async_cm_exit(self, cm, cm_exit):
678*cda5da8dSAndroid Build Coastguard Worker        """Helper to correctly register coroutine function to __aexit__
679*cda5da8dSAndroid Build Coastguard Worker        method."""
680*cda5da8dSAndroid Build Coastguard Worker        _exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit)
681*cda5da8dSAndroid Build Coastguard Worker        self._push_exit_callback(_exit_wrapper, False)
682*cda5da8dSAndroid Build Coastguard Worker
683*cda5da8dSAndroid Build Coastguard Worker    async def __aenter__(self):
684*cda5da8dSAndroid Build Coastguard Worker        return self
685*cda5da8dSAndroid Build Coastguard Worker
686*cda5da8dSAndroid Build Coastguard Worker    async def __aexit__(self, *exc_details):
687*cda5da8dSAndroid Build Coastguard Worker        received_exc = exc_details[0] is not None
688*cda5da8dSAndroid Build Coastguard Worker
689*cda5da8dSAndroid Build Coastguard Worker        # We manipulate the exception state so it behaves as though
690*cda5da8dSAndroid Build Coastguard Worker        # we were actually nesting multiple with statements
691*cda5da8dSAndroid Build Coastguard Worker        frame_exc = sys.exc_info()[1]
692*cda5da8dSAndroid Build Coastguard Worker        def _fix_exception_context(new_exc, old_exc):
693*cda5da8dSAndroid Build Coastguard Worker            # Context may not be correct, so find the end of the chain
694*cda5da8dSAndroid Build Coastguard Worker            while 1:
695*cda5da8dSAndroid Build Coastguard Worker                exc_context = new_exc.__context__
696*cda5da8dSAndroid Build Coastguard Worker                if exc_context is None or exc_context is old_exc:
697*cda5da8dSAndroid Build Coastguard Worker                    # Context is already set correctly (see issue 20317)
698*cda5da8dSAndroid Build Coastguard Worker                    return
699*cda5da8dSAndroid Build Coastguard Worker                if exc_context is frame_exc:
700*cda5da8dSAndroid Build Coastguard Worker                    break
701*cda5da8dSAndroid Build Coastguard Worker                new_exc = exc_context
702*cda5da8dSAndroid Build Coastguard Worker            # Change the end of the chain to point to the exception
703*cda5da8dSAndroid Build Coastguard Worker            # we expect it to reference
704*cda5da8dSAndroid Build Coastguard Worker            new_exc.__context__ = old_exc
705*cda5da8dSAndroid Build Coastguard Worker
706*cda5da8dSAndroid Build Coastguard Worker        # Callbacks are invoked in LIFO order to match the behaviour of
707*cda5da8dSAndroid Build Coastguard Worker        # nested context managers
708*cda5da8dSAndroid Build Coastguard Worker        suppressed_exc = False
709*cda5da8dSAndroid Build Coastguard Worker        pending_raise = False
710*cda5da8dSAndroid Build Coastguard Worker        while self._exit_callbacks:
711*cda5da8dSAndroid Build Coastguard Worker            is_sync, cb = self._exit_callbacks.pop()
712*cda5da8dSAndroid Build Coastguard Worker            try:
713*cda5da8dSAndroid Build Coastguard Worker                if is_sync:
714*cda5da8dSAndroid Build Coastguard Worker                    cb_suppress = cb(*exc_details)
715*cda5da8dSAndroid Build Coastguard Worker                else:
716*cda5da8dSAndroid Build Coastguard Worker                    cb_suppress = await cb(*exc_details)
717*cda5da8dSAndroid Build Coastguard Worker
718*cda5da8dSAndroid Build Coastguard Worker                if cb_suppress:
719*cda5da8dSAndroid Build Coastguard Worker                    suppressed_exc = True
720*cda5da8dSAndroid Build Coastguard Worker                    pending_raise = False
721*cda5da8dSAndroid Build Coastguard Worker                    exc_details = (None, None, None)
722*cda5da8dSAndroid Build Coastguard Worker            except:
723*cda5da8dSAndroid Build Coastguard Worker                new_exc_details = sys.exc_info()
724*cda5da8dSAndroid Build Coastguard Worker                # simulate the stack of exceptions by setting the context
725*cda5da8dSAndroid Build Coastguard Worker                _fix_exception_context(new_exc_details[1], exc_details[1])
726*cda5da8dSAndroid Build Coastguard Worker                pending_raise = True
727*cda5da8dSAndroid Build Coastguard Worker                exc_details = new_exc_details
728*cda5da8dSAndroid Build Coastguard Worker        if pending_raise:
729*cda5da8dSAndroid Build Coastguard Worker            try:
730*cda5da8dSAndroid Build Coastguard Worker                # bare "raise exc_details[1]" replaces our carefully
731*cda5da8dSAndroid Build Coastguard Worker                # set-up context
732*cda5da8dSAndroid Build Coastguard Worker                fixed_ctx = exc_details[1].__context__
733*cda5da8dSAndroid Build Coastguard Worker                raise exc_details[1]
734*cda5da8dSAndroid Build Coastguard Worker            except BaseException:
735*cda5da8dSAndroid Build Coastguard Worker                exc_details[1].__context__ = fixed_ctx
736*cda5da8dSAndroid Build Coastguard Worker                raise
737*cda5da8dSAndroid Build Coastguard Worker        return received_exc and suppressed_exc
738*cda5da8dSAndroid Build Coastguard Worker
739*cda5da8dSAndroid Build Coastguard Worker
740*cda5da8dSAndroid Build Coastguard Workerclass nullcontext(AbstractContextManager, AbstractAsyncContextManager):
741*cda5da8dSAndroid Build Coastguard Worker    """Context manager that does no additional processing.
742*cda5da8dSAndroid Build Coastguard Worker
743*cda5da8dSAndroid Build Coastguard Worker    Used as a stand-in for a normal context manager, when a particular
744*cda5da8dSAndroid Build Coastguard Worker    block of code is only sometimes used with a normal context manager:
745*cda5da8dSAndroid Build Coastguard Worker
746*cda5da8dSAndroid Build Coastguard Worker    cm = optional_cm if condition else nullcontext()
747*cda5da8dSAndroid Build Coastguard Worker    with cm:
748*cda5da8dSAndroid Build Coastguard Worker        # Perform operation, using optional_cm if condition is True
749*cda5da8dSAndroid Build Coastguard Worker    """
750*cda5da8dSAndroid Build Coastguard Worker
751*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, enter_result=None):
752*cda5da8dSAndroid Build Coastguard Worker        self.enter_result = enter_result
753*cda5da8dSAndroid Build Coastguard Worker
754*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
755*cda5da8dSAndroid Build Coastguard Worker        return self.enter_result
756*cda5da8dSAndroid Build Coastguard Worker
757*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, *excinfo):
758*cda5da8dSAndroid Build Coastguard Worker        pass
759*cda5da8dSAndroid Build Coastguard Worker
760*cda5da8dSAndroid Build Coastguard Worker    async def __aenter__(self):
761*cda5da8dSAndroid Build Coastguard Worker        return self.enter_result
762*cda5da8dSAndroid Build Coastguard Worker
763*cda5da8dSAndroid Build Coastguard Worker    async def __aexit__(self, *excinfo):
764*cda5da8dSAndroid Build Coastguard Worker        pass
765*cda5da8dSAndroid Build Coastguard Worker
766*cda5da8dSAndroid Build Coastguard Worker
767*cda5da8dSAndroid Build Coastguard Workerclass chdir(AbstractContextManager):
768*cda5da8dSAndroid Build Coastguard Worker    """Non thread-safe context manager to change the current working directory."""
769*cda5da8dSAndroid Build Coastguard Worker
770*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, path):
771*cda5da8dSAndroid Build Coastguard Worker        self.path = path
772*cda5da8dSAndroid Build Coastguard Worker        self._old_cwd = []
773*cda5da8dSAndroid Build Coastguard Worker
774*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
775*cda5da8dSAndroid Build Coastguard Worker        self._old_cwd.append(os.getcwd())
776*cda5da8dSAndroid Build Coastguard Worker        os.chdir(self.path)
777*cda5da8dSAndroid Build Coastguard Worker
778*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, *excinfo):
779*cda5da8dSAndroid Build Coastguard Worker        os.chdir(self._old_cwd.pop())
780