lagom
lagom copied to clipboard
ContextManager doesn't work with async, or maybe ExplicitContainer?
Trying to use the context container to create a "transaction" for the whole "request". Here is some code to give an example:
import asyncio
import dataclasses
from collections.abc import AsyncIterator
from typing import Any
import lagom
class Transaction:
async def __aenter__(self) -> "Transaction":
return self
async def commit(self) -> None:
return
async def rollback(self) -> None:
return
async def close(self) -> None:
return
async def __aexit__(self, exc_type: type[BaseException] | None, *args: Any, **kwargs: Any) -> None:
if exc_type is None:
# Auto commit if there was no exception
await self.commit()
else:
# Auto rollback is there was an exception
await self.rollback()
return None
@dataclasses.dataclass
class UserModel:
user_id: int
class UserRepository:
def __init__(self, transaction: Transaction) -> None:
self._transaction = transaction
async def find_user(self, user_id: int) -> UserModel:
user = None
async with self._transaction as t:
# do some db stuff here, maybe create the user if it doesn't exist or something...
user = UserModel(user_id=user_id)
return user
class FindUserUseCase:
def __init__(self, user_repo: UserRepository) -> None:
self._user_repo = user_repo
async def execute(self, user_id: int) -> UserModel:
return await self._user_repo.find_user(user_id=user_id)
container = lagom.ExplicitContainer()
@lagom.context_dependency_definition(container) # type: ignore[misc]
async def _get_a_transaction() -> AsyncIterator[Transaction]:
transaction = Transaction()
try:
yield transaction
finally:
await transaction.close()
container[UserRepository] = lambda c: UserRepository(c[Transaction])
container[FindUserUseCase] = lambda c: FindUserUseCase(c[UserRepository])
context_container = lagom.ContextContainer(container=container, context_types=[], context_singletons=[Transaction])
@lagom.bind_to_container(context_container)
async def find_user(user_id: int, find_user_use_case: FindUserUseCase = lagom.injectable) -> None:
user = await find_user_use_case.execute(user_id=user_id)
print(user)
if __name__ == "__main__":
asyncio.run(find_user(1))
When I run this I get:
lagom.exceptions.InvalidDependencyDefinition: A ContextManager[<class '__main__.Transaction'>] should be defined. This could be an Iterator[<class '__main__.Transaction'>] or Generator[<class '__main__.Transaction'>, None, None] with the @contextmanager decorator
Am I doing something wrong? If so, what?