Context manager dependencies
Dependencies can use
@contextlib.contextmanager
and @contextlib.asynccontextmanager
decorators to execute code during their init and shutdown.
Implementation
Internally aioinject uses contextlib.ExitStack and contextlib.AsyncExitStack
Providers
Scoped and Transient providers
For Scoped
and Transient
providers dependencies will close when context is
closed:
import contextlib
from collections.abc import Iterator
import aioinject
from aioinject import Scoped
@contextlib.contextmanager
def dependency() -> Iterator[int]:
print("Startup")
yield 42
print("Shutdown")
container = aioinject.Container()
container.register(Scoped(dependency))
with container.sync_context() as ctx:
print(ctx.resolve(int)) # Startup, 42
# Shutdown
Singleton provider
In case of a Singleton
they're closed when you close container itself:
import contextlib
from collections.abc import Iterator
import aioinject
from aioinject import Singleton
@contextlib.contextmanager
def dependency() -> Iterator[int]:
print("Startup")
yield 42
print("Shutdown")
container = aioinject.Container()
container.register(Singleton(dependency))
with container:
with container.sync_context() as ctx:
print(ctx.resolve(int)) # Startup, 42
print("Context is closed")
# Shutdown
Using your own or 3rd party class as a context manager
Even if your class has __enter__
and __exit__
methods it won't implicitly be
used as a context manager:
from types import TracebackType
from typing_extensions import Self
import aioinject
from aioinject import Scoped
class Class:
def __enter__(self) -> Self:
print("Startup")
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
print("Shutdown")
container = aioinject.Container()
container.register(Scoped(Class))
with container.sync_context() as ctx:
print(ctx.resolve(Class)) # <__main__.Class object at ...>