python-dependency-injector
python-dependency-injector copied to clipboard
Ability to use provider method/property in Singleton or Callable Provider
Hi, probably a simple question, but I can not find a straight answer anywhere on it:
- Is there a way to use a method of one provider in another if another provider is a Singletone or Callable provider?
So I want to do something like this (and in an ideal way to have proper typings for mypy check):
factory= providers.Factory(Factory)
service= providers.Callable(factory.create_service)
I already know that it will work with:
factory= providers.Factory(Factory)
service= providers.Callable(factory().create_service)
However, I would like to make it clean and postpone factory instantiation up to the moment when service will be required
I have seen this page about "Injecting provided object attributes" :
https://python-dependency-injector.ets-labs.org/providers/provided_instance.html
And it looks like a perfect solution for me, but this code doesn't work:
factory= providers.Factory(Factory)
service= providers.Callable(factory.provided.create_service)
Maybe because 'provided' works only when it is used as a dependency for another Provider
So, yeah, would be happy for any suggestions
Do you have a minimal working example that shows your issue?
For sure:
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Service:
def hello(self):
print("Hello World")
class ServiceFactory:
def create_service(self):
return Service()
class Container(containers.DeclarativeContainer):
service_factory = providers.Factory(ServiceFactory)
# service = providers.Callable(service_factory.provides.create_service) # doesn't work
# service = providers.Callable(service_factory.provider.create_service) # doesn't work
# service = providers.Callable(service_factory.provided.create_service) # doesn't work
service = providers.Callable(service_factory().create_service) # works, but requires to instantiate factory during this registration
@inject
def main(service: Service = Provide[Container.service]) -> None:
service.hello()
container = Container()
container.wire(modules=[__name__])
main()
Using provided instead of provides and calling service where its injected works for me:
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Service:
def hello(self):
print("Hello World")
class ServiceFactory:
def create_service(self):
return Service()
class Container(containers.DeclarativeContainer):
service_factory = providers.Factory(ServiceFactory)
service = providers.Callable(service_factory.provided.create_service)
@inject
def main(service: providers.Container[Service] = Provide[Container.service]) -> None:
service().hello()
container = Container()
container.wire(modules=[__name__])
main()
Interesting but is there any way to inject service as it is and not call:
service().hello()
but
service.hello()
is there any way to inject service as it is and not call
Not from my experience but I might be mistaken.
@rustam-ashurov-mcx Probably late but shouldn't you have used .call()?
Does that work the way you wanted?
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Service:
def hello(self):
print("Hello World")
class ServiceFactory:
def create_service(self):
return Service()
class Container(containers.DeclarativeContainer):
service_factory = providers.Factory(ServiceFactory)
service = providers.Callable(
service_factory.provided.create_service.call()
)
@inject
def main(service: Service = Provide[Container.service]) -> None:
service.hello()
container = Container()
container.wire(modules=[__name__])
main()
@rustam-ashurov-mcx Probably late but shouldn't you have used
.call()?Does that work the way you wanted?
from dependency_injector import containers, providers from dependency_injector.wiring import Provide, inject class Service: def hello(self): print("Hello World") class ServiceFactory: def create_service(self): return Service() class Container(containers.DeclarativeContainer): service_factory = providers.Factory(ServiceFactory) service = providers.Callable( service_factory.provided.create_service.call() ) @inject def main(service: Service = Provide[Container.service]) -> None: service.hello() container = Container() container.wire(modules=[__name__]) main()
really appreciate this response, having it I was able to find a page with documentation, and yes, it's exactly what I was looking for, many thanks : )