Provider overriding

You can override any provider with another provider.

When provider is overridden it calls to the overriding provider instead of providing the object by its own.

This helps in testing. This also helps in overriding API clients with stubs for the development or staging environment.

To override a provider you need to call the Provider.override() method. This method receives a single argument called overriding. If the overriding value is a provider, this provider is called instead of the original. If value is not a provider, this value is returned instead of calling the original provider.

../_images/overriding.png
import dataclasses
import unittest.mock

from dependency_injector import containers, providers


class ApiClient:
    ...


class ApiClientStub(ApiClient):
    ...


@dataclasses.dataclass
class Service:
    api_client: ApiClient


class Container(containers.DeclarativeContainer):

    api_client_factory = providers.Factory(ApiClient)

    service_factory = providers.Factory(
        Service,
        api_client=api_client_factory,
    )


if __name__ == "__main__":
    container = Container()

    # 1. Use .override() to replace the API client with stub
    container.api_client_factory.override(providers.Factory(ApiClientStub))
    service1 = container.service_factory()
    assert isinstance(service1.api_client, ApiClientStub)

    # 2. Use .override() as a context manager to mock the API client in testing
    with container.api_client_factory.override(unittest.mock.Mock(ApiClient)):
        service2 = container.service_factory()
        assert isinstance(service2.api_client, unittest.mock.Mock)

    # 3. Use .reset_override() to get back to normal
    container.api_client_factory.reset_override()
    service3 = container.service_factory()
    assert isinstance(service3.api_client, ApiClient)

You can override a provider multiple times. In that case the latest overriding value will be used. The rest of the overriding values will form a stack.

To reset an overriding you can use the Provider.reset_override() or Provider.reset_last_overriding() methods.

You can use a context manager for overriding a provider with Provider.override():. The overriding will be reset when context closed.