Open ecs-jnguyen opened 3 years ago
Hi @ecs-jnguyen ,
Yes, Resource
provider supports generators but not support context managers: https://python-dependency-injector.ets-labs.org/providers/resource.html#generator-initializer
Generator-based initializer is a 2 phase generator. First phase is responsible for resource initialization and should yield resource object. Second phase is responsible for resource shutdown.
Do you look for the support of context managers?
@rmk135
ah i see the difference is between generators and context managers.
From my understanding the Resource
provider is used to initialize the resource with the init_resources()
method and clean up resources with the shutdown_resources()
method.
Generators can return multiple values i.e. have multiple yield
statements in a method. Would it be better for the Resource
provider to make use of the with
keyword i.e. things with __enter__
and __exit__
instead?
Generators can return multiple values i.e. have multiple yield statements in a method.
That's true. Generators can return multiple values or be infinite. Dependency Injector uses 2-phase generators as I described before:
This design solution mimics @contextlib.contextmanager
decorator and pytest yield fixtures and I don't see a problem with it.
Also this is a part of API and I could not remove it cause it will break other's people code.
I could add context manager interface support to the Resource
provider. In that case it will support all objects with __enter__
and __exit__
, @contextlib.contextmanager
decorated generators, async context managers etc.
What's a practical use case how you faced this issue?
@rmk135
True you would be breaking existing code if you change the behavior. It would be best not to do that.
I'm trying to see how to use the Resource
provider properly with a context manager. If I wanted to use a class that has an __enter__
and __exit__
method, would I have to create a wrapper method like below?
class DataBaseConnector:
def __init__():
# initialize db connection
self.connection = None
def __enter__():
return self
def __exit__():
# clean up resources
self.connection.close()
def db_connector_wrapper():
db_connector = DataBaseConnector()
yield db_connector
db_connector.__exit__()
def db_connector_wrapper_alternative():
with DataBaseConnector() as db_connector:
yield db_connector
Yeah, Resource
provider doesn't support context manager interface so you need a wrapper.
I'll add a backlog item to implement context manager interface support.
As a temp alternative you might want to take a look at this subclassing solution:
from dependency_injector import resources
class MyResource(resources.Resource):
def init(self, argument1=..., argument2=...) -> SomeResource:
return SomeResource()
def shutdown(self, resource: SomeResource) -> None:
# shutdown
...
class Container(containers.DeclarativeContainer):
resource = providers.Resource(
MyResource,
argument1=...,
argument2=...,
)
Docs: https://python-dependency-injector.ets-labs.org/providers/resource.html#subclass-initializer
Was this feature added?
4.41 asynccontextmanager donw work
I noticed that using
provider.Resource()
withcontainer.init_resources()
andcontainer.shutdown_resources()
does not call the__enter__
and/or__exit__
methods for a class or the@contextlib.contextmanager
. For initializing and shutting down resources I had to make a wrapper method without@contextlib.contextmanager
in order to call the__enter__
and__exit__
methods. Is this intended?