The contextlib library

The asyncstdlib.contextlib library implements Python’s contextlib for (async) iterables and (async) context managers.

Context Managers

class AbstractContextManager

An abstract base class for asynchronous context managers

This class can be used to check whether some object is an asynchronous context manager. If a class may inherit from AbstractContextManager, in which case it must implement an __aenter__ method; the default __aenter__ returns the asynchronous context manager itself.

New in version 1.1.0.

async with contextmanager(func: (...) async iter T) (...) as :T[source]
@contextmanager(func: (...) async iter T) (...) async with T[source]

Create an asynchronous context manager out of an asynchronous generator function

This is intended as a decorator for an asynchronous generator function. The asynchronous generator should yield once, at which point the body of the context manager executes. If yield provides a value, this becomes the value of the context in the block.

@contextmanager
async def Context(*args, **kwargs):
    # __aenter__
    yield  # context value
    # __aexit__

Note that if an exception ends the context block, it gets re-raised at the yield inside the asynchronous generator (via athrow()). In order to handle this exception, the yield should be wrapped in a try statement.

async with closing(thing: AC) as :AC

Create an asynchronous context manager to aclose some thing on exit

Once entered, the context manager guarantees to await thing.aclose() at the end of its block. This is useful for safe cleanup even if errors occur.

Use closing for objects that need reliable cleanup but do not support the context manager protocol. For example, it is advisable to prompty clean up any asynchronous iterator that holds resources:

import asyncstdlib as a

async with a.closing(a.iter(something)) as async_iter:
    async for element in async_iter:
        ...

See also

Use scoped_iter() to ensure an (async) iterable is eventually closed and only borrowed until then.

async with nullcontext(enter_result: T) as :T

Create an asynchronous context manager that only returns enter_result

Intended as a neutral element, a nullcontext serves as a placeholder where an async context manager is semantically required but not meaningfull. This allows for an optional async context manager with a default nullcontext, or to prevent closing of an existing context manager in an async with statement.

async def safe_fetch(source):
    if not isinstance(source, AsyncIterator):
        # use a context manager if required ...
        acm = a.closing(iter(source))
    else:
        # ... or a neutral placeholder
        acm = a.nullcontext(source)
    async with acm as async_iter:
        ...
class ExitStack[source]

Context Manager emulating several nested Context Managers

Once an ExitStack is entered, enter_context() can be used to emulate entering further context managers. When unwinding the stack, context managers are exited in LIFO order, effectively emulating nested context managers. The primary use-case is programmatically entering optional or a dynamically sized number of context managers.

In addition, arbitrary cleanup functions and callbacks can be registered using push() and callback(). This allows running additional cleanup, similar to defer statements in other languages.

Note

Unlike contextlib.AsyncExitStack, this class provides an async neutral version of the contextlib.ExitStack. There are no separate methods to distinguish async and regular arguments.

await enter_context(cm: (async) with T) T[source]

Enter the supplied context manager, and register it for exit if successful

This method is equivalent to using cm in an async with statement; if cm can only be used in a with statement, it is silently promoted. The stack will enter cm and, if successful, ensure that cm is exited when the stack unwinds. The return value of this method is the value that cm provides in an async with statement.

# explicitly enter context managers
async with cm_a as value_a, cm_b as value_b:
    ...

# programmatically enter context managers
async with a.ExitStack() as exit_stack:
    value_a = exit_stack.enter_context(cm_a)
    value_b = exit_stack.enter_context(cm_b)
    ...

When unwinding, the context manager is exited as if it were part of a regular stack of async with (that is, in LIFO order). It receives the current exception details and may suppress it as usual. As with the async with statement, if the context cannot be entered (that is, await cm.__aenter__() throws an exception) it is not exited either.

callback(callback: T as (*args, **kwargs) -> None, *args, **kwargs) T[source]

Registers an arbitrary callback to be called with arguments on unwinding

Returns

the callback parameter, unchanged

The callback is invoked as await callback(*args, **kwargs) when the stack unwinds. It does not receive the current exception details and cannot suppress the exception handled by the stack. The callback is treated as async neutral, i.e. it may be a synchronous function.

This method does not change its argument, and can be used as a context manager.

push(exit: T as {.__aexit__}) T[source]
push(exit: T as {.__exit__}) T[source]
push(exit: T as (Type[BaseException], BaseException, traceback) -> (await) bool) T[source]

Registers a callback with the standard __aexit__ method signature

Parameters

exit – the exit callback to invoke on __aexit__

Returns

the exit parameter, unchanged

When the stack is unwound, callbacks receive the current exception details, and are expected to return True if the exception should be suppressed. Two normalizations are applied to match the __aexit__ signature:

  • If exit has an __aexit__ method, this method is used instead.

  • If exit has an __exit__ method, this method is used instead. It is automatically treated as asynchronous.

  • If exit is not asynchronous, it is automatically treated as such.

Note that exit is only treated as async neutral when it does not have an __aexit__ method. If an __aexit__ method is found, it is expected to conform to the object.__aexit__() signature.

Regardless of internal normalizations, exit is always returned unchanged. This allows using push as a decorator.

See also

When receiving a context manager, this method only sets up __aexit__ or __exit__ for being called. It does not enter the context manager. If a context manager must also be entered, use enter_context() instead.

pop_all() asyncstdlib.contextlib.ExitStack[source]

Transfer all exit callbacks to a new ExitStack

Returns

new ExitStack owning all previously registered callbacks

The responsibility of invoking previously registered handlers is fully transferred to the new ExitStack. Neither calling this method, nor closing the original ExitStack (via aclose() or an async with statement) invokes these callbacks. Note that callbacks added after calling pop_all() are not affected by this.

await aclose() None[source]

Immediately unwind the context stack

Note

Unlike the regular contextlib.ExitStack.close() method, this method is async and follows the aclose naming convention.

New in version 1.1.0.