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.Added in version 1.1.0.
- class ContextDecorator[source]¶
Base class to turn an async context manager into a decorator as well
Inheriting from this class adds the scaffolding to automatically enter an async context manager on awaiting any callable decorated with it:
class DecoratorAndContext(ContextDecorator): async def __aenter__(self) -> Any: print("entering", self) async def __aexit__(self, *exc): print("exiting", self) @DecoratorAndContext() async def func(): print("running some function...")
The context manager can still be used regularly in async with statements.
Since functions are decorated with an existing context manager instance, the same instance is entered and exited on every call. If the context is not safe to be entered multiple times or even concurrently it should implement the method
_recreate_cm(:Self) -> Self
to create a copy of itself.
- 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. Ifyield
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 (viaathrow()
). In order to handle this exception, theyield
should be wrapped in atry
statement.The created context manager is a
ContextDecorator
and can also be used as a decorator. It is automatically entered when a decorated function isawait
ed.Added in version 3.12.2: The created context manager is a
ContextDecorator
.
- async with closing(thing: AC) as :AC¶
Create an asynchronous context manager to
aclose
something
on exitOnce 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 defaultnullcontext
, or to prevent closing of an existing context manager in anasync 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()
andcallback()
. This allows running additional cleanup, similar todefer
statements in other languages.Note
Unlike
contextlib.AsyncExitStack
, this class provides an async neutral version of thecontextlib.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 anasync with
statement; ifcm
can only be used in awith
statement, it is silently promoted. The stack will entercm
and, if successful, ensure thatcm
is exited when the stack unwinds. The return value of this method is the value thatcm
provides in anasync 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 theasync 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 decorator.
- 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 theobject.__aexit__()
signature.Regardless of internal normalizations,
exit
is always returned unchanged. This allows usingpush
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, useenter_context()
instead.
- pop_all() 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 originalExitStack
(viaaclose()
or anasync with
statement) invokes these callbacks. Note that callbacks added after callingpop_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 isasync
and follows theaclose
naming convention.
Added in version 1.1.0.