Refactor chained factories pattern example

This commit is contained in:
Roman Mogylatov 2020-09-07 21:45:03 -04:00
parent d93c4a419b
commit 8284d1f169
8 changed files with 149 additions and 90 deletions

View File

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

View File

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

View File

@ -13,5 +13,5 @@ This sections contains assorted ``Dependency Injector`` examples.
use-cases
password-hashing
chained_factories
chained-factories
factory_of_factories

View File

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

View File

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

View File

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

View File

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