diff --git a/docs/examples-other/chained-factories.rst b/docs/examples-other/chained-factories.rst index d7730cec..0bec024e 100644 --- a/docs/examples-other/chained-factories.rst +++ b/docs/examples-other/chained-factories.rst @@ -13,7 +13,7 @@ additional arguments. base_argument=1, ) - factory = providers.Factory( + concrete_factory = providers.Factory( base_factory, extra_argument=2, ) @@ -23,7 +23,6 @@ additional arguments. instance = concrete_factory() # Same as: # instance = SomeClass(base_argument=1, extra_argument=2) - Sample code ----------- @@ -37,8 +36,6 @@ 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 @@ -55,7 +52,7 @@ Explanation & some more examples: ) print(chained_dict_factory()) # prints: {'arg1': 2} - # 3. Keyword arguments provided from context have most priority + # 3. Keyword arguments provided from context have the most priority chained_dict_factory = providers.Factory( providers.Factory(dict, arg1=1), arg1=2, diff --git a/docs/examples-other/factory-of-factories.rst b/docs/examples-other/factory-of-factories.rst new file mode 100644 index 00000000..6cc71aa3 --- /dev/null +++ b/docs/examples-other/factory-of-factories.rst @@ -0,0 +1,74 @@ +Factory of Factories pattern +============================ + +This example demonstrates "Factory of Factories" pattern. + +The idea of the pattern is in creating a ``Factory`` that creates another ``Factory`` and adds +additional arguments. + +.. code-block:: python + + base_factory = providers.Factory( + providers.Factory + SomeClass, + base_argument=1, + ) + + concrete_factory = providers.Factory( + OtherClass, + instance=base_factory(extra_argument=1), + ) + + + 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/factory_of_factories.py + :language: python + +Arguments priority +------------------ + +Passing of the arguments works the same way like for any other :ref:`factory-provider`. + +.. code-block:: python + + # 1. Keyword arguments of upper level factory are added to lower level factory + factory_of_dict_factories = providers.Factory( + providers.Factory, + dict, + arg1=1, + ) + dict_factory = factory_of_dict_factories(arg2=2) + print(dict_factory()) # prints: {'arg1': 1, 'arg2': 2} + + # 2. Keyword arguments of upper level factory have priority + factory_of_dict_factories = providers.Factory( + providers.Factory, + dict, + arg1=1, + ) + dict_factory = factory_of_dict_factories(arg1=2) + print(dict_factory()) # prints: {'arg1': 2} + + # 3. Keyword arguments provided from context have the most priority + factory_of_dict_factories = providers.Factory( + providers.Factory, + dict, + arg1=1, + ) + dict_factory = factory_of_dict_factories(arg1=2) + print(dict_factory(arg1=3)) # prints: {'arg1': 3} + +Credits +------- + +The "Factory of Factories" pattern was suggested by the ``Dependency Injector`` users. + +.. disqus:: diff --git a/docs/examples-other/factory_of_factories.rst b/docs/examples-other/factory_of_factories.rst deleted file mode 100644 index d3ef157b..00000000 --- a/docs/examples-other/factory_of_factories.rst +++ /dev/null @@ -1,20 +0,0 @@ -Factory of Factories pattern -============================ - -This example demonstrate implementation of "Factory of Factories" pattern. -Main idea of this pattern is about creation of a :py:class:`Factory` that -creates another :py:class:`Factory` and mix additional arguments to it. - -Listing of ``data.py``, demonstrates sample classes structure: - -.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py - :language: python - -Listing of ``factory_of_factories.py``, demonstrates "Chained Factories" -pattern and provide some explanation: - -.. literalinclude:: ../../examples/miniapps/factory_patterns/factory_of_factories.py - :language: python - - -.. disqus:: diff --git a/docs/examples-other/index.rst b/docs/examples-other/index.rst index 50d97ae5..023e60ec 100644 --- a/docs/examples-other/index.rst +++ b/docs/examples-other/index.rst @@ -14,4 +14,4 @@ This sections contains assorted ``Dependency Injector`` examples. use-cases password-hashing chained-factories - factory_of_factories + factory-of-factories diff --git a/docs/examples-other/password-hashing.rst b/docs/examples-other/password-hashing.rst index be12f713..d4d0af39 100644 --- a/docs/examples-other/password-hashing.rst +++ b/docs/examples-other/password-hashing.rst @@ -10,11 +10,17 @@ This example demonstrates an injection of the ``Callable`` provider. The source code is available on the `Github `_. -Listing of the ``example.py``: +Sample code +----------- + +Listing of the pattern example: .. literalinclude:: ../../examples/miniapps/password-hashing/example.py :language: python +Run the example +--------------- + Instructions for running: .. code-block:: bash diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 83770704..ad3f961b 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -12,6 +12,7 @@ Develop - Refactor "use cases" example. - Refactor "password hashing" example. - Refactor "chained factories" pattern example. +- Refactor "factory of 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/data.py b/examples/miniapps/factory-patterns/data.py deleted file mode 100644 index c3229855..00000000 --- a/examples/miniapps/factory-patterns/data.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Sample classes and objects.""" - - -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() diff --git a/examples/miniapps/factory-patterns/factory_of_factories.py b/examples/miniapps/factory-patterns/factory_of_factories.py index 7a6a5fc1..664c2c58 100644 --- a/examples/miniapps/factory-patterns/factory_of_factories.py +++ b/examples/miniapps/factory-patterns/factory_of_factories.py @@ -1,69 +1,68 @@ """`Factory of Factories` pattern.""" -from dependency_injector import providers - -from data import ( - id_generator, - session, - SqlAlchemyDatabaseService, - TokensService, - Token, - UsersService, - User, -) +from dependency_injector import containers, providers -# "Factory of Factories" pattern +class SqlAlchemyDatabaseService: -database_factory = providers.Factory( - providers.Factory, - SqlAlchemyDatabaseService, - session=session, -) + def __init__(self, session, base_class): + self.session = session + self.base_class = base_class -tokens = providers.Factory( - TokensService, - id_generator=id_generator, - database=database_factory(base_class=Token), -) -users = providers.Factory( - UsersService, - id_generator=id_generator, - database=database_factory(base_class=User), -) +class TokensService: -tokens_service = tokens() -assert tokens_service.database.base_class is Token + def __init__(self, id_generator, database): + self.id_generator = id_generator + self.database = database -users_service = users() -assert users_service.database.base_class is User -# Explanation & some more examples +class Token: + ... -# 1. Keyword arguments of upper level factory are added to lower level factory -factory_of_dict_factories = providers.Factory( - providers.Factory, - dict, - arg1=1, -) -dict_factory = factory_of_dict_factories(arg2=2) -print(dict_factory()) # prints: {'arg1': 1, 'arg2': 2} -# 2. Keyword arguments of upper level factory have priority -factory_of_dict_factories = providers.Factory( - providers.Factory, - dict, - arg1=1, -) -dict_factory = factory_of_dict_factories(arg1=2) -print(dict_factory()) # prints: {'arg1': 2} +class UsersService: -# 3. Keyword arguments provided from context have most priority -factory_of_dict_factories = providers.Factory( - providers.Factory, - dict, - arg1=1, -) -dict_factory = factory_of_dict_factories(arg1=2) -print(dict_factory(arg1=3)) # prints: {'arg1': 3} + 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_factory = providers.Factory( + providers.Factory, + SqlAlchemyDatabaseService, + session=session, + ) + + token_service = providers.Factory( + TokensService, + id_generator=id_generator, + database=database_factory(base_class=Token), + ) + + user_service = providers.Factory( + UsersService, + id_generator=id_generator, + database=database_factory(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