async-exit-stack

raw JSON →
1.0.1 verified Mon Apr 27 auth: no python maintenance

A backport of AsyncExitStack from Python 3.7+ for use on Python 3.5 and 3.6. It provides an async context manager that can combine multiple async context managers and cleanup callbacks. Current version 1.0.1, release cadence is low (last release in 2018).

pip install async-exit-stack
error ModuleNotFoundError: No module named 'async_exit_stack'
cause Package not installed or wrong import name (confused with hyphen name).
fix
Run pip install async-exit-stack and then use from async_exit_stack import AsyncExitStack.
error AttributeError: module 'async_exit_stack' has no attribute 'AsyncExitStack'
cause Imported the module but did not import the class correctly, e.g., `import async_exit_stack` then `async_exit_stack.AsyncExitStack` when the class is not in the module's top-level? Actually it is. More likely: installed a different package or shadowed by a local file.
fix
Ensure you have the correct package installed and no local file named async_exit_stack.py. Uninstall and reinstall: pip uninstall async-exit-stack and pip install async-exit-stack.
error TypeError: object AsyncExitStack can't be used in 'await' expression
cause Trying to await AsyncExitStack() directly. AsyncExitStack is an async context manager, not a coroutine.
fix
Use async with AsyncExitStack() as stack: not await AsyncExitStack().
deprecated This library is a backport for Python <3.7. Python 3.5 and 3.6 are end-of-life. Use Python 3.7+'s built-in contextlib.AsyncExitStack instead.
fix Upgrade to Python 3.7+ and use `from contextlib import AsyncExitStack`. Remove dependency on async-exit-stack.
gotcha The package is named `async-exit-stack` on PyPI, but the import module is `async_exit_stack` (underscore). Confusing these leads to ImportError.
fix Import as `from async_exit_stack import AsyncExitStack`.
gotcha AsyncExitStack.enter_context (sync) is not available; use enter_async_context. Attempting to use enter_context will raise AttributeError.
fix Use `await stack.enter_async_context(cm)` instead of `stack.enter_context(cm)`.

Minimal example using AsyncExitStack to enter an async context manager and push a callback.

import asyncio
from async_exit_stack import AsyncExitStack

async def main():
    async with AsyncExitStack() as stack:
        # enter an async context manager
        result = await stack.enter_async_context(some_async_context())
        # push a callback
        stack.push_async_callback(lambda: asyncio.sleep(0))
        print('Inside stack')
    print('Exited stack')

async def some_async_context():
    class FakeAsyncCM:
        async def __aenter__(self):
            return self
        async def __aexit__(self, *args):
            pass
    return FakeAsyncCM()

asyncio.run(main())