A simple asyncio context manager with explicit interface.
This library provides a simple context manager for managing resources in an asyncio environment. It's designed to have an explicit interface, which makes it easy to use both as context manager and as a regular object for custom use cases.
You can install or upgrade aiorem
via
$ pip install aiorem --upgrade
When working with asyncio
Python libraries, async context managers are a common pattern for managing resources and snippets like
async with some_lib.Client() as client:
...
are often seen in the quickstart. However, there are two use cases, where this pattern is hard to use and an explicit interface for acquiring and releasing resources is desirable.
- Nested context managers: When writing a class that manages several resources, acquiring and releasing these resources should each usually be bundled in a single method.
- Low level event loop usage: In some advanced cases, it can be desirable to use things like
loop.run_until_complete
thanawait
-ing a coroutine.
For both cases, one can then either explicitly call Client.__aenter__
and Client.__aexit__
or duplicate whatever logic is used within these methods.
Unfortunately, the behavior of Client.__aenter__
and Client.__aexit__
is not always well documented.
Moreover, using magic/dunder might be viewed as bad practice, as they are mostly intended to be used by the Python interpreter.
This shortcoming is what aiorem
aims to improve.
As the Quick Start below shows, subclasses of aiorem.AbstractResourceManager
can be used in different ways according to the needs of the use case while the behavior is well documented and explicit.
For the case of nested context managers, aiorem
provides the AbstractResourceManagerCollection class as a natural extension of AbstractResourceManager.
Here is a simple example of how to use aiorem
:
import asyncio
from aiorem import AbstractResourceManager
class ResourceManager(AbstractResourceManager):
async def acquire_resources(self):
print("Resource acquired")
async def release_resources(self):
print("Resource released")
async def context_manager():
async with ResourceManager():
print("Context manager block")
@ResourceManager()
async def decorator():
print("Decorator block")
async def explicit_interface():
rm = ResourceManager()
await rm.acquire_resources()
print("Explicit interface block")
await rm.release_resources()
async def main():
await context_manager()
await decorator()
await explicit_interface()
if __name__ == "__main__":
asyncio.run(main())
For more information on how to use aiorem
, please refer to the documentation.