Chained Factories pattern¶
This example demonstrates “Chained Factories” pattern.
The idea of the pattern is in wrapping Factory into another Factory that adds
additional arguments.
base_factory = providers.Factory(
    SomeClass,
    base_argument=1,
)
concrete_factory = providers.Factory(
    base_factory,
    extra_argument=2,
)
if __name__ == "__main__":
    instance = concrete_factory()
    # Same as: # instance = SomeClass(base_argument=1, extra_argument=2)
Sample code¶
Listing of the pattern example:
"""`Chained Factories` pattern."""
from dependency_injector import containers, providers
class SqlAlchemyDatabaseService:
    def __init__(self, session, base_class):
        self.session = session
        self.base_class = base_class
class TokensService:
    def __init__(self, id_generator, database):
        self.id_generator = id_generator
        self.database = database
class Token:
    ...
class UsersService:
    def __init__(self, id_generator, database):
        self.id_generator = id_generator
        self.database = database
class User:
    ...
# Sample objects
session = object()
id_generator = object()
class Container(containers.DeclarativeContainer):
    database = providers.Factory(
        SqlAlchemyDatabaseService,
        session=session,
    )
    token_service = providers.Factory(
        TokensService,
        id_generator=id_generator,
        database=providers.Factory(
            database,
            base_class=Token,
        ),
    )
    user_service = providers.Factory(
        UsersService,
        id_generator=id_generator,
        database=providers.Factory(
            database,
            base_class=User,
        ),
    )
if __name__ == "__main__":
    container = Container()
    token_service = container.token_service()
    assert token_service.database.base_class is Token
    user_service = container.user_service()
    assert user_service.database.base_class is User
Arguments priority¶
Passing of the arguments works the same way like for any other Factory provider.
# 1. Keyword arguments of upper level factory are added to lower level factory
chained_dict_factory = providers.Factory(
    providers.Factory(dict, arg1=1),
    arg2=2,
)
print(chained_dict_factory())  # prints: {"arg1": 1, "arg2": 2}
# 2. Keyword arguments of upper level factory have priority
chained_dict_factory = providers.Factory(
    providers.Factory(dict, arg1=1),
    arg1=2,
)
print(chained_dict_factory())  # prints: {"arg1": 2}
# 3. Keyword arguments provided from context have the most priority
chained_dict_factory = providers.Factory(
    providers.Factory(dict, arg1=1),
    arg1=2,
)
print(chained_dict_factory(arg1=3))  # prints: {"arg1": 3}
Credits¶
The “Chained Factories” pattern was suggested by the Dependency Injector users.