Refactor factory of factories pattern example

This commit is contained in:
Roman Mogylatov 2020-09-07 21:57:43 -04:00
parent 8284d1f169
commit e1844a3040
8 changed files with 140 additions and 118 deletions

View File

@ -13,7 +13,7 @@ additional arguments.
base_argument=1, base_argument=1,
) )
factory = providers.Factory( concrete_factory = providers.Factory(
base_factory, base_factory,
extra_argument=2, extra_argument=2,
) )
@ -23,7 +23,6 @@ additional arguments.
instance = concrete_factory() instance = concrete_factory()
# Same as: # instance = SomeClass(base_argument=1, extra_argument=2) # Same as: # instance = SomeClass(base_argument=1, extra_argument=2)
Sample code Sample code
----------- -----------
@ -37,8 +36,6 @@ Arguments priority
Passing of the arguments works the same way like for any other :ref:`factory-provider`. Passing of the arguments works the same way like for any other :ref:`factory-provider`.
Explanation & some more examples:
.. code-block:: python .. code-block:: python
# 1. Keyword arguments of upper level factory are added to lower level factory # 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} 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( chained_dict_factory = providers.Factory(
providers.Factory(dict, arg1=1), providers.Factory(dict, arg1=1),
arg1=2, arg1=2,

View File

@ -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::

View File

@ -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::

View File

@ -14,4 +14,4 @@ This sections contains assorted ``Dependency Injector`` examples.
use-cases use-cases
password-hashing password-hashing
chained-factories chained-factories
factory_of_factories factory-of-factories

View File

@ -10,11 +10,17 @@ This example demonstrates an injection of the ``Callable`` provider.
The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/password-hashing>`_. The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/password-hashing>`_.
Listing of the ``example.py``: Sample code
-----------
Listing of the pattern example:
.. literalinclude:: ../../examples/miniapps/password-hashing/example.py .. literalinclude:: ../../examples/miniapps/password-hashing/example.py
:language: python :language: python
Run the example
---------------
Instructions for running: Instructions for running:
.. code-block:: bash .. code-block:: bash

View File

@ -12,6 +12,7 @@ Develop
- Refactor "use cases" example. - Refactor "use cases" example.
- Refactor "password hashing" example. - Refactor "password hashing" example.
- Refactor "chained factories" pattern example. - Refactor "chained factories" pattern example.
- Refactor "factory of factories" pattern example.
- Fix declarative container mypy stub to ``__init__`` to accept not only providers. - Fix declarative container mypy stub to ``__init__`` to accept not only providers.
- Refactor main module of the "decoupled packages" example. - Refactor main module of the "decoupled packages" example.

View File

@ -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()

View File

@ -1,69 +1,68 @@
"""`Factory of Factories` pattern.""" """`Factory of Factories` pattern."""
from dependency_injector import providers from dependency_injector import containers, providers
from data import (
id_generator,
session,
SqlAlchemyDatabaseService,
TokensService,
Token,
UsersService,
User,
)
# "Factory of Factories" pattern class SqlAlchemyDatabaseService:
database_factory = providers.Factory( def __init__(self, session, base_class):
providers.Factory, self.session = session
SqlAlchemyDatabaseService, self.base_class = base_class
session=session,
)
tokens = providers.Factory(
TokensService,
id_generator=id_generator,
database=database_factory(base_class=Token),
)
users = providers.Factory( class TokensService:
UsersService,
id_generator=id_generator,
database=database_factory(base_class=User),
)
tokens_service = tokens() def __init__(self, id_generator, database):
assert tokens_service.database.base_class is Token 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 class UsersService:
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 most priority def __init__(self, id_generator, database):
factory_of_dict_factories = providers.Factory( self.id_generator = id_generator
providers.Factory, self.database = database
dict,
arg1=1,
) class User:
dict_factory = factory_of_dict_factories(arg1=2) ...
print(dict_factory(arg1=3)) # prints: {'arg1': 3}
# 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