-
-
Notifications
You must be signed in to change notification settings - Fork 326
Feature request: allow specification of types of DependencyContainer() providers #357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hey @shaunc, next works with current codebase: from dependency_injector import containers, providers
from container_utils import resolve_part
class C1(containers.DeclarativeContainer):
foo1 = providers.Dependency(instance_of=str)
foo2 = providers.Dependency(instance_of=str)
class C2(containers.DeclarativeContainer):
c1 = providers.DependenciesContainer(**C1.providers)
class C3(containers.DeclarativeContainer):
c2 = providers.DependenciesContainer(**C2.providers)
foo1 = resolve_part(resolve_part(c2, "c1"), "foo1")
foo2 = resolve_part(resolve_part(c2, "c1"), "foo2")
if __name__ == '__main__':
c3 = C3(c2=C2(c1=C1(foo1="hello", foo2="world")))
print(c3.foo1(), c3.foo2()) # prints "hello world" Also there is a version without from dependency_injector import containers, providers
class C1(containers.DeclarativeContainer):
foo1 = providers.Dependency(instance_of=str)
foo2 = providers.Dependency(instance_of=str)
class C2(containers.DeclarativeContainer):
c1 = providers.DependenciesContainer(**C1.providers)
class C3(containers.DeclarativeContainer):
c2 = providers.DependenciesContainer(**C2.providers)
foo1 = c2.c1.foo1
foo2 = c2.c1.foo2
if __name__ == '__main__':
c3 = C3(c2=C2(c1=C1(foo1="hello", foo2="world")))
print(c3.foo1(), c3.foo2()) # prints "hello world" |
Example with from dependency_injector import containers, providers
class C1(containers.DeclarativeContainer):
foo1 = providers.Dependency(instance_of=str)
foo2 = providers.Dependency(instance_of=str)
class C2(containers.DeclarativeContainer):
c1 = providers.DependenciesContainer(**C1.providers)
class C3(containers.DeclarativeContainer):
c2 = providers.DependenciesContainer(**C2.providers)
foo1 = c2.c1.foo1
foo2 = c2.c1.foo2
@containers.copy(C3)
class C4(C3):
selected_c1 = providers.DependenciesContainer(foo1="hello", foo2="world")
c2 = providers.DependenciesContainer(**C2.providers)
c2.override(C2(c1=selected_c1))
if __name__ == '__main__':
c4 = C4()
print(c4.foo1(), c4.foo2()) # prints "hello world" |
I guess the only missing part here is that @property
def dependencies(cls):
"""Return container dependency providers dictionary.
Dependency providers could be both of :py:class:`dependency_injector.providers.Dependency` and
:py:class:`dependency_injector.providers.DependenciesContainer`.
:rtype:
dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return {
name: provider
for name, provider in cls.providers.items()
if isinstance(provider, (Dependency, DependenciesContainer))
} In that case the code will look like: from dependency_injector import containers, providers
class C1(containers.DeclarativeContainer):
foo1 = providers.Dependency(instance_of=str)
foo2 = providers.Dependency(instance_of=str)
class C2(containers.DeclarativeContainer):
c1 = providers.DependenciesContainer(**C1.dependencies)
class C3(containers.DeclarativeContainer):
c2 = providers.DependenciesContainer(**C2.dependencies)
foo1 = c2.c1.foo1
foo2 = c2.c1.foo2
if __name__ == '__main__':
c3 = C3(c2=C2(c1=C1(foo1="hello", foo2="world")))
print(c3.foo1(), c3.foo2()) # prints "hello world" What do you think? |
Looks great -- but where is @dependencies
class C1( ... ):
...
@dependencies
class C2( ... ):
... ? |
Ok, cool. Working on it. |
I've released version |
This example now works with from dependency_injector import containers, providers
class C1(containers.DeclarativeContainer):
foo1 = providers.Dependency(instance_of=str)
foo2 = providers.Dependency(instance_of=str)
class C2(containers.DeclarativeContainer):
c1 = providers.DependenciesContainer(**C1.dependencies)
class C3(containers.DeclarativeContainer):
c2 = providers.DependenciesContainer(**C2.dependencies)
foo1 = c2.c1.foo1
foo2 = c2.c1.foo2
if __name__ == '__main__':
c3 = C3(c2=C2(c1=C1(foo1="hello", foo2="world")))
print(c3.foo1(), c3.foo2()) # prints "hello world" |
Great! Thanks so much. Yes -- I think it will help with the other issues as well. (Will have to unwind my workarounds -- will try later today.) |
Ok, sounds good. Waiting for your feedback from the field. |
Everything good on this one -- Thanks! |
Good. Thanks for the update. |
Containers have two types of parameters - dependencies, and dependency containers, which are collections of dependencies, satisfied with a container. They both can be instantiated in two ways: either on container creation (or afterwards with
override_providers
), or when a derived Container class overrides a dependency or dependency container.In the latter case, currently at least, a DependenciesContainer has to be provided with explicit dependencies so that other providers binding to them have placeholders for their eventual targets:
For complex DependenciesContainers, this can be onerous, especially if the dependencies themselves container dependencies containers.
I suggest allowing a DependenciesContainer to take as an argument a Container, which specifies the base type of Container that will instantiate the DependenciesContainer:
Below is a snippet that constructs placeholders appropriate for a given incoming container (or even another dependencies container):
It doesn't check the type of a passed in container on instantiation -- that is nice to have, but not as essential for me.
It can be used so:
Also, this should work (or something similar):
The text was updated successfully, but these errors were encountered: