Closed zerlok closed 1 week ago
I think this is a good idea, but here you are suggesting that providers.Resource
accepts a Callable[P, AsyncContextManager[T]]
, why not just AsyncContextManager[T]
directly?
I agree with @alexanderlazarev0 , accepting context managers directly seems better.
@zerlok you are welcome to try, thank you for the proposal
@lesnik512 , @alexanderlazarev0 , if resource can accept Callable[P, AsyncContextManager[T]]
, then client can use async factory methods, without extra code.
For example:
class MySender:
@asynccontextmanager
@classmethod
async def create(cls, conn: AMQPConnection) -> typing.AsyncIterator[MyPublisher]:
exchange = await conn.declare_exchange(...)
try:
yield cls(exchange)
finally:
await conn.delete_exchange(exchange)
def __init__(self, exchange: AMQPExchange) -> None:
self.__exchange = exchange
async def send(self, msg: bytes) -> None:
await self.__exchange.publish_message(msg)
class Container(BaseContainer):
conn = providers.Resource(_connect_amqp)
my_publisher = providers.Resource(MySender.create, conn=conn.cast)
For now it has to be done with extra code:
async def _init_my_sender(conn: AMQPConnection) -> AsyncIterator[MySender]:
async with MySender.create(conn) as my_sender:
yield my_sender
class Container(BaseContainer):
conn = providers.Resource(_connect_amqp)
my_publisher = providers.Resource(_init_my_sender, conn=conn.cast)
I think the best solution is to support both types: simple async context manager & callable that returns async context manager.
I think, that we don't need to accept iterators wrapped in contextmanager and asynccontextmanager decorators. Only inherited from ContextManager and AsyncContextManager.
Making some experiments now. Will make PR to show.
@lesnik512 I don't believe this functionality was necessary in the first place, since the above example would work by simply not wrapping the create
method with a asyncontextmanager
. From what I can understand @zerlok just wanted to use methods that were wrapped as providers, not sure if making one implement ContextManager
or AsyncContextManager
help...
@alexanderlazarev0 I agree about wrapped context managers. But about inherited context managers, I think it can be useful. So I'm not planning to release it yet before making some changes and discussing them through PR
@lesnik512 Yes I agree it can be useful, was just mentioning that it might not resolve this issue :)
@alexanderlazarev0 A little off topic, I'm writing some alternative version for alternative universe) https://github.com/modern-python/modern-di
And there I wrote resource which accepts context manager classes https://github.com/modern-python/modern-di/commit/4582b5c9c8990a111e381ee3fd352188a95a8cb4
Resource
provider expects callable object that returns eitherIterable
orAsyncIterable
that yields only one element (the result value for provider attribute in DI container).I think it would be great to support python context managers too.
P.S. I'm ready to make a PR