utilities for withstatement contexts see pep 343 import abc import os import sys import collectionsabc from collections import deque from functools import wraps from types import methodtype genericalias all asynccontextmanager contextmanager closing nullcontext abstractcontextmanager abstractasynccontextmanager asyncexitstack contextdecorator exitstack redirectstdout redirectstderr suppress aclosing chdir class abstractcontextmanagerabc abc return self upon entering the runtime context return self abc abstractmethod def exitself exctype excvalue traceback an abstract base class for asynchronous context managers classgetitem classmethodgenericalias slots async def aenterself raise any exception triggered within the runtime context return none classmethod def subclasshookcls c if cls is abstractasynccontextmanager return collectionsabc checkmethodsc aenter aexit return notimplemented class contextdecoratorobject a base class or mixin that enables context managers to work as decorators def recreatecmself return self def callself func wrapsfunc def innerargs kwds with self recreatecm return funcargs kwds return inner class asynccontextdecoratorobject a base class or mixin that enables async context managers to work as decorators def recreatecmself return self def callself func wrapsfunc async def innerargs kwds async with self recreatecm return await funcargs kwds return inner class generatorcontextmanagerbase issue 19330 ensure context manager instances have good docstrings 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 orgissue19404 for more details gcmb instances are oneshot context managers so the cm must be recreated each time a decorated function is called helper for contextmanager decorator def enterself do not keep args and kwds alive unnecessarily they are only needed for recreation which is not possible anymore del self args self kwds self func try return nextself gen except stopiteration raise runtimeerrorgenerator didn t yield from none def exitself typ value traceback if typ is none try nextself gen except stopiteration return false else try raise runtimeerrorgenerator didn t stop finally self gen close else if value is none need to force instantiation so we can reliably tell if we get the same exception back value typ try self gen throwvalue except stopiteration as exc suppress stopiteration unless it s the same exception that was passed to throw this prevents a stopiteration raised inside the with statement from being suppressed return exc is not value except runtimeerror as exc don t reraise the passed in exception issue27122 if exc is value exc traceback traceback 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 actually stopasynciteration see issue29692 if isinstancevalue stopiteration and exc cause is value value traceback traceback return false raise except baseexception as exc only reraise if it s not the exception that was passed to throw because exit must not raise an exception unless exit itself failed but throw has to raise the exception to signal propagation so this fixes the impedance mismatch between the throw protocol and the exit protocol if exc is not value raise exc traceback traceback return false try raise runtimeerrorgenerator didn t stop after throw finally self gen close class asyncgeneratorcontextmanager generatorcontextmanagerbase abstractasynccontextmanager asynccontextdecorator do not keep args and kwds alive unnecessarily they are only needed for recreation which is not possible anymore need to force instantiation so we can reliably tell if we get the same exception back suppress stopiteration unless it s the same exception that was passed to throw this prevents a stopiteration raised inside the with statement from being suppressed don t reraise the passed in exception issue27122 avoid suppressing if a stopasynciteration exception was passed to athrow 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 actually stopasynciteration see issue29692 only reraise if it s not the exception that was passed to throw because exit must not raise an exception unless exit itself failed but throw has to raise the exception to signal propagation so this fixes the impedance mismatch between the throw protocol and the exit protocol contextmanager decorator typical usage contextmanager def somegeneratorarguments setup try yield value finally cleanup this makes this with somegeneratorarguments as variable body equivalent to this setup try variable value body finally cleanup asynccontextmanager decorator typical usage asynccontextmanager async def someasyncgeneratorarguments setup try yield value finally cleanup this makes this async with someasyncgeneratorarguments as variable body equivalent to this setup try variable value body finally cleanup context to automatically close something at the end of a block code like this with closingmodule openarguments as f block is equivalent to this f module openarguments try block finally f close async context manager for safely finalizing an asynchronously cleanedup resource such as an async generator calling its aclose method code like this async with aclosingmodule fetcharguments as agen block is equivalent to this agen module fetcharguments try block finally await agen aclose we use a list of old targets to make this cm reentrant context manager for temporarily redirecting stdout to another file how to send help to stderr with redirectstdoutsys stderr helpdir how to write help to a file with open help txt w as f with redirectstdoutf helppow context manager for temporarily redirecting stderr to another file stream stderr class suppressabstractcontextmanager execution still resumes here if the file was already removed def initself exceptions self exceptions exceptions def enterself pass def exitself exctype excinst exctb unlike isinstance and issubclass cpython exception handling currently only looks at the concrete type hierarchy ignoring the instance and subclass checking hooks while guido considers that a bug rather than a feature it s a fairly hard one to fix due to various internal implementation details suppress provides the simpler issubclass based semantics rather than trying to exactly reproduce the limitations of the cpython interpreter see http bugs python orgissue12029 for more details if exctype is none return if issubclassexctype self exceptions return true if issubclassexctype baseexceptiongroup match rest excinst splitself exceptions if rest is none return true raise rest return false class baseexitstack preserve the context stack by transferring it to a new instance newstack typeself newstack exitcallbacks self exitcallbacks self exitcallbacks deque return newstack def pushself exit we use an unbound method rather than a bound method to follow the standard lookup behaviour for special methods cbtype typeexit try exitmethod cbtype exit except attributeerror not a context manager so assume it s a callable self pushexitcallbackexit else self pushcmexitexit exitmethod return exit allow use as a decorator def entercontextself cm we look up the special methods on the type to match the with statement cls typecm try enter cls enter exit cls exit except attributeerror raise typeerrorf cls module cls qualname object does fnot support the context manager protocol from none result entercm self pushcmexitcm exit return result def callbackself callback args kwds exitwrapper self createcbwrappercallback args kwds we changed the signature so using wraps is not appropriate but setting wrapped may still help with introspection exitwrapper wrapped callback self pushexitcallbackexitwrapper return callback allow use as a decorator def pushcmexitself cm cmexit inspired by discussions on http bugs python orgissue13585 context manager for dynamic management of a stack of exit callbacks for example with exitstack as stack files stack entercontextopenfname for fname in filenames all opened files will automatically be closed at the end of the with statement even if attempts to open files later in the list raise an exception we manipulate the exception state so it behaves as though we were actually nesting multiple with statements context may not be correct so find the end of the chain context is already set correctly see issue 20317 change the end of the chain to point to the exception we expect it to reference callbacks are invoked in lifo order to match the behaviour of nested context managers simulate the stack of exceptions by setting the context bare raise exc replaces our carefully setup context immediately unwind the context stack self exitnone none none inspired by discussions on https bugs python orgissue29302 class asyncexitstackbaseexitstack abstractasynccontextmanager all opened connections will automatically be released at the end of the async with statement even if attempts to open a connection later in the list raise an exception staticmethod def createasyncexitwrappercm cmexit return methodtypecmexit cm staticmethod def createasynccbwrappercallback args kwds async def exitwrapperexctype exc tb await callbackargs kwds return exitwrapper async def enterasynccontextself cm cls typecm try enter cls aenter exit cls aexit except attributeerror raise typeerrorf cls module cls qualname object does fnot support the asynchronous context manager protocol from none result await entercm self pushasynccmexitcm exit return result def pushasyncexitself exit cbtype typeexit try exitmethod cbtype aexit except attributeerror not an async context manager so assume it s a coroutine function self pushexitcallbackexit false else self pushasynccmexitexit exitmethod return exit allow use as a decorator def pushasynccallbackself callback args kwds exitwrapper self createasynccbwrappercallback args kwds we changed the signature so using wraps is not appropriate but setting wrapped may still help with introspection exitwrapper wrapped callback self pushexitcallbackexitwrapper false return callback allow use as a decorator async def acloseself helper to correctly register coroutine function to aexit method exitwrapper self createasyncexitwrappercm cmexit self pushexitcallbackexitwrapper false async def aenterself return self async def aexitself excdetails exc excdetails1 receivedexc exc is not none we manipulate the exception state so it behaves as though we were actually nesting multiple with statements frameexc sys exception def fixexceptioncontextnewexc oldexc context may not be correct so find the end of the chain while 1 exccontext newexc context if exccontext is none or exccontext is oldexc context is already set correctly see issue 20317 return if exccontext is frameexc break newexc exccontext change the end of the chain to point to the exception we expect it to reference newexc context oldexc callbacks are invoked in lifo order to match the behaviour of nested context managers suppressedexc false pendingraise false while self exitcallbacks issync cb self exitcallbacks pop try if exc is none excdetails none none none else excdetails typeexc exc exc traceback if issync cbsuppress cbexcdetails else cbsuppress await cbexcdetails if cbsuppress suppressedexc true pendingraise false exc none except baseexception as newexc simulate the stack of exceptions by setting the context fixexceptioncontextnewexc exc pendingraise true exc newexc if pendingraise try bare raise exc replaces our carefully setup context fixedctx exc context raise exc except baseexception exc context fixedctx raise return receivedexc and suppressedexc class nullcontextabstractcontextmanager abstractasynccontextmanager perform operation using optionalcm if condition is true def initself enterresultnone self enterresult enterresult def enterself return self enterresult def exitself excinfo pass async def aenterself return self enterresult async def aexitself excinfo pass class chdirabstractcontextmanager an abstract base class for context managers return self upon entering the runtime context raise any exception triggered within the runtime context an abstract base class for asynchronous context managers return self upon entering the runtime context raise any exception triggered within the runtime context return a recreated instance of self allows an otherwise one shot context manager like _generatorcontextmanager to support use as a decorator via implicit recreation this is a private interface just for _generatorcontextmanager see issue 11647 for details return a recreated instance of self shared functionality for contextmanager and asynccontextmanager issue 19330 ensure context manager instances have good docstrings 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 _gcmb instances are one shot context managers so the cm must be recreated each time a decorated function is called helper for contextmanager decorator do not keep args and kwds alive unnecessarily they are only needed for recreation which is not possible anymore need to force instantiation so we can reliably tell if we get the same exception back suppress stopiteration unless it s the same exception that was passed to throw this prevents a stopiteration raised inside the with statement from being suppressed don t re raise the passed in exception issue27122 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 actually stop async iteration see issue29692 only re raise if it s not the exception that was passed to throw because __exit__ must not raise an exception unless __exit__ itself failed but throw has to raise the exception to signal propagation so this fixes the impedance mismatch between the throw protocol and the __exit__ protocol helper for asynccontextmanager decorator do not keep args and kwds alive unnecessarily they are only needed for recreation which is not possible anymore need to force instantiation so we can reliably tell if we get the same exception back suppress stopiteration unless it s the same exception that was passed to throw this prevents a stopiteration raised inside the with statement from being suppressed don t re raise the passed in exception issue27122 avoid suppressing if a stop async iteration exception was passed to athrow 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 actually stop async iteration see issue29692 only re raise if it s not the exception that was passed to throw because __exit__ must not raise an exception unless __exit__ itself failed but throw has to raise the exception to signal propagation so this fixes the impedance mismatch between the throw protocol and the __exit__ protocol contextmanager decorator typical usage contextmanager def some_generator arguments setup try yield value finally cleanup this makes this with some_generator arguments as variable body equivalent to this setup try variable value body finally cleanup 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 context to automatically close something at the end of a block code like this with closing module open arguments as f block is equivalent to this f module open arguments try block finally f close 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 we use a list of old targets to make this cm re entrant context manager for temporarily redirecting stdout to another file how to send help to stderr with redirect_stdout sys stderr help dir how to write help to a file with open help txt w as f with redirect_stdout f help pow context manager for temporarily redirecting stderr to another file context manager to suppress specified exceptions after the exception is suppressed execution proceeds with the next statement following the with statement with suppress filenotfounderror os remove somefile execution still resumes here if the file was already removed unlike isinstance and issubclass cpython exception handling currently only looks at the concrete type hierarchy ignoring the instance and subclass checking hooks while guido considers that a bug rather than a feature it s a fairly hard one to fix due to various internal implementation details suppress provides the simpler issubclass based semantics rather than trying to exactly reproduce the limitations of the cpython interpreter see http bugs python org issue12029 for more details a base class for exitstack and asyncexitstack preserve the context stack by transferring it to a new instance registers a callback with the standard __exit__ method signature can suppress exceptions the same way __exit__ method can also accepts any object with an __exit__ method registering a call to the method instead of the object itself we use an unbound method rather than a bound method to follow the standard lookup behaviour for special methods not a context manager so assume it s a callable allow use as a decorator enters the supplied context manager if successful also pushes its __exit__ method as a callback and returns the result of the __enter__ method we look up the special methods on the type to match the with statement registers an arbitrary callback and arguments cannot suppress exceptions we changed the signature so using wraps is not appropriate but setting __wrapped__ may still help with introspection allow use as a decorator helper to correctly register callbacks to __exit__ methods inspired by discussions on http bugs python org issue13585 context manager for dynamic management of a stack of exit callbacks for example with exitstack as stack files stack enter_context open fname for fname in filenames all opened files will automatically be closed at the end of the with statement even if attempts to open files later in the list raise an exception we manipulate the exception state so it behaves as though we were actually nesting multiple with statements context may not be correct so find the end of the chain context is already set correctly see issue 20317 change the end of the chain to point to the exception we expect it to reference callbacks are invoked in lifo order to match the behaviour of nested context managers simulate the stack of exceptions by setting the context bare raise exc replaces our carefully set up context immediately unwind the context stack inspired by discussions on https bugs python org issue29302 async context manager for dynamic management of a stack of exit callbacks for example async with asyncexitstack as stack connections await stack enter_async_context get_connection for i in range 5 all opened connections will automatically be released at the end of the async with statement even if attempts to open a connection later in the list raise an exception enters the supplied async context manager if successful also pushes its __aexit__ method as a callback and returns the result of the __aenter__ method registers a coroutine function with the standard __aexit__ method signature can suppress exceptions the same way __aexit__ method can also accepts any object with an __aexit__ method registering a call to the method instead of the object itself not an async context manager so assume it s a coroutine function allow use as a decorator registers an arbitrary coroutine function and arguments cannot suppress exceptions we changed the signature so using wraps is not appropriate but setting __wrapped__ may still help with introspection allow use as a decorator immediately unwind the context stack helper to correctly register coroutine function to __aexit__ method we manipulate the exception state so it behaves as though we were actually nesting multiple with statements context may not be correct so find the end of the chain context is already set correctly see issue 20317 change the end of the chain to point to the exception we expect it to reference callbacks are invoked in lifo order to match the behaviour of nested context managers simulate the stack of exceptions by setting the context bare raise exc replaces our carefully set up context context manager that does no additional processing used as a stand in for a normal context manager when a particular block of code is only sometimes used with a normal context manager cm optional_cm if condition else nullcontext with cm perform operation using optional_cm if condition is true non thread safe context manager to change the current working directory
import abc
import os
import sys
import _collections_abc
from collections import deque
from functools import wraps
from types import MethodType, GenericAlias

__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
           "AbstractContextManager", "AbstractAsyncContextManager",
           "AsyncExitStack", "ContextDecorator", "ExitStack",
           "redirect_stdout", "redirect_stderr", "suppress", "aclosing",
           "chdir"]


class AbstractContextManager(abc.ABC):

    

    __class_getitem__ = classmethod(GenericAlias)

    __slots__ = ()

    def __enter__(self):
        
        return self

    @abc.abstractmethod
    def __exit__(self, exc_type, exc_value, traceback):
        
        return None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is AbstractContextManager:
            return _collections_abc._check_methods(C, "__enter__", "__exit__")
        return NotImplemented


class AbstractAsyncContextManager(abc.ABC):

    

    __class_getitem__ = classmethod(GenericAlias)

    __slots__ = ()

    async def __aenter__(self):
        
        return self

    @abc.abstractmethod
    async def __aexit__(self, exc_type, exc_value, traceback):
        
        return None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is AbstractAsyncContextManager:
            return _collections_abc._check_methods(C, "__aenter__",
                                                   "__aexit__")
        return NotImplemented


class ContextDecorator(object):
    "A base class or mixin that enables context managers to work as decorators."

    def _recreate_cm(self):
        
        return self

    def __call__(self, func):
        @wraps(func)
        def inner(*args, **kwds):
            with self._recreate_cm():
                return func(*args, **kwds)
        return inner


class AsyncContextDecorator(object):
    "A base class or mixin that enables async context managers to work as decorators."

    def _recreate_cm(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:
    

    def __init__(self, func, args, kwds):
        self.gen = func(*args, **kwds)
        self.func, self.args, self.kwds = func, args, kwds
        
        doc = getattr(func, "__doc__", None)
        if doc is None:
            doc = type(self).__doc__
        self.__doc__ = doc
        
        
        
        
        

    def _recreate_cm(self):
        
        
        
        return self.__class__(self.func, self.args, self.kwds)


class _GeneratorContextManager(
    _GeneratorContextManagerBase,
    AbstractContextManager,
    ContextDecorator,
):
    

    def __enter__(self):
        
        
        del self.args, self.kwds, self.func
        try:
            return next(self.gen)
        except StopIteration:
            raise RuntimeError("generator didn't yield") from None

    def __exit__(self, typ, value, traceback):
        if typ is None:
            try:
                next(self.gen)
            except StopIteration:
                return False
            else:
                try:
                    raise RuntimeError("generator didn't stop")
                finally:
                    self.gen.close()
        else:
            if value is None:
                
                
                value = typ()
            try:
                self.gen.throw(value)
            except StopIteration as exc:
                
                
                
                return exc is not value
            except RuntimeError as exc:
                
                if exc is value:
                    exc.__traceback__ = traceback
                    return False
                
                
                
                
                
                
                if (
                    isinstance(value, StopIteration)
                    and exc.__cause__ is value
                ):
                    value.__traceback__ = traceback
                    return False
                raise
            except BaseException as exc:
                
                
                
                
                
                
                if exc is not value:
                    raise
                exc.__traceback__ = traceback
                return False
            try:
                raise RuntimeError("generator didn't stop after throw()")
            finally:
                self.gen.close()

class _AsyncGeneratorContextManager(
    _GeneratorContextManagerBase,
    AbstractAsyncContextManager,
    AsyncContextDecorator,
):
    

    async def __aenter__(self):
        
        
        del self.args, self.kwds, self.func
        try:
            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 anext(self.gen)
            except StopAsyncIteration:
                return False
            else:
                try:
                    raise RuntimeError("generator didn't stop")
                finally:
                    await self.gen.aclose()
        else:
            if value is None:
                
                
                value = typ()
            try:
                await self.gen.athrow(value)
            except StopAsyncIteration as exc:
                
                
                
                return exc is not value
            except RuntimeError as exc:
                
                if exc is value:
                    exc.__traceback__ = traceback
                    return False
                
                
                
                
                
                
                if (
                    isinstance(value, (StopIteration, StopAsyncIteration))
                    and exc.__cause__ is value
                ):
                    value.__traceback__ = traceback
                    return False
                raise
            except BaseException as exc:
                
                
                
                
                
                
                if exc is not value:
                    raise
                exc.__traceback__ = traceback
                return False
            try:
                raise RuntimeError("generator didn't stop after athrow()")
            finally:
                await self.gen.aclose()


def contextmanager(func):
    
    @wraps(func)
    def helper(*args, **kwds):
        return _GeneratorContextManager(func, args, kwds)
    return helper


def asynccontextmanager(func):
    
    @wraps(func)
    def helper(*args, **kwds):
        return _AsyncGeneratorContextManager(func, args, kwds)
    return helper


class closing(AbstractContextManager):
    
    def __init__(self, thing):
        self.thing = thing
    def __enter__(self):
        return self.thing
    def __exit__(self, *exc_info):
        self.thing.close()


class aclosing(AbstractAsyncContextManager):
    
    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

    def __init__(self, new_target):
        self._new_target = new_target
        
        self._old_targets = []

    def __enter__(self):
        self._old_targets.append(getattr(sys, self._stream))
        setattr(sys, self._stream, self._new_target)
        return self._new_target

    def __exit__(self, exctype, excinst, exctb):
        setattr(sys, self._stream, self._old_targets.pop())


class redirect_stdout(_RedirectStream):
    

    _stream = "stdout"


class redirect_stderr(_RedirectStream):
    

    _stream = "stderr"


class suppress(AbstractContextManager):
    

    def __init__(self, *exceptions):
        self._exceptions = exceptions

    def __enter__(self):
        pass

    def __exit__(self, exctype, excinst, exctb):
        
        
        
        
        
        
        
        
        
        if exctype is None:
            return
        if issubclass(exctype, self._exceptions):
            return True
        if issubclass(exctype, BaseExceptionGroup):
            match, rest = excinst.split(self._exceptions)
            if rest is None:
                return True
            raise rest
        return False


class _BaseExitStack:
    

    @staticmethod
    def _create_exit_wrapper(cm, cm_exit):
        return MethodType(cm_exit, cm)

    @staticmethod
    def _create_cb_wrapper(callback, /, *args, **kwds):
        def _exit_wrapper(exc_type, exc, tb):
            callback(*args, **kwds)
        return _exit_wrapper

    def __init__(self):
        self._exit_callbacks = deque()

    def pop_all(self):
        
        new_stack = type(self)()
        new_stack._exit_callbacks = self._exit_callbacks
        self._exit_callbacks = deque()
        return new_stack

    def push(self, exit):
        
        
        
        _cb_type = type(exit)

        try:
            exit_method = _cb_type.__exit__
        except AttributeError:
            
            self._push_exit_callback(exit)
        else:
            self._push_cm_exit(exit, exit_method)
        return exit  

    def enter_context(self, cm):
        
        
        
        cls = type(cm)
        try:
            _enter = cls.__enter__
            _exit = cls.__exit__
        except AttributeError:
            raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
                            f"not support the context manager protocol") from None
        result = _enter(cm)
        self._push_cm_exit(cm, _exit)
        return result

    def callback(self, callback, /, *args, **kwds):
        
        _exit_wrapper = self._create_cb_wrapper(callback, *args, **kwds)

        
        
        _exit_wrapper.__wrapped__ = callback
        self._push_exit_callback(_exit_wrapper)
        return callback  

    def _push_cm_exit(self, cm, cm_exit):
        
        _exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
        self._push_exit_callback(_exit_wrapper, True)

    def _push_exit_callback(self, callback, is_sync=True):
        self._exit_callbacks.append((is_sync, callback))



class ExitStack(_BaseExitStack, AbstractContextManager):
    

    def __enter__(self):
        return self

    def __exit__(self, *exc_details):
        exc = exc_details[1]
        received_exc = exc is not None

        
        
        frame_exc = sys.exception()
        def _fix_exception_context(new_exc, old_exc):
            
            while 1:
                exc_context = new_exc.__context__
                if exc_context is None or exc_context is old_exc:
                    
                    return
                if exc_context is frame_exc:
                    break
                new_exc = exc_context
            
            
            new_exc.__context__ = old_exc

        
        
        suppressed_exc = False
        pending_raise = False
        while self._exit_callbacks:
            is_sync, cb = self._exit_callbacks.pop()
            assert is_sync
            try:
                if exc is None:
                    exc_details = None, None, None
                else:
                    exc_details = type(exc), exc, exc.__traceback__
                if cb(*exc_details):
                    suppressed_exc = True
                    pending_raise = False
                    exc = None
            except BaseException as new_exc:
                
                _fix_exception_context(new_exc, exc)
                pending_raise = True
                exc = new_exc

        if pending_raise:
            try:
                
                
                fixed_ctx = exc.__context__
                raise exc
            except BaseException:
                exc.__context__ = fixed_ctx
                raise
        return received_exc and suppressed_exc

    def close(self):
        
        self.__exit__(None, None, None)



class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
    

    @staticmethod
    def _create_async_exit_wrapper(cm, cm_exit):
        return MethodType(cm_exit, cm)

    @staticmethod
    def _create_async_cb_wrapper(callback, /, *args, **kwds):
        async def _exit_wrapper(exc_type, exc, tb):
            await callback(*args, **kwds)
        return _exit_wrapper

    async def enter_async_context(self, cm):
        
        cls = type(cm)
        try:
            _enter = cls.__aenter__
            _exit = cls.__aexit__
        except AttributeError:
            raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
                            f"not support the asynchronous context manager protocol"
                           ) from None
        result = await _enter(cm)
        self._push_async_cm_exit(cm, _exit)
        return result

    def push_async_exit(self, exit):
        
        _cb_type = type(exit)
        try:
            exit_method = _cb_type.__aexit__
        except AttributeError:
            
            self._push_exit_callback(exit, False)
        else:
            self._push_async_cm_exit(exit, exit_method)
        return exit  

    def push_async_callback(self, callback, /, *args, **kwds):
        
        _exit_wrapper = self._create_async_cb_wrapper(callback, *args, **kwds)

        
        
        _exit_wrapper.__wrapped__ = callback
        self._push_exit_callback(_exit_wrapper, False)
        return callback  

    async def aclose(self):
        
        await self.__aexit__(None, None, None)

    def _push_async_cm_exit(self, cm, cm_exit):
        
        _exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit)
        self._push_exit_callback(_exit_wrapper, False)

    async def __aenter__(self):
        return self

    async def __aexit__(self, *exc_details):
        exc = exc_details[1]
        received_exc = exc is not None

        
        
        frame_exc = sys.exception()
        def _fix_exception_context(new_exc, old_exc):
            
            while 1:
                exc_context = new_exc.__context__
                if exc_context is None or exc_context is old_exc:
                    
                    return
                if exc_context is frame_exc:
                    break
                new_exc = exc_context
            
            
            new_exc.__context__ = old_exc

        
        
        suppressed_exc = False
        pending_raise = False
        while self._exit_callbacks:
            is_sync, cb = self._exit_callbacks.pop()
            try:
                if exc is None:
                    exc_details = None, None, None
                else:
                    exc_details = type(exc), exc, exc.__traceback__
                if is_sync:
                    cb_suppress = cb(*exc_details)
                else:
                    cb_suppress = await cb(*exc_details)

                if cb_suppress:
                    suppressed_exc = True
                    pending_raise = False
                    exc = None
            except BaseException as new_exc:
                
                _fix_exception_context(new_exc, exc)
                pending_raise = True
                exc = new_exc

        if pending_raise:
            try:
                
                
                fixed_ctx = exc.__context__
                raise exc
            except BaseException:
                exc.__context__ = fixed_ctx
                raise
        return received_exc and suppressed_exc


class nullcontext(AbstractContextManager, AbstractAsyncContextManager):
    

    def __init__(self, enter_result=None):
        self.enter_result = enter_result

    def __enter__(self):
        return self.enter_result

    def __exit__(self, *excinfo):
        pass

    async def __aenter__(self):
        return self.enter_result

    async def __aexit__(self, *excinfo):
        pass


class chdir(AbstractContextManager):
    

    def __init__(self, path):
        self.path = path
        self._old_cwd = []

    def __enter__(self):
        self._old_cwd.append(os.getcwd())
        os.chdir(self.path)

    def __exit__(self, *excinfo):
        os.chdir(self._old_cwd.pop())