Edit providers delegation section

This commit is contained in:
Roman Mogylatov 2020-08-30 22:01:24 -04:00
parent 1bd0abb897
commit 46935b3152
6 changed files with 35 additions and 109 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@ -77,48 +77,20 @@ If ``<dependency>`` is found the underlying provider will receive the
.. _factory_providers_delegation:
Factory providers delegation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Passing providers to the objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`Factory` provider could be delegated to any other provider via any
kind of injection.
When you need to inject the provider itself, but not the result of its call, use the ``.provider``
attribute of the provider that you're going to inject.
As it was mentioned earlier, if :py:class:`Factory` is
injectable value, it will be called every time when injection needs to be
done. But sometimes there is a need to inject :py:class:`Factory` provider
itself (not a result of its call) as a dependency. Such injections are called
- *delegated provider injections*.
Saying in other words, delegation of factories - is a way to inject factories
themselves, instead of results of their calls.
:py:class:`Factory` delegation is performed by wrapping delegated
:py:class:`Factory` into special provider type - :py:class:`Delegate`, that
just returns wrapped :py:class:`Factory`.
Actually, there are three ways for creating factory delegates:
+ ``DelegatedFactory(...)`` - use special type of factory -
:py:class:`DelegatedFactory`. Such factories are always injected as
delegates ("as is").
+ ``Delegate(Factory(...))`` - obviously wrapping factory into
:py:class:`Delegate` provider.
+ ``Factory(...).delegate()`` - calling factory :py:meth:`Factory.delegate`
method, that returns delegate wrapper for current factory.
+ ``Factory(...).provider`` - getting factory :py:attr:`Factory.provider`
attribute, that returns delegate wrapper for current factory (alias of
``Factory(...).delegate()`` method).
Example:
.. image:: /images/providers/factory_delegation.png
:width: 85%
:align: center
.. image:: images/factory_delegation.png
.. literalinclude:: ../../examples/providers/factory_delegation.py
:language: python
:lines: 3-
:emphasize-lines: 25
.. _factory_providers_specialization:
.. note:: Any provider has a ``.provider`` attribute.
Factory providers specialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,82 +1,37 @@
"""`Factory` providers delegation example."""
import collections
from typing import Callable, List
import dependency_injector.providers as providers
Photo = collections.namedtuple('Photo', [])
from dependency_injector import providers
class User:
"""Example user model."""
def __init__(self, photos_factory):
"""Initialize instance."""
self.photos_factory = photos_factory
self._main_photo = None
@property
def main_photo(self):
"""Return user's main photo."""
if not self._main_photo:
self._main_photo = self.photos_factory()
return self._main_photo
def __init__(self, uid: int) -> None:
self.uid = uid
# Defining User and Photo factories using DelegatedFactory provider:
photos_factory = providers.DelegatedFactory(Photo)
users_factory = providers.Factory(
User,
photos_factory=photos_factory,
)
class UserRepository:
def __init__(self, user_factory: Callable[..., User]) -> None:
self.user_factory = user_factory
# or using Delegate(Factory(...))
def get_all(self) -> List[User]:
return [
self.user_factory(**user_data)
for user_data in [{'uid': 1}, {'uid': 2}]
]
photos_factory = providers.Factory(Photo)
users_factory = providers.Factory(
User,
photos_factory=providers.Delegate(photos_factory),
user_factory = providers.Factory(User)
user_repository_factory = providers.Factory(
UserRepository,
user_factory=user_factory.provider,
)
# or using Factory(...).delegate()
if __name__ == '__main__':
user_repository = user_repository_factory()
photos_factory = providers.Factory(Photo)
users_factory = providers.Factory(
User,
photos_factory=photos_factory.delegate(),
)
user1, user2 = user_repository.get_all()
# Creating several User objects:
user1 = users_factory()
user2 = users_factory()
# Same as:
# user1 = User(photos_factory=photos_factory)
# user2 = User(photos_factory=photos_factory)
# Making some asserts:
assert isinstance(user1.main_photo, Photo)
assert isinstance(user2.main_photo, Photo)
# or using Factory(...).provider
photos_factory = providers.Factory(Photo)
users_factory = providers.Factory(
User,
photos_factory=photos_factory.provider,
)
# Creating several User objects:
user1 = users_factory()
user2 = users_factory()
# Same as:
# user1 = User(photos_factory=photos_factory)
# user2 = User(photos_factory=photos_factory)
# Making some asserts:
assert isinstance(user1.main_photo, Photo)
assert isinstance(user2.main_photo, Photo)
assert user1.uid == 1
assert user2.uid == 2

View File

@ -8,8 +8,7 @@ class Photo:
class User:
def __init__(self, uid: int, main_photo: Photo):
def __init__(self, uid: int, main_photo: Photo) -> None:
self.uid = uid
self.main_photo = main_photo

View File

@ -4,22 +4,22 @@ from dependency_injector import providers
class Regularizer:
def __init__(self, alpha: float):
def __init__(self, alpha: float) -> None:
self.alpha = alpha
class Loss:
def __init__(self, regularizer: Regularizer):
def __init__(self, regularizer: Regularizer) -> None:
self.regularizer = regularizer
class ClassificationTask:
def __init__(self, loss: Loss):
def __init__(self, loss: Loss) -> None:
self.loss = loss
class Algorithm:
def __init__(self, task: ClassificationTask):
def __init__(self, task: ClassificationTask) -> None:
self.task = task