python-dependency-injector icon indicating copy to clipboard operation
python-dependency-injector copied to clipboard

Provide, providers.Dependency() and order of containers.

Open kkjot88 opened this issue 2 years ago • 0 comments
trafficstars

This works:

class Foo:
    def __init__(self, bar):
        self.bar = bar


class SubContainer(containers.DeclarativeContainer):
    wiring_config = containers.WiringConfiguration(
        modules=[__name__], packages=[]
    )
    bar = providers.Dependency(instance_of=str)

    foo = providers.Factory(Foo, bar=bar)


class MainContainer(containers.DeclarativeContainer):
    wiring_config = containers.WiringConfiguration(
        modules=[__name__], packages=[]
    )
    sub_container = providers.Container(SubContainer, bar="BAR")
    foo = sub_container.foo


foo: Foo = Provide["foo"]

container = MainContainer()
container.check_dependencies()

but this doesn't:

class Foo:
    def __init__(self, bar):
        self.bar = bar


class SubContainer(containers.DeclarativeContainer):
    wiring_config = containers.WiringConfiguration(
        modules=[__name__], packages=[]
    )
    bar = providers.Dependency(instance_of=str)

    foo = providers.Factory(Foo, bar=bar)


foo: Foo = Provide["foo"]


class MainContainer(containers.DeclarativeContainer):
    wiring_config = containers.WiringConfiguration(
        modules=[__name__], packages=[]
    )
    sub_container = providers.Container(SubContainer, bar="BAR")  # runs into issues while trying to process this line
    foo = sub_container.foo


container = MainContainer()
container.check_dependencies()

pycharm traceback:

File "./main.py", line 41, in <module>
class MainContainer(containers.DeclarativeContainer):
File "./main.py", line 45, in MainContainer
sub_container = providers.Container(SubContainer, bar="BAR")
File "src/dependency_injector/providers.pyx", line 3905, in dependency_injector.providers.Container.__init__
File "src/dependency_injector/containers.pyx", line 748, in dependency_injector.containers.DeclarativeContainer.__new__
File "src/dependency_injector/containers.pyx", line 317, in dependency_injector.containers.DynamicContainer.wire
File "./venv/lib/python3.10/site-packages/dependency_injector/wiring.py", line 348, in wire
_patch_attribute(module, member_name, member, providers_map)
File "./venv/lib/python3.10/site-packages/dependency_injector/wiring.py", line 482, in _patch_attribute
instance = provider()
File "src/dependency_injector/providers.pyx", line 224, in dependency_injector.providers.Provider.__call__
File "src/dependency_injector/providers.pyx", line 2594, in dependency_injector.providers.Factory._provide
File "src/dependency_injector/providers.pxd", line 649, in dependency_injector.providers.__factory_call
File "src/dependency_injector/providers.pxd", line 576, in dependency_injector.providers.__call
File "src/dependency_injector/providers.pxd", line 444, in dependency_injector.providers.__provide_keyword_args
File "src/dependency_injector/providers.pxd", line 364, in dependency_injector.providers.__get_value
File "src/dependency_injector/providers.pyx", line 814, in dependency_injector.providers.Dependency.__call__
File "src/dependency_injector/providers.pyx", line 958, in dependency_injector.providers.Dependency._raise_undefined_error
dependency_injector.errors.Error: Dependency "SubContainer.bar" is not defined

What I'm wondering is if this is intended behaviour. Seems to me there should be no difference whether Provide["foo"] is declared before or after MainContainer declaration as long as I'm not trying to use the foo variable BEFORE MainContainer is initialized.

This in general is what i'm trying to accomplish:

# external library class
class Foo:
    def __init__(self, bar):
        self.bar = bar

# sub_module/container.py
class SubContainer(containers.DeclarativeContainer):
    wiring_config = containers.WiringConfiguration(
        modules=[__name__], packages=[]
    )
    bar = providers.Dependency(instance_of=str)

    foo = providers.Factory(Foo, bar=bar)

# sub_module/foo.py
foo: Foo = Provide["foo"]

# main.py
from .sub_module import foo

class MainContainer(containers.DeclarativeContainer):
    sub_container = providers.Container(SubContainer, bar="BAR")

container = MainContainer()
container.check_dependencies()

app = App(foo)

kkjot88 avatar Apr 20 '23 11:04 kkjot88