nightblure / injection

Easy dependency injection, works with Python 3.8-3.12
https://injection.readthedocs.io/latest/
MIT License
4 stars 0 forks source link

Support for Container.override #3

Open warvariuc opened 1 month ago

warvariuc commented 1 month ago

The docs say:

Replace method call: some_container.override_providers(**overrides) -> some_container.override_providers(overrides)

This allows overriding providers.

But what about overriding a container?

https://github.com/ets-labs/python-dependency-injector/blob/cc2304e46e054ae08dc12995428759fbfb51af10/src/dependency_injector/containers.pyx#L220

nightblure commented 1 month ago

@warvariuc Thanks for the question!

Can you give an example of cases where this would be useful? I have never yet encountered this functionality in my experience with dependency_injector


UPD: I found a description of this functionality here. I couldn’t immediately understand in what situations this would be useful, because we have already implemented redefinition of one or multiple providers. I'm waiting for your examples

warvariuc commented 1 month ago

Here is an example how we use this in our code.

class Adapters(dependency_injector.containers.DeclarativeContainer.DeclarativeContainer):
    """A set of dependencies replaced as a whole in tests."""
    email_client: dependency_injector.providers.Provider[EmailClient] = dependency_injector.providers.Singleton(EmailHttpClient,  ...)
    ...

class ApplicationContainer(dependency_injector.containers.DeclarativeContainer):
    """Dependencies used in our code."""
    adapters: Adapters = dependency_injector.providers .DependenciesContainer()  # type: ignore
    ...
    email_client: dependency_injector.providers.Provider[EmailClient] = adapters.email_client
    ...

And in tests we override some dependencies:

class TestAdapters(Adapters):
    __test__ = False

    email_client: dip.Singleton[EmailClient] = dip.Singleton(TestEmailClient)
    ...

@pytest.fixture()
def inject_test_deps() -> containers.ApplicationContainer:
    with containers.container.adapters.override(TestAdapters()):
        yield containers.container
nightblure commented 1 month ago

@warvariuc thanks for example. I think this can be useful in a code base where DI containers are used everywhere and there are several of them. I'll probably implement what you suggested after I finish the documentation

warvariuc commented 1 month ago

Maybe there is a simpler/easier to override many providers at once. I am not sure. In the version I posted it's good that you declare test dependencies in a class, instead of of overriding them imperatively one by one.

nightblure commented 1 month ago

Maybe there is a simpler/easier to override many providers at once. I am not sure. In the version I posted it's good that you declare test dependencies in a class, instead of of overriding them imperatively one by one.

If I understand you correctly, it is already possible to override many providers: https://injection.readthedocs.io/latest/testing/provider-overriding.html#override-multiple-providers

But above it seems you are proposing, so to speak, the “next level” of overriding - this is not the level of overriding providers, but containers. Although this can certainly be replaced completely by overriding providers


If batch override of providers using the override_providers(**providers) method is enough for you, then I think you can close the current issue. If you want to override containers, I'm ready to try to implement it