Resource Management
A resource is any dependency that requires cleanup, such as database connections, file handles, or network clients. Use generator factories to manage their lifecycle.
Generator Factories¶
Generator factories use Python's yield statement to manage resource lifecycle:
- Setup: Code before
yieldruns when the dependency is created. - Use: The yielded value is injected into consumers.
- Teardown: Code after
yieldruns when the scope closes.
from typing import Iterator
from wireup import injectable
@injectable
def db_session_factory() -> Iterator[Session]:
db = Session()
try:
yield db
finally:
db.close()
import contextlib
from typing import Iterator
from wireup import injectable
@injectable
def db_session_factory() -> Iterator[Session]:
with contextlib.closing(Session()) as db:
yield db
from typing import AsyncIterator
from aiohttp import ClientSession
from wireup import injectable
@injectable
async def client_session_factory() -> AsyncIterator[ClientSession]:
async with ClientSession() as sess:
yield sess
Generator Factories
Generator factories must yield exactly once. Yielding multiple times will result in cleanup not being performed.
When cleanup runs depends on the lifetime. See Cleanup Timing for details.
Error Handling¶
When using generator factories with scoped or transient lifetimes, unhandled errors that occur within the scope are automatically propagated to the factories. This enables conditional cleanup, such as rolling back uncommitted database changes when operations fail.
from typing import Iterator
from sqlalchemy import Engine
from sqlalchemy.orm import Session
from wireup import injectable
@injectable(lifetime="scoped")
def db_session_factory(engine: Engine) -> Iterator[Session]:
session = Session(engine)
try:
yield session
except Exception:
# Error occurred - rollback any uncommitted changes
session.rollback()
raise
finally:
# Always close the session
session.close()
Suppressing Errors
Factories cannot suppress exceptions, they can perform cleanup, but the original error will always propagate. This ensures cleanup code doesn't accidentally change your program's control flow.