Declarative containerΒΆ

DeclarativeContainer is a class-based style of the providers definition.

You create the declarative container subclass, put the providers as attributes and create the container instance.

from dependency_injector import containers, providers


class Container(containers.DeclarativeContainer):

    factory1 = providers.Factory(object)

    factory2 = providers.Factory(object)


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

    object1 = container.factory1()
    object2 = container.factory2()

    print(container.providers)
    # {
    #     "factory1": <dependency_injector.providers.Factory(...),
    #     "factory2": <dependency_injector.providers.Factory(...),
    # }

The declarative container providers should only be used when you have the container instance. Working with the providers of the container on the class level will influence all further instances.

The declarative container can not have any methods or any other attributes then providers.

The container class provides next attributes:

  • providers - the dictionary of all the container providers

  • cls_providers - the dictionary of the container providers of the current container

  • inherited_providers - the dictionary of all the inherited container providers

from dependency_injector import containers, providers


class ContainerA(containers.DeclarativeContainer):

    provider1 = providers.Factory(object)


class ContainerB(ContainerA):

    provider2 = providers.Singleton(object)


assert ContainerA.providers == {
    "provider1": ContainerA.provider1,
}
assert ContainerB.providers == {
    "provider1": ContainerA.provider1,
    "provider2": ContainerB.provider2,
}

assert ContainerA.cls_providers == {
    "provider1": ContainerA.provider1,
}
assert ContainerB.cls_providers == {
    "provider2": ContainerB.provider2,
}

assert ContainerA.inherited_providers == {}
assert ContainerB.inherited_providers == {
    "provider1": ContainerA.provider1,
}

Injections in the declarative container are done the usual way:

import sqlite3

from dependency_injector import containers, providers


class UserService:
    def __init__(self, db: sqlite3.Connection):
        self.db = db


class AuthService:
    def __init__(self, db: sqlite3.Connection, user_service: UserService):
        self.db = db
        self.user_service = user_service


class Container(containers.DeclarativeContainer):

    database = providers.Singleton(sqlite3.connect, ":memory:")

    user_service = providers.Factory(
        UserService,
        db=database,
    )

    auth_service = providers.Factory(
        AuthService,
        db=database,
        user_service=user_service,
    )


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

    user_service = container.user_service()
    auth_service = container.auth_service()

    assert user_service.db is auth_service.db is container.database()
    assert isinstance(auth_service.user_service, UserService)

You can override container providers while creating a container instance:

import sqlite3
from unittest import mock

from dependency_injector import containers, providers


class Container(containers.DeclarativeContainer):

    database = providers.Singleton(sqlite3.connect, ":memory:")


if __name__ == "__main__":
    container = Container(database=mock.Mock(sqlite3.Connection))

    database = container.database()
    assert isinstance(database, mock.Mock)

Alternatively, you can call container.override_providers() method when the container instance already exists:

container = Container()

container.override_providers(foo=mock.Mock(Foo), bar=mock.Mock(Bar))

assert isinstance(container.foo(), mock.Mock)
assert isinstance(container.bar(), mock.Mock)

You can also use container.override_providers() with a context manager to reset provided overriding after the context is closed:

container = Container()

with container.override_providers(foo=mock.Mock(Foo), bar=mock.Mock(Bar)):
    assert isinstance(container.foo(), mock.Mock)
    assert isinstance(container.bar(), mock.Mock)

assert isinstance(container.foo(), Foo)
assert isinstance(container.bar(), Bar)