diff --git a/docs/examples-other/chained-factories.rst b/docs/examples-other/chained-factories.rst new file mode 100644 index 00000000..d7730cec --- /dev/null +++ b/docs/examples-other/chained-factories.rst @@ -0,0 +1,71 @@ +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. + +.. code-block:: python + + base_factory = providers.Factory( + SomeClass, + base_argument=1, + ) + + 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: + +.. literalinclude:: ../../examples/miniapps/factory-patterns/chained_factories.py + :language: python + +Arguments priority +------------------ + +Passing of the arguments works the same way like for any other :ref:`factory-provider`. + +Explanation & some more examples: + +.. code-block:: python + + # 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 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. + +.. disqus:: diff --git a/docs/examples-other/chained_factories.rst b/docs/examples-other/chained_factories.rst deleted file mode 100644 index 6d20bc7a..00000000 --- a/docs/examples-other/chained_factories.rst +++ /dev/null @@ -1,21 +0,0 @@ -Chained Factories pattern -========================= - -This example demonstrate implementation of "Chained Factories" pattern. -Main idea of this pattern is about wrapping :py:class:`Factory` into -another :py:class:`Factory` that mix additional arguments or keyword -arguments to a wrapped one. - -Listing of ``data.py``, demonstrates sample classes structure: - -.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py - :language: python - -Listing of ``chained_factories.py``, demonstrates "Chained Factories" -pattern and provide some explanation: - -.. literalinclude:: ../../examples/miniapps/factory_patterns/chained_factories.py - :language: python - - -.. disqus:: diff --git a/docs/examples-other/index.rst b/docs/examples-other/index.rst index 8dc717f1..50d97ae5 100644 --- a/docs/examples-other/index.rst +++ b/docs/examples-other/index.rst @@ -13,5 +13,5 @@ This sections contains assorted ``Dependency Injector`` examples. use-cases password-hashing - chained_factories + chained-factories factory_of_factories diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index b894247b..83770704 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -11,6 +11,7 @@ Develop ------- - Refactor "use cases" example. - Refactor "password hashing" example. +- Refactor "chained factories" pattern example. - Fix declarative container mypy stub to ``__init__`` to accept not only providers. - Refactor main module of the "decoupled packages" example. diff --git a/examples/miniapps/factory-patterns/chained_factories.py b/examples/miniapps/factory-patterns/chained_factories.py new file mode 100644 index 00000000..b54da028 --- /dev/null +++ b/examples/miniapps/factory-patterns/chained_factories.py @@ -0,0 +1,73 @@ +"""`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 diff --git a/examples/miniapps/factory_patterns/data.py b/examples/miniapps/factory-patterns/data.py similarity index 66% rename from examples/miniapps/factory_patterns/data.py rename to examples/miniapps/factory-patterns/data.py index 80fdd20f..c3229855 100644 --- a/examples/miniapps/factory_patterns/data.py +++ b/examples/miniapps/factory-patterns/data.py @@ -1,39 +1,33 @@ -"""Sample data classes.""" +"""Sample classes and objects.""" class SqlAlchemyDatabaseService: - """Database service of an entity.""" def __init__(self, session, base_class): - """Initialize object.""" self.session = session self.base_class = base_class class TokensService: - """Tokens service.""" def __init__(self, id_generator, database): - """Initialize object.""" self.id_generator = id_generator self.database = database class Token: - """Token entity.""" + ... class UsersService: - """Users service.""" def __init__(self, id_generator, database): - """Initialize object.""" self.id_generator = id_generator self.database = database class User: - """User entity.""" + ... # Sample objects diff --git a/examples/miniapps/factory_patterns/factory_of_factories.py b/examples/miniapps/factory-patterns/factory_of_factories.py similarity index 100% rename from examples/miniapps/factory_patterns/factory_of_factories.py rename to examples/miniapps/factory-patterns/factory_of_factories.py diff --git a/examples/miniapps/factory_patterns/chained_factories.py b/examples/miniapps/factory_patterns/chained_factories.py deleted file mode 100644 index 993d1fa2..00000000 --- a/examples/miniapps/factory_patterns/chained_factories.py +++ /dev/null @@ -1,59 +0,0 @@ -"""`Chained Factories` pattern.""" - -from dependency_injector import providers - -from data import ( - id_generator, - session, - SqlAlchemyDatabaseService, - TokensService, - Token, - UsersService, - User, -) - - -# "Chained Factories" pattern - -database = providers.Factory(SqlAlchemyDatabaseService, session=session) - -tokens = providers.Factory( - TokensService, - id_generator=id_generator, - database=providers.Factory(database, base_class=Token), -) - -users = providers.Factory( - UsersService, - id_generator=id_generator, - database=providers.Factory(database, base_class=User), -) - -tokens_service = tokens() -assert tokens_service.database.base_class is Token - -users_service = users() -assert users_service.database.base_class is User - -# Explanation & some more examples - -# 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 most priority -chained_dict_factory = providers.Factory( - providers.Factory(dict, arg1=1), - arg1=2, -) -print(chained_dict_factory(arg1=3)) # prints: {'arg1': 3}