Merge branch 'release/3.36.0' into master
|
@ -52,7 +52,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = u'Dependency Injector'
|
||||
copyright = u'2017, ETS Labs'
|
||||
copyright = u'2020, ETS Labs'
|
||||
author = u'ETS Labs'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Overriding of the container
|
||||
---------------------------
|
||||
Container overriding
|
||||
--------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
|
|
Before Width: | Height: | Size: 295 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 10 KiB |
|
@ -7,6 +7,15 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
3.36.0
|
||||
------
|
||||
- Update providers overriding documentation and rework examples.
|
||||
- Update documentation on injecting provided object attributes, items or method calls.
|
||||
- Update documentation and example on creating a custom provider.
|
||||
- Update providers index documentation page to give better overview of providers functionality.
|
||||
- Fix mypy stub of the ``Provider`` to specify the protected ``._copy_overridings()`` method.
|
||||
- Update copyright year in the documentation.
|
||||
|
||||
3.35.1
|
||||
------
|
||||
- Fix minor issues in the providers documentation and examples.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Callable provider
|
||||
-----------------
|
||||
=================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Function,Method,Example
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Configuration provider
|
||||
----------------------
|
||||
======================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection,
|
||||
|
@ -20,7 +20,7 @@ Configuration provider
|
|||
It implements the principle "use first, define later".
|
||||
|
||||
Loading from an INI file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
------------------------
|
||||
|
||||
``Configuration`` provider can load configuration from an ``ini`` file using the
|
||||
:py:meth:`Configuration.from_ini` method:
|
||||
|
@ -40,7 +40,7 @@ where ``examples/providers/configuration/config.ini`` is:
|
|||
variable ``ENV_NAME``.
|
||||
|
||||
Loading from a YAML file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
------------------------
|
||||
|
||||
``Configuration`` provider can load configuration from a ``yaml`` file using the
|
||||
:py:meth:`Configuration.from_yaml` method:
|
||||
|
@ -74,7 +74,7 @@ variable ``ENV_NAME``.
|
|||
*Don't forget to mirror the changes in the requirements file.*
|
||||
|
||||
Loading from a dictionary
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------
|
||||
|
||||
``Configuration`` provider can load configuration from a Python ``dict`` using the
|
||||
:py:meth:`Configuration.from_dict` method:
|
||||
|
@ -85,7 +85,7 @@ Loading from a dictionary
|
|||
:emphasize-lines: 6-13
|
||||
|
||||
Loading from an environment variable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
------------------------------------
|
||||
|
||||
``Configuration`` provider can load configuration from an environment variable using the
|
||||
:py:meth:`Configuration.from_env` method:
|
||||
|
@ -96,7 +96,7 @@ Loading from an environment variable
|
|||
:emphasize-lines: 6-8
|
||||
|
||||
Loading from the multiple sources
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------------------
|
||||
|
||||
``Configuration`` provider can load configuration from the multiple sources. Loaded
|
||||
configuration is merged recursively over the existing configuration.
|
||||
|
@ -112,7 +112,7 @@ where ``examples/providers/configuration/config.local.yml`` is:
|
|||
:language: ini
|
||||
|
||||
Specifying the value type
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------
|
||||
|
||||
You can specify the type of the injected configuration value explicitly.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Coroutine provider
|
||||
------------------
|
||||
==================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Coroutine,Asynchronous,
|
||||
|
|
|
@ -1,35 +1,45 @@
|
|||
Writing of custom providers
|
||||
---------------------------
|
||||
.. _create-provider:
|
||||
|
||||
Creating a custom provider
|
||||
==========================
|
||||
|
||||
.. 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
|
||||
|
||||
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 -
|
||||
:py:class:`Provider`.
|
||||
2. Custom provider's ``__init__()`` could be overridden, but parent's
|
||||
initializer (:py:meth:`Provider.__init__`) has to be called.
|
||||
3. Providing strategy has to be implemented in custom provider's
|
||||
:py:meth:`Provider.__call__` method.
|
||||
4. If custom provider is based on some standard providers, it is better to
|
||||
use delegation of standard providers, then extending of them.
|
||||
5. If custom provider defines any attributes, it is good to list them in
|
||||
``__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
|
||||
1. New provider class should inherit :py:class:`Provider`.
|
||||
2. You need to implement the ``Provider._provide()`` method.
|
||||
3. You need to implement the ``Provider.__deepcopy__()`` method. It should return an
|
||||
equivalent copy of a provider. All providers must be copied with a ``deepcopy()`` function
|
||||
from the ``providers`` module. After the a new provider object is created use
|
||||
``Provider._copy_overriding()`` method to copy all overriding providers. See the example
|
||||
below.
|
||||
4. If the new provider has a ``__init__()`` method, it should call the parent
|
||||
``Provider.__init__()``.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/custom_factory.py
|
||||
: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::
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Dependency provider
|
||||
-------------------
|
||||
===================
|
||||
|
||||
.. currentmodule:: dependency_injector.providers
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ injected following these rules:
|
|||
:lines: 3-
|
||||
|
||||
Passing arguments to the underlying providers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------------------------------
|
||||
|
||||
``Factory`` provider can pass the arguments to the underlying providers. This helps when you need
|
||||
to assemble a nested objects graph and pass the arguments deep inside.
|
||||
|
@ -88,7 +88,7 @@ If ``<dependency>`` is found the underlying provider will receive the
|
|||
.. _factory_providers_delegation:
|
||||
|
||||
Passing providers to the objects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
--------------------------------
|
||||
|
||||
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.
|
||||
|
@ -105,7 +105,7 @@ attribute of the provider that you're going to inject.
|
|||
.. _factory-specialize-provided-type:
|
||||
|
||||
Specializing the provided type
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
------------------------------
|
||||
|
||||
You can create a specialized ``Factory`` provider that provides only specific type. For doing
|
||||
this you need to create a subclass of the ``Factory`` provider and define the ``provided_type``
|
||||
|
@ -119,7 +119,7 @@ class attribute.
|
|||
.. _abstract-factory:
|
||||
|
||||
Abstract factory
|
||||
~~~~~~~~~~~~~~~~
|
||||
----------------
|
||||
|
||||
:py:class:`AbstractFactory` provider helps when you need to create a provider of some base class
|
||||
and the particular implementation is not yet know. ``AbstractFactory`` provider is a ``Factory``
|
||||
|
@ -138,7 +138,7 @@ provider with two peculiarities:
|
|||
:emphasize-lines: 32
|
||||
|
||||
Factory aggregate
|
||||
~~~~~~~~~~~~~~~~~
|
||||
-----------------
|
||||
|
||||
:py:class:`FactoryAggregate` provider aggregates multiple factories. When you call the
|
||||
``FactoryAggregate`` it delegates the call to one of the factories.
|
||||
|
|
BIN
docs/providers/images/overriding.png
Normal file
After Width: | Height: | Size: 13 KiB |
|
@ -7,7 +7,8 @@ Providers help to assemble the objects. They create objects and inject the depen
|
|||
|
||||
Each provider is a callable. You call the provider like a function when you need to create an
|
||||
object. Provider retrieves the underlying dependencies and inject them into the created object.
|
||||
It causes the cascade effect that helps to assemble object graphs.
|
||||
It causes the cascade effect that helps to assemble object graphs. See ``Factory``, ``Singleton``,
|
||||
``Callable`` and other provider docs below.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
@ -23,10 +24,13 @@ It causes the cascade effect that helps to assemble object graphs.
|
|||
│
|
||||
└──> provider6()
|
||||
|
||||
Another providers feature is an overriding. Any of the providers can be overridden by another
|
||||
provider. When provider is overridden it calls to the overriding provider instead of providing
|
||||
the object by its own. This helps in testing. This also helps in overriding API clients with
|
||||
stubs for the development or staging environment.
|
||||
Another providers feature is an overriding. You can override any provider by another provider.
|
||||
This helps in testing. This also helps in overriding API clients with stubs for the development
|
||||
or staging environment. See the example at :ref:`provider-overriding`.
|
||||
|
||||
If you need to inject not the whole object but the parts see :ref:`provided-instance`.
|
||||
|
||||
To create a new provider see :ref:`create-provider`.
|
||||
|
||||
Providers module API docs - :py:mod:`dependency_injector.providers`
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
List provider
|
||||
-------------
|
||||
=============
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,List,Injection
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Object provider
|
||||
---------------
|
||||
===============
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Object
|
||||
|
|
|
@ -1,47 +1,43 @@
|
|||
Overriding of providers
|
||||
-----------------------
|
||||
.. _provider-overriding:
|
||||
|
||||
Provider overriding
|
||||
===================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Override,Test,Unit
|
||||
:description: This page demonstrates how to implement providers overriding. This helps in
|
||||
testing and configuring the system for the multiple environments.
|
||||
|
||||
.. currentmodule:: dependency_injector.providers
|
||||
|
||||
Every provider could be overridden by another provider.
|
||||
You can override any provider by another provider.
|
||||
|
||||
This gives opportunity to make system behaviour more flexible at some point.
|
||||
The main feature is that while your code is using providers, it depends on
|
||||
providers, but not on the objects that providers provide. As a result of this,
|
||||
you can change providing by provider object to a different one, but still
|
||||
compatible one, without changing your previously written code.
|
||||
When provider is overridden it calls to the overriding provider instead of providing
|
||||
the object by its own.
|
||||
|
||||
Provider overriding functionality has such interface:
|
||||
This helps in testing. This also helps in overriding API clients with stubs for the development
|
||||
or staging environment.
|
||||
|
||||
.. image:: /images/providers/provider_override.png
|
||||
:width: 55%
|
||||
:align: center
|
||||
To override a provider you need to call the ``Provider.override()`` method. This method receives
|
||||
a single argument called ``overriding``. If the ``overriding`` value is a provider, this provider
|
||||
is called instead of the original. If value is not a provider, this value is returned instead of
|
||||
calling the original provider.
|
||||
|
||||
+ :py:meth:`Provider.override()` - takes another provider that will be used
|
||||
instead of current provider. This method could be called several times.
|
||||
In such case, last passed provider would be used as overriding one.
|
||||
+ :py:meth:`Provider.reset_override()` - resets all overriding providers.
|
||||
Provider starts to behave itself like usual.
|
||||
+ :py:meth:`Provider.reset_last_overriding()` - remove last overriding
|
||||
provider from stack of overriding providers.
|
||||
|
||||
Example:
|
||||
|
||||
.. image:: /images/providers/overriding_simple.png
|
||||
.. image:: images/overriding.png
|
||||
:width: 80%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/providers/overriding_simple.py
|
||||
.. literalinclude:: ../../examples/providers/overriding.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Example:
|
||||
You can override a provider multiple times. In that case the latest ``overriding`` value will be
|
||||
used. The rest of the overriding values will form a stack.
|
||||
|
||||
.. image:: /images/providers/overriding_users_model.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/providers/overriding_users_model.py
|
||||
:language: python
|
||||
To reset an overriding you can use the ``Provider.reset_override()`` or
|
||||
``Provider.reset_last_overriding()`` methods.
|
||||
|
||||
You can use a context manager for overriding a provider ``with Provider.override():``. The
|
||||
overriding will be reset when context closed.
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
Injecting attributes, items, or call methods of the provided instance
|
||||
---------------------------------------------------------------------
|
||||
.. _provided-instance:
|
||||
|
||||
Injecting provided object attributes, items, or call its methods
|
||||
================================================================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Attribute,Method,Call
|
||||
:description: This page demonstrates how to inject attributes, items or call method of the
|
||||
provided instance.
|
||||
|
||||
.. currentmodule:: dependency_injector.providers
|
||||
|
||||
In this section you will know how to inject provided instance attribute or item into the other
|
||||
provider.
|
||||
|
||||
It also describes how to call a method of the provided instance and use the result of
|
||||
this call as an injection value.
|
||||
You can inject provided object attribute, item or result of its method call.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/provided_instance.py
|
||||
:language: python
|
||||
|
@ -15,14 +18,14 @@ this call as an injection value.
|
|||
:lines: 3-
|
||||
|
||||
To use the feature you should use the ``.provided`` attribute of the injected provider. This
|
||||
attribute helps to specify what happens with the provided instance. You can retrieve an injection
|
||||
value from:
|
||||
attribute helps to specify what happens with the provided instance before the injection. You can
|
||||
use any combination of the following:
|
||||
|
||||
- an attribute of the provided instance
|
||||
- an item of the provided instance
|
||||
- a call of the provided instance method
|
||||
- an attribute of the provided object
|
||||
- an item of the provided object
|
||||
- a call of the provided object method
|
||||
|
||||
When you use the call of the provided instance method you can specify the injections into this
|
||||
When you use a call of the provided instance method you can specify the injections for this
|
||||
method like you do with any other provider.
|
||||
|
||||
You can do nested constructions:
|
||||
|
@ -32,35 +35,24 @@ You can do nested constructions:
|
|||
:emphasize-lines: 24-30
|
||||
:lines: 3-
|
||||
|
||||
Attribute ``.provided`` is available for the providers that return instances. Providers that
|
||||
have ``.provided`` attribute:
|
||||
The ``.provided`` attribute is available for the next providers:
|
||||
|
||||
- :py:class:`Callable` and its subclasses
|
||||
- :py:class:`Factory` and its subclasses
|
||||
- :py:class:`Singleton` and its subclasses
|
||||
- :py:class:`Callable` and its subclasses
|
||||
- :py:class:`Object`
|
||||
- :py:class:`List`
|
||||
- :py:class:`Selector`
|
||||
- :py:class:`Dependency`
|
||||
|
||||
Special providers like :py:class:`Configuration` or :py:class:`Delegate` do not have the
|
||||
``.provided`` attribute.
|
||||
|
||||
Provider subclasses
|
||||
-------------------
|
||||
|
||||
When you create a new provider subclass and want to implement the ``.provided`` attribute, you
|
||||
should use the :py:class:`ProvidedInstance` provider.
|
||||
should use the :py:class:`ProvidedInstance` provider. Add the ``.provided`` property
|
||||
implementation to a new subclass:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@property
|
||||
def provided(self):
|
||||
"""Return :py:class:`ProvidedInstance` provider."""
|
||||
return ProvidedInstance(self)
|
||||
|
||||
In all other cases you should not use :py:class:`ProvidedInstance`, :py:class:`AttributeGetter`,
|
||||
:py:class:`ItemGetter`, or :py:class:`MethodCaller` providers directly. Use the ``.provided``
|
||||
attribute of the injected provider instead.
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.. _selector-provider:
|
||||
|
||||
Selector provider
|
||||
-----------------
|
||||
=================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Singleton provider
|
||||
------------------
|
||||
==================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Singleton,Pattern,Example,
|
||||
|
@ -33,7 +33,7 @@ factories:
|
|||
- :ref:`abstract-factory`
|
||||
|
||||
Resetting memorized object
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
--------------------------
|
||||
|
||||
To reset a memorized object you need to call the ``.reset()`` method of the ``Singleton``
|
||||
provider.
|
||||
|
@ -48,7 +48,7 @@ provider.
|
|||
managed by the garbage collector.
|
||||
|
||||
Using singleton with multiple threads
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------------------
|
||||
|
||||
``Singleton`` provider is NOT thread-safe. You need to explicitly establish a synchronization for
|
||||
using the ``Singleton`` provider in the multi-threading application. Otherwise you could trap
|
||||
|
@ -67,7 +67,7 @@ There are two thread-safe singleton implementations out of the box:
|
|||
:emphasize-lines: 11,12
|
||||
|
||||
Implementing scopes
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
-------------------
|
||||
|
||||
To implement a scoped singleton provider use a ``Singleton`` provider and reset its scope when
|
||||
needed.
|
||||
|
|
|
@ -1,40 +1,42 @@
|
|||
"""Custom `Factory` example."""
|
||||
"""Custom provider example."""
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User:
|
||||
"""Example class User."""
|
||||
|
||||
|
||||
class UsersFactory(providers.Provider):
|
||||
"""Example users factory."""
|
||||
class CustomFactory(providers.Provider):
|
||||
|
||||
__slots__ = ('_factory',)
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize instance."""
|
||||
self._factory = providers.Factory(User)
|
||||
def __init__(self, provides, *args, **kwargs):
|
||||
self._factory = providers.Factory(provides, *args, **kwargs)
|
||||
super().__init__()
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""Return provided object.
|
||||
def __deepcopy__(self, memo):
|
||||
copied = memo.get(id(self))
|
||||
if copied is not None:
|
||||
return copied
|
||||
|
||||
Callable interface implementation.
|
||||
"""
|
||||
if self.last_overriding is not None:
|
||||
return self.last_overriding._provide(args, kwargs)
|
||||
copied = self.__class__(
|
||||
self._factory.provides,
|
||||
*providers.deepcopy(self._factory.args, memo),
|
||||
**providers.deepcopy(self._factory.kwargs, memo),
|
||||
)
|
||||
self._copy_overridings(copied, memo)
|
||||
|
||||
return copied
|
||||
|
||||
def _provide(self, args, kwargs):
|
||||
return self._factory(*args, **kwargs)
|
||||
|
||||
|
||||
# Users factory:
|
||||
users_factory = UsersFactory()
|
||||
factory = CustomFactory(object)
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory()
|
||||
user2 = users_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert isinstance(user1, User)
|
||||
assert isinstance(user2, User)
|
||||
assert user1 is not user2
|
||||
if __name__ == '__main__':
|
||||
object1 = factory()
|
||||
assert isinstance(object1, object)
|
||||
|
||||
object2 = factory()
|
||||
assert isinstance(object1, object)
|
||||
|
||||
assert object1 is not object2
|
||||
|
|
42
examples/providers/overriding.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
"""Simple providers overriding example."""
|
||||
|
||||
import unittest.mock
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class ApiClient:
|
||||
...
|
||||
|
||||
|
||||
class ApiClientStub(ApiClient):
|
||||
...
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, api_client: ApiClient):
|
||||
self._api_client = api_client
|
||||
|
||||
|
||||
api_client_factory = providers.Factory(ApiClient)
|
||||
service_factory = providers.Factory(
|
||||
Service,
|
||||
api_client=api_client_factory,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 1. Use .override() to replace the API client with stub
|
||||
api_client_factory.override(providers.Factory(ApiClientStub))
|
||||
service1 = service_factory()
|
||||
assert isinstance(service1.api_client, ApiClientStub)
|
||||
|
||||
# 2. Use .override() as a context manager to mock the API client in testing
|
||||
with api_client_factory.override(unittest.mock.Mock(ApiClient)):
|
||||
service3 = service_factory()
|
||||
assert isinstance(service3.api_client, unittest.mock.Mock)
|
||||
|
||||
# 3. Use .reset_override() to get back to normal
|
||||
api_client_factory.reset_override()
|
||||
service3 = service_factory()
|
||||
assert isinstance(service3.api_client, ApiClient)
|
|
@ -1,36 +0,0 @@
|
|||
"""Simple providers overriding example."""
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
class User:
|
||||
"""Example class User."""
|
||||
|
||||
|
||||
# Users factory:
|
||||
users_factory = providers.Factory(User)
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory()
|
||||
user2 = users_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert user1 is not user2
|
||||
assert isinstance(user1, User) and isinstance(user2, User)
|
||||
|
||||
|
||||
# Extending User:
|
||||
class SuperUser(User):
|
||||
"""Example class SuperUser."""
|
||||
|
||||
|
||||
# Overriding users factory:
|
||||
users_factory.override(providers.Factory(SuperUser))
|
||||
|
||||
# Creating some more User objects using overridden users factory:
|
||||
user3 = users_factory()
|
||||
user4 = users_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert user4 is not user3
|
||||
assert isinstance(user3, SuperUser) and isinstance(user4, SuperUser)
|
|
@ -1,95 +0,0 @@
|
|||
"""Overriding user's model example."""
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
class User:
|
||||
"""Example class User."""
|
||||
|
||||
def __init__(self, id, password):
|
||||
"""Initialize instance."""
|
||||
self.id = id
|
||||
self.password = password
|
||||
super().__init__()
|
||||
|
||||
|
||||
class UsersService:
|
||||
"""Example class UsersService."""
|
||||
|
||||
def __init__(self, user_cls):
|
||||
"""Initialize instance."""
|
||||
self.user_cls = user_cls
|
||||
super().__init__()
|
||||
|
||||
def get_by_id(self, id):
|
||||
"""Find user by his id and return user model."""
|
||||
return self.user_cls(id=id, password='secret' + str(id))
|
||||
|
||||
|
||||
# Users factory and UsersService provider:
|
||||
users_service = providers.Factory(UsersService, user_cls=User)
|
||||
|
||||
# Getting several users and making some asserts:
|
||||
user1 = users_service().get_by_id(1)
|
||||
user2 = users_service().get_by_id(2)
|
||||
|
||||
assert isinstance(user1, User)
|
||||
assert user1.id == 1
|
||||
assert user1.password == 'secret1'
|
||||
|
||||
assert isinstance(user2, User)
|
||||
assert user2.id == 2
|
||||
assert user2.password == 'secret2'
|
||||
|
||||
assert user1 is not user2
|
||||
|
||||
# Extending user model and user service for adding custom attributes without
|
||||
# making any changes to client's code.
|
||||
|
||||
|
||||
class ExtendedUser(User):
|
||||
"""Example class ExtendedUser."""
|
||||
|
||||
def __init__(self, id, password, first_name=None, last_name=None,
|
||||
gender=None):
|
||||
"""Initialize instance."""
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.gender = gender
|
||||
super().__init__(id, password)
|
||||
|
||||
|
||||
class ExtendedUsersService(UsersService):
|
||||
"""Example class ExtendedUsersService."""
|
||||
|
||||
def get_by_id(self, id):
|
||||
"""Find user by his id and return user model."""
|
||||
user = super(ExtendedUsersService, self).get_by_id(id)
|
||||
user.first_name = 'John' + str(id)
|
||||
user.last_name = 'Smith' + str(id)
|
||||
user.gender = 'male'
|
||||
return user
|
||||
|
||||
|
||||
# Overriding users_service provider:
|
||||
extended_users_service = providers.Factory(ExtendedUsersService,
|
||||
user_cls=ExtendedUser)
|
||||
users_service.override(extended_users_service)
|
||||
|
||||
# Getting few other users users and making some asserts:
|
||||
user3 = users_service().get_by_id(3)
|
||||
user4 = users_service().get_by_id(4)
|
||||
|
||||
assert isinstance(user3, ExtendedUser)
|
||||
assert user3.id == 3
|
||||
assert user3.password == 'secret3'
|
||||
assert user3.first_name == 'John3'
|
||||
assert user3.last_name == 'Smith3'
|
||||
|
||||
assert isinstance(user4, ExtendedUser)
|
||||
assert user4.id == 4
|
||||
assert user4.password == 'secret4'
|
||||
assert user4.first_name == 'John4'
|
||||
assert user4.last_name == 'Smith4'
|
||||
|
||||
assert user3 is not user4
|
|
@ -33,6 +33,7 @@ client_factory = providers.Factory(
|
|||
value4=service.provided.get_value.call(),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
client = client_factory()
|
||||
assert client.value1 == client.value2 == client.value3 == 'foo'
|
||||
|
|
|
@ -31,6 +31,7 @@ demo_list = providers.List(
|
|||
dependency.provided['foo']['baz'].call(service)['arg'].get_value.call(),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
assert demo_list() == [
|
||||
10,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Dependency injector top-level package."""
|
||||
|
||||
__version__ = '3.35.1'
|
||||
__version__ = '3.36.0'
|
||||
"""Version number that follows semantic versioning.
|
||||
|
||||
:type: str
|
||||
|
|
|
@ -43,6 +43,7 @@ class Provider(_Provider):
|
|||
def delegate(self) -> Provider: ...
|
||||
@property
|
||||
def provider(self) -> Provider: ...
|
||||
def _copy_overridings(self, copied: Provider, memo: Optional[Dict[str, Any]]) -> None: ...
|
||||
|
||||
|
||||
class Object(Provider, Generic[T]):
|
||||
|
|