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.
A declarative container cannot have any methods or attributes other than providers.
The container class provides next attributes:
providers
- the dictionary of all the container providerscls_providers
- the dictionary of the container providers of the current containerinherited_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)