mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-26 03:23:58 +03:00
Update documentation and example on creating a custom provider
This commit is contained in:
parent
aeace8cba5
commit
dd2ded7321
Binary file not shown.
Before Width: | Height: | Size: 37 KiB |
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
|
@ -11,6 +11,7 @@ Development version
|
||||||
-------------------
|
-------------------
|
||||||
- Update providers overriding documentation and rework examples.
|
- Update providers overriding documentation and rework examples.
|
||||||
- Update documentation on injecting provided object attributes, items or method calls.
|
- Update documentation on injecting provided object attributes, items or method calls.
|
||||||
|
- Update documentation and example on creating a custom provider.
|
||||||
|
|
||||||
3.35.1
|
3.35.1
|
||||||
------
|
------
|
||||||
|
|
|
@ -1,35 +1,43 @@
|
||||||
Writing of custom providers
|
Creating a custom providers
|
||||||
---------------------------
|
===========================
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Custom provider, Create
|
||||||
|
:description: This page demonstrates how to create a custom provider.
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
List of *Dependency Injector* providers could be widened with custom providers.
|
You can create a custom provider.
|
||||||
|
|
||||||
Below are some tips and recommendations that have to be met:
|
To create a custom provider you need to follow these rules:
|
||||||
|
|
||||||
1. Every custom provider has to extend base provider class -
|
1. New provider class should inherit :py:class:`Provider`.
|
||||||
:py:class:`Provider`.
|
2. You need to implement the ``Provider._provide()`` method.
|
||||||
2. Custom provider's ``__init__()`` could be overridden, but parent's
|
3. You need to implement the ``Provider.__deepcopy__()`` method. It should return an
|
||||||
initializer (:py:meth:`Provider.__init__`) has to be called.
|
equivalent copy of a provider. All providers must be copied with a ``deepcopy()`` function
|
||||||
3. Providing strategy has to be implemented in custom provider's
|
from the ``providers`` module. After the a new provider object is created use
|
||||||
:py:meth:`Provider.__call__` method.
|
``Provider._copy_overriding()`` method to copy all overriding providers. See the example
|
||||||
4. If custom provider is based on some standard providers, it is better to
|
below.
|
||||||
use delegation of standard providers, then extending of them.
|
4. If the new provider has a ``__init__()`` method, it should call the parent
|
||||||
5. If custom provider defines any attributes, it is good to list them in
|
``Provider.__init__()``.
|
||||||
``__slots__`` attribute (as *Dependency Injector* does). It can save
|
|
||||||
some memory.
|
|
||||||
6. If custom provider deals with injections, it is strongly recommended
|
|
||||||
to be consistent with :py:class:`Factory`, :py:class:`Singleton` and
|
|
||||||
:py:class:`Callable` providers style.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
.. image:: /images/providers/custom_provider.png
|
|
||||||
:width: 100%
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/custom_factory.py
|
.. literalinclude:: ../../examples/providers/custom_factory.py
|
||||||
:language: python
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
1. Prefer delegation over inheritance. If you choose between inheriting a ``Factory`` or
|
||||||
|
inheriting a ``Provider`` and use ``Factory`` internally - the last is better.
|
||||||
|
2. When create a new provider follow the ``Factory``-like injections style. Consistency matters.
|
||||||
|
3. Use the ``__slots__`` attribute to make sure nothing could be attached to your provider. You
|
||||||
|
will also save some memory.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
If you don't find needed provider in the ``providers`` module and experience troubles creating
|
||||||
|
one by your own - open a
|
||||||
|
`Github Issue <https://github.com/ets-labs/python-dependency-injector/issues>`_.
|
||||||
|
|
||||||
|
I'll help you to resolve the issue if that's possible. If the new provider can be useful for
|
||||||
|
others I'll include it into the ``providers`` module.
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,40 +1,42 @@
|
||||||
"""Custom `Factory` example."""
|
"""Custom provider example."""
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
class User:
|
class CustomFactory(providers.Provider):
|
||||||
"""Example class User."""
|
|
||||||
|
|
||||||
|
|
||||||
class UsersFactory(providers.Provider):
|
|
||||||
"""Example users factory."""
|
|
||||||
|
|
||||||
__slots__ = ('_factory',)
|
__slots__ = ('_factory',)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, provides, *args, **kwargs):
|
||||||
"""Initialize instance."""
|
self._factory = providers.Factory(provides, *args, **kwargs)
|
||||||
self._factory = providers.Factory(User)
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __deepcopy__(self, memo):
|
||||||
"""Return provided object.
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
Callable interface implementation.
|
copied = self.__class__(
|
||||||
"""
|
self._factory.provides,
|
||||||
if self.last_overriding is not None:
|
*providers.deepcopy(self._factory.args, memo),
|
||||||
return self.last_overriding._provide(args, kwargs)
|
**providers.deepcopy(self._factory.kwargs, memo),
|
||||||
|
)
|
||||||
|
self._copy_overridings(copied, memo)
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
|
def _provide(self, args, kwargs):
|
||||||
return self._factory(*args, **kwargs)
|
return self._factory(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
# Users factory:
|
factory = CustomFactory(object)
|
||||||
users_factory = UsersFactory()
|
|
||||||
|
|
||||||
# Creating several User objects:
|
|
||||||
user1 = users_factory()
|
|
||||||
user2 = users_factory()
|
|
||||||
|
|
||||||
# Making some asserts:
|
if __name__ == '__main__':
|
||||||
assert isinstance(user1, User)
|
object1 = factory()
|
||||||
assert isinstance(user2, User)
|
assert isinstance(object1, object)
|
||||||
assert user1 is not user2
|
|
||||||
|
object2 = factory()
|
||||||
|
assert isinstance(object1, object)
|
||||||
|
|
||||||
|
assert object1 is not object2
|
||||||
|
|
|
@ -43,6 +43,7 @@ class Provider(_Provider):
|
||||||
def delegate(self) -> Provider: ...
|
def delegate(self) -> Provider: ...
|
||||||
@property
|
@property
|
||||||
def provider(self) -> Provider: ...
|
def provider(self) -> Provider: ...
|
||||||
|
def _copy_overridings(self, copied: Provider, memo: Optional[Dict[str, Any]]) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
class Object(Provider, Generic[T]):
|
class Object(Provider, Generic[T]):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user