mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-01-31 03:36:41 +03:00
Providers docs update (#289)
* Update callable provider docs * Update coroutine provider docs * Edit object docs * Edit list provider docs * Edit configuration provider docs * Edit selector provider docs * Fix mypy stub of the ``DeclarativeContainer`` to specify the ``__init__`` interface * Edit Dependency provider docs
This commit is contained in:
parent
995b2165df
commit
c4b33749d2
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 42 KiB |
|
@ -9,8 +9,9 @@ follows `Semantic versioning`_
|
||||||
|
|
||||||
Development version
|
Development version
|
||||||
-------------------
|
-------------------
|
||||||
- Update ``Singleton`` provider documentation.
|
- Update documentation and rework examples for: ``Singleton``, ``Callable``, ``Coroutine``,
|
||||||
- Rework ``Singleton`` provider examples.
|
``Object``, ``List``, ``Configuration``, ``Selector``, and ``Dependency`` providers.
|
||||||
|
- Fix mypy stub of the ``DeclarativeContainer`` to specify the ``__init__`` interface.
|
||||||
|
|
||||||
3.34.0
|
3.34.0
|
||||||
------
|
------
|
||||||
|
|
|
@ -1,69 +1,20 @@
|
||||||
Callable providers
|
Callable provider
|
||||||
------------------
|
-----------------
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Function,Method,Example
|
||||||
|
:description: Callable provider helps to make dependencies injection into functions. This page
|
||||||
|
demonstrates how to use a Callable provider.
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
:py:class:`Callable` provider calls wrapped callable on every call.
|
:py:class:`Callable` provider calls a function, a method or another callable.
|
||||||
|
|
||||||
Callable providers and injections
|
.. literalinclude:: ../../examples/providers/callable.py
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:py:class:`Callable` provider takes a various number of positional and keyword
|
|
||||||
arguments that are used as wrapped callable injections. Every time, when
|
|
||||||
:py:class:`Callable` provider is called, positional and keyword argument
|
|
||||||
injections would be passed as callable arguments.
|
|
||||||
|
|
||||||
Injections are done according to the next rules:
|
|
||||||
|
|
||||||
+ All providers (instances of :py:class:`Provider`) are called every time
|
|
||||||
when injection needs to be done.
|
|
||||||
+ Providers could be injected "as is" (delegated), if it is defined obviously.
|
|
||||||
Check out :ref:`callable_providers_delegation`.
|
|
||||||
+ All other injectable values are provided *"as is"*.
|
|
||||||
+ Positional context arguments will be appended after :py:class:`Callable`
|
|
||||||
positional injections.
|
|
||||||
+ Keyword context arguments have priority on :py:class:`Callable` keyword
|
|
||||||
injections and will be merged over them.
|
|
||||||
|
|
||||||
Example that shows usage of :py:class:`Callable` with positional argument
|
|
||||||
injections:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/callable_args.py
|
|
||||||
:language: python
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
|
|
||||||
Next one example shows usage of :py:class:`Callable` with keyword argument
|
``Callable`` provider handles an injection of the dependencies the same way like a
|
||||||
injections:
|
:ref:`factory-provider`.
|
||||||
|
|
||||||
.. image:: /images/providers/callable.png
|
|
||||||
:width: 100%
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/callable_kwargs.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
.. _callable_providers_delegation:
|
|
||||||
|
|
||||||
Callable providers delegation
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:py:class:`Callable` provider could be delegated to any other provider via
|
|
||||||
any kind of injection.
|
|
||||||
|
|
||||||
Delegation of :py:class:`Callable` providers is the same as
|
|
||||||
:py:class:`Factory` providers delegation, please follow
|
|
||||||
:ref:`factory_providers_delegation` section for examples (with exception
|
|
||||||
of using :py:class:`DelegatedCallable` instead of
|
|
||||||
:py:class:`DelegatedFactory`).
|
|
||||||
|
|
||||||
Abstract callable providers
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:py:class:`AbstractCallable` provider is a :py:class:`Callable` provider that
|
|
||||||
must be explicitly overridden before calling.
|
|
||||||
|
|
||||||
Behaviour of :py:class:`AbstractCallable` providers is the same as of
|
|
||||||
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
|
|
||||||
section for examples (with exception of using :py:class:`AbstractCallable`
|
|
||||||
provider instead of :py:class:`AbstractFactory`).
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
Configuration providers
|
Configuration provider
|
||||||
-----------------------
|
----------------------
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection,
|
||||||
|
Option,Ini,Json,Yaml,Dict,Environment Variable,Load,Read,Get
|
||||||
|
:description: Configuration provides configuration options to the other providers. This page
|
||||||
|
demonstrates how to use Configuration provider to inject the dependencies, load
|
||||||
|
a configuration from an ini or yaml file, dictionary or an environment variable.
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
|
@ -10,13 +17,13 @@ Configuration providers
|
||||||
:emphasize-lines: 4,9-10
|
:emphasize-lines: 4,9-10
|
||||||
:lines: 4-14
|
:lines: 4-14
|
||||||
|
|
||||||
It implements "use first, define later" principle.
|
It implements the principle "use first, define later".
|
||||||
|
|
||||||
Loading from ``ini`` file
|
Loading from an INI file
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
:py:class:`Configuration` provider can load configuration from ``ini`` file using
|
``Configuration`` provider can load configuration from an ``ini`` file using the
|
||||||
:py:meth:`Configuration.from_ini`:
|
:py:meth:`Configuration.from_ini` method:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_ini.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_ini.py
|
||||||
:language: python
|
:language: python
|
||||||
|
@ -28,15 +35,15 @@ where ``examples/providers/configuration/config.ini`` is:
|
||||||
.. literalinclude:: ../../examples/providers/configuration/config.ini
|
.. literalinclude:: ../../examples/providers/configuration/config.ini
|
||||||
:language: ini
|
:language: ini
|
||||||
|
|
||||||
:py:meth:`Configuration.from_ini` supports environment variables interpolation. Use
|
:py:meth:`Configuration.from_ini` method supports environment variables interpolation. Use
|
||||||
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
``${ENV_NAME}`` format in the configuration file to substitute value of the environment
|
||||||
variable ``ENV_NAME``.
|
variable ``ENV_NAME``.
|
||||||
|
|
||||||
Loading from ``yaml`` file
|
Loading from a YAML file
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
:py:class:`Configuration` provider can load configuration from ``yaml`` file using
|
``Configuration`` provider can load configuration from a ``yaml`` file using the
|
||||||
:py:meth:`Configuration.from_yaml`:
|
:py:meth:`Configuration.from_yaml` method:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_yaml.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_yaml.py
|
||||||
:language: python
|
:language: python
|
||||||
|
@ -48,43 +55,51 @@ where ``examples/providers/configuration/config.yml`` is:
|
||||||
.. literalinclude:: ../../examples/providers/configuration/config.yml
|
.. literalinclude:: ../../examples/providers/configuration/config.yml
|
||||||
:language: ini
|
:language: ini
|
||||||
|
|
||||||
:py:meth:`Configuration.from_yaml` supports environment variables interpolation. Use
|
:py:meth:`Configuration.from_yaml` method supports environment variables interpolation. Use
|
||||||
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
``${ENV_NAME}`` format in the configuration file to substitute value of the environment
|
||||||
variable ``ENV_NAME``.
|
variable ``ENV_NAME``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Loading configuration from yaml requires ``PyYAML`` package. You can install
|
Loading of a yaml configuration requires ``PyYAML`` package.
|
||||||
`Dependency Injector` with extras ``pip install dependency-injector[yaml]`` or install
|
|
||||||
``PyYAML`` separately ``pip install pyyaml``.
|
|
||||||
|
|
||||||
Loading from ``dict``
|
You can install the ``Dependency Injector`` with an extra dependency::
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:py:class:`Configuration` provider can load configuration from Python ``dict`` using
|
pip install dependency-injector[yaml]
|
||||||
:py:meth:`Configuration.from_dict`:
|
|
||||||
|
or install ``PyYAML`` directly::
|
||||||
|
|
||||||
|
pip install pyyaml
|
||||||
|
|
||||||
|
*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:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_dict.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_dict.py
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 3-5,6-
|
:lines: 3-5,6-
|
||||||
:emphasize-lines: 6-13
|
:emphasize-lines: 6-13
|
||||||
|
|
||||||
Loading from environment variable
|
Loading from an environment variable
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
:py:class:`Configuration` provider can load configuration from environment variable using
|
``Configuration`` provider can load configuration from an environment variable using the
|
||||||
:py:meth:`Configuration.from_env`:
|
:py:meth:`Configuration.from_env` method:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_env.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_env.py
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 5-7,13-21
|
:lines: 5-7,13-21
|
||||||
:emphasize-lines: 6-8
|
:emphasize-lines: 6-8
|
||||||
|
|
||||||
Loading from multiple sources
|
Loading from the multiple sources
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
:py:class:`Configuration` provider can load configuration from multiple sources. Loaded
|
``Configuration`` provider can load configuration from the multiple sources. Loaded
|
||||||
configuration is merged recursively over existing configuration.
|
configuration is merged recursively over the existing configuration.
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_multiple.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_multiple.py
|
||||||
:language: python
|
:language: python
|
||||||
|
@ -96,12 +111,12 @@ where ``examples/providers/configuration/config.local.yml`` is:
|
||||||
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
|
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
|
||||||
:language: ini
|
:language: ini
|
||||||
|
|
||||||
Specifying value type
|
Specifying the value type
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
You can specify the type of the injected configuration value explicitly.
|
You can specify the type of the injected configuration value explicitly.
|
||||||
|
|
||||||
This helps when you read the value from the ini file or the environment variable and need to
|
This helps when you read the value from an ini file or an environment variable and need to
|
||||||
convert it into an ``int`` or a ``float``.
|
convert it into an ``int`` or a ``float``.
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_type.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_type.py
|
||||||
|
@ -109,20 +124,20 @@ convert it into an ``int`` or a ``float``.
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
:emphasize-lines: 17
|
:emphasize-lines: 17
|
||||||
|
|
||||||
:py:class:`Configuration` provider has next helper methods:
|
``Configuration`` provider has next helper methods:
|
||||||
|
|
||||||
- ``.as_int()``
|
- ``.as_int()``
|
||||||
- ``.as_float()``
|
- ``.as_float()``
|
||||||
- ``.as_(callback, *args, **kwargs)``
|
- ``.as_(callback, *args, **kwargs)``
|
||||||
|
|
||||||
The last method ``.as_(callback, *args, **kwargs)`` helps to implement a other conversions.
|
The last method ``.as_(callback, *args, **kwargs)`` helps to implement other conversions.
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_type_custom.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_type_custom.py
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
:emphasize-lines: 16
|
:emphasize-lines: 16
|
||||||
|
|
||||||
With the ``.as_(callback, *args, **kwargs)`` you can specify the function that will be called
|
With the ``.as_(callback, *args, **kwargs)`` you can specify a function that will be called
|
||||||
before the injection. The value from the config will be passed as a first argument. The returned
|
before the injection. The value from the config will be passed as a first argument. The returned
|
||||||
value will be injected. Parameters ``*args`` and ``**kwargs`` are handled as any other injections.
|
value will be injected. Parameters ``*args`` and ``**kwargs`` are handled as any other injections.
|
||||||
|
|
||||||
|
|
|
@ -1,72 +1,27 @@
|
||||||
Coroutine providers
|
Coroutine provider
|
||||||
-------------------
|
------------------
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Coroutine,Asynchronous,
|
||||||
|
Asyncio,Example
|
||||||
|
:description: Coroutine provider creates a coroutine. This page demonstrates how to use a
|
||||||
|
Coroutine provider.
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
:py:class:`Coroutine` provider create wrapped coroutine on every call.
|
:py:class:`Coroutine` provider creates a coroutine.
|
||||||
|
|
||||||
:py:class:`Coroutine` provider is designed for making better integration with
|
.. literalinclude:: ../../examples/providers/coroutine.py
|
||||||
``asyncio`` coroutines. In particular, :py:class:`Coroutine` provider returns
|
|
||||||
``True`` for ``asyncio.iscoroutinefunction()`` checks.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
:py:class:`Coroutine` provider works only for Python 3.4+.
|
|
||||||
|
|
||||||
Example of usage :py:class:`Coroutine` provider with ``async / await``-based
|
|
||||||
coroutine:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/coroutine_async_await.py
|
|
||||||
:language: python
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
Coroutine providers and injections
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:py:class:`Coroutine` provider takes a various number of positional and keyword
|
|
||||||
arguments that are used as wrapped coroutine injections. Every time, when
|
|
||||||
:py:class:`Coroutine` provider is called, positional and keyword argument
|
|
||||||
injections would be passed as coroutine arguments.
|
|
||||||
|
|
||||||
Injections are done according to the next rules:
|
|
||||||
|
|
||||||
+ All providers (instances of :py:class:`Provider`) are called every time
|
|
||||||
when injection needs to be done.
|
|
||||||
+ Providers could be injected "as is" (delegated), if it is defined obviously.
|
|
||||||
Check out :ref:`coroutine_providers_delegation`.
|
|
||||||
+ All other injectable values are provided *"as is"*.
|
|
||||||
+ Positional context arguments will be appended after :py:class:`Coroutine`
|
|
||||||
positional injections.
|
|
||||||
+ Keyword context arguments have priority on :py:class:`Coroutine` keyword
|
|
||||||
injections and will be merged over them.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
The example works on Python 3.7+. For earlier versions use ``loop.run_until_complete()``.
|
||||||
|
|
||||||
Examples of making injections could be found in API docs -
|
``Coroutine`` provider handles an injection of the dependencies the same way like a
|
||||||
:py:class:`Coroutine`.
|
:ref:`factory-provider`.
|
||||||
|
|
||||||
.. _coroutine_providers_delegation:
|
.. note::
|
||||||
|
``Coroutine`` provider returns ``True`` for ``asyncio.iscoroutinefunction()`` check.
|
||||||
Coroutine providers delegation
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:py:class:`Coroutine` provider could be delegated to any other provider via
|
|
||||||
any kind of injection.
|
|
||||||
|
|
||||||
Delegation of :py:class:`Coroutine` providers is the same as
|
|
||||||
:py:class:`Factory` providers delegation, please follow
|
|
||||||
:ref:`factory_providers_delegation` section for examples (with exception
|
|
||||||
of using :py:class:`DelegatedCoroutine` instead of
|
|
||||||
:py:class:`DelegatedFactory`).
|
|
||||||
|
|
||||||
Abstract coroutine providers
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:py:class:`AbstractCoroutine` provider is a :py:class:`Coroutine` provider that
|
|
||||||
must be explicitly overridden before calling.
|
|
||||||
|
|
||||||
Behaviour of :py:class:`AbstractCoroutine` providers is the same as of
|
|
||||||
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
|
|
||||||
section for examples (with exception of using :py:class:`AbstractCoroutine`
|
|
||||||
provider instead of :py:class:`AbstractFactory`).
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,43 +1,21 @@
|
||||||
Dependency providers
|
Dependency provider
|
||||||
--------------------
|
-------------------
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
:py:class:`Dependency` provider can be useful for development of
|
:py:class:`Dependency` provider is a placeholder for the dependency of the specified type.
|
||||||
self-sufficient libraries / modules / applications that have required external
|
|
||||||
dependencies.
|
|
||||||
|
|
||||||
For example, you have created self-sufficient library / module / application,
|
The first argument of the ``Dependency`` provider specifies a type of the dependency. It is
|
||||||
that has dependency on *database connection*.
|
called ``instance_of``. ``Dependency`` provider controls the type of the returned object to be an
|
||||||
|
instance of the ``instance_of`` type.
|
||||||
|
|
||||||
Second step you want to do is to make this software component to be easy
|
The ``Dependency`` provider must be overridden before usage. It can be overridden by any type of
|
||||||
reusable by wide amount of developers and to be easily integrated into many
|
the provider. The only rule is that overriding provider must return an instance of ``instance_of``
|
||||||
applications.
|
dependency type.
|
||||||
|
|
||||||
It may be good idea, to move all external dependencies (like
|
|
||||||
*database connection*) to the top level and make them to be injected on your
|
|
||||||
software component's initialization. It will make third party developers feel
|
|
||||||
themselves free about integration of your component in their applications,
|
|
||||||
because they would be able to find right place / right way for doing this
|
|
||||||
in their application's architectures.
|
|
||||||
|
|
||||||
At the same time, you can be sure, that your external dependency will be
|
|
||||||
satisfied with appropriate instance.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Class ``UsersService`` is a part of some library. ``UsersService`` has
|
|
||||||
dependency on database connection, which can be satisfied with any
|
|
||||||
DBAPI 2.0 database connection. Being a self-sufficient library,
|
|
||||||
``UsersService`` doesn't hardcode any kind of database management logic.
|
|
||||||
Instead of this, ``UsersService`` has external dependency, that has to
|
|
||||||
be satisfied by client's code, out of library's scope.
|
|
||||||
|
|
||||||
.. image:: /images/providers/dependency.png
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/dependency.py
|
.. literalinclude:: ../../examples/providers/dependency.py
|
||||||
:language: python
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
|
:emphasize-lines: 26
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
List providers
|
List provider
|
||||||
--------------
|
-------------
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,List,Injection
|
||||||
|
:description: List provider helps to inject a list of the dependencies. This page demonstrates
|
||||||
|
how to use a List provider.
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
|
@ -7,28 +12,12 @@ List providers
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/list.py
|
.. literalinclude:: ../../examples/providers/list.py
|
||||||
:language: python
|
:language: python
|
||||||
:emphasize-lines: 6-9
|
|
||||||
:lines: 6-8, 23-29
|
|
||||||
|
|
||||||
:py:class:`List` provider is needed for injecting a list of dependencies. It handles
|
|
||||||
positional argument injections the same way as :py:class:`Factory` provider:
|
|
||||||
|
|
||||||
+ All providers (instances of :py:class:`Provider`) are called every time
|
|
||||||
when injection needs to be done.
|
|
||||||
+ Providers could be injected "as is" (delegated), if it is defined explicitly. Check out
|
|
||||||
:ref:`factory_providers_delegation`.
|
|
||||||
+ All other values are injected *"as is"*.
|
|
||||||
+ Positional context arguments will be appended after :py:class:`List` positional injections.
|
|
||||||
|
|
||||||
Full example:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/list.py
|
|
||||||
:language: python
|
|
||||||
:emphasize-lines: 23-26
|
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
|
:emphasize-lines: 19-22
|
||||||
|
|
||||||
|
``List`` provider handles positional arguments the same way as a :ref:`factory-provider`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
Keyword argument are not supported.
|
||||||
Keyword argument injections are not supported.
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
Object providers
|
Object provider
|
||||||
----------------
|
---------------
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Object
|
||||||
|
:description: Object provider provides an object "as is". This page demonstrates how to use an
|
||||||
|
Object provider.
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
:py:class:`Object` provider returns provided instance "as is".
|
:py:class:`Object` provider returns an object "as is".
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/object.py
|
.. literalinclude:: ../../examples/providers/object.py
|
||||||
:language: python
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -3,29 +3,31 @@
|
||||||
Selector providers
|
Selector providers
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection,
|
||||||
|
Selector,Polymorphism,Environment Variable,Flexibility
|
||||||
|
:description: Selector selects provider based on a configuration value or another callable.
|
||||||
|
This page demonstrates how to implement the polymorphism and increase the
|
||||||
|
flexibility of your application using the Selector provider.
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
:py:class:`Selector` provider selects provider based on the configuration value or other callable.
|
:py:class:`Selector` provider selects provider based on a configuration value or another callable.
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/selector.py
|
.. literalinclude:: ../../examples/providers/selector.py
|
||||||
:language: python
|
:language: python
|
||||||
:emphasize-lines: 6-10
|
|
||||||
:lines: 3-5,14-20
|
|
||||||
|
|
||||||
:py:class:`Selector` provider has a callable called ``selector`` and a dictionary of providers.
|
|
||||||
|
|
||||||
The ``selector`` callable is provided as a first positional argument. It can be
|
|
||||||
:py:class:`Configuration` provider or any other callable. It has to return a string value.
|
|
||||||
This value is used as a key for selecting the provider from the dictionary of providers.
|
|
||||||
|
|
||||||
The providers are provided as keyword arguments. Argument name is used as a key for
|
|
||||||
selecting the provider.
|
|
||||||
|
|
||||||
Full example:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/selector.py
|
|
||||||
:language: python
|
|
||||||
:emphasize-lines: 14-18
|
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
|
:emphasize-lines: 14-18
|
||||||
|
|
||||||
|
The first argument of the ``Selector`` provider is called ``selector``. It can be an option of
|
||||||
|
a ``Configuration`` provider or any other callable. The ``selector`` callable has to return a
|
||||||
|
string value. This value is used as a key for selecting the provider.
|
||||||
|
|
||||||
|
The providers are provided as keyword arguments. Argument name is used as a key for selecting the
|
||||||
|
provider.
|
||||||
|
|
||||||
|
When a ``Selector`` provider is called, it gets a ``selector`` value and delegates the work to
|
||||||
|
the provider with a matching name. The ``selector`` callable works as a switch: when the returned
|
||||||
|
value is changed the ``Selector`` provider will delegate the work to another provider.
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
18
examples/providers/callable.py
Normal file
18
examples/providers/callable.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
"""`Callable` provider example."""
|
||||||
|
|
||||||
|
import passlib.hash
|
||||||
|
|
||||||
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
|
password_hasher = providers.Callable(
|
||||||
|
passlib.hash.sha256_crypt.hash,
|
||||||
|
salt_size=16,
|
||||||
|
rounds=10000,
|
||||||
|
)
|
||||||
|
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
hashed_password = password_hasher('super secret')
|
||||||
|
assert password_verifier('super secret', hashed_password)
|
|
@ -1,16 +0,0 @@
|
||||||
"""`Callable` providers with positional arguments example."""
|
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
# Creating even and odd filter providers:
|
|
||||||
even_filter = providers.Callable(filter, lambda x: x % 2 == 0)
|
|
||||||
odd_filter = providers.Callable(filter, lambda x: x % 2 != 0)
|
|
||||||
|
|
||||||
# Creating even and odd ranges using range() and filter providers:
|
|
||||||
even_range = even_filter(range(1, 10))
|
|
||||||
odd_range = odd_filter(range(1, 10))
|
|
||||||
|
|
||||||
# Making some asserts:
|
|
||||||
assert even_range == [2, 4, 6, 8]
|
|
||||||
assert odd_range == [1, 3, 5, 7, 9]
|
|
|
@ -1,16 +0,0 @@
|
||||||
"""`Callable` providers with keyword arguments example."""
|
|
||||||
|
|
||||||
import passlib.hash
|
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
# Password hasher and verifier providers:
|
|
||||||
password_hasher = providers.Callable(passlib.hash.sha256_crypt.encrypt,
|
|
||||||
salt_size=16,
|
|
||||||
rounds=10000)
|
|
||||||
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
|
|
||||||
|
|
||||||
# Making some asserts:
|
|
||||||
hashed_password = password_hasher('super secret')
|
|
||||||
assert password_verifier('super secret', hashed_password)
|
|
|
@ -1,26 +1,19 @@
|
||||||
"""`Coroutine` providers example with @asyncio.coroutine decorator.
|
"""`Coroutine` providers example with async / await syntax."""
|
||||||
|
|
||||||
Current example works only fot Python 3.4+.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def coroutine(arg1, arg2):
|
||||||
def coroutine_function(arg1, arg2):
|
await asyncio.sleep(0.1)
|
||||||
"""Sample coroutine function."""
|
|
||||||
yield from asyncio.sleep(0.1)
|
|
||||||
return arg1, arg2
|
return arg1, arg2
|
||||||
|
|
||||||
|
|
||||||
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
|
coroutine_provider = providers.Coroutine(coroutine, arg1=1, arg2=2)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
loop = asyncio.get_event_loop()
|
arg1, arg2 = asyncio.run(coroutine_provider())
|
||||||
arg1, arg2 = loop.run_until_complete(coroutine_provider())
|
|
||||||
|
|
||||||
assert (arg1, arg2) == (1, 2)
|
assert (arg1, arg2) == (1, 2)
|
||||||
assert asyncio.iscoroutinefunction(coroutine_provider)
|
assert asyncio.iscoroutinefunction(coroutine_provider)
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
"""`Coroutine` providers example with async / await syntax.
|
|
||||||
|
|
||||||
Current example works only fot Python 3.5+.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
async def coroutine_function(arg1, arg2):
|
|
||||||
"""Sample coroutine function."""
|
|
||||||
await asyncio.sleep(0.1)
|
|
||||||
return arg1, arg2
|
|
||||||
|
|
||||||
|
|
||||||
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
arg1, arg2 = loop.run_until_complete(coroutine_provider())
|
|
||||||
|
|
||||||
assert (arg1, arg2) == (1, 2)
|
|
||||||
assert asyncio.iscoroutinefunction(coroutine_provider)
|
|
|
@ -1,73 +1,50 @@
|
||||||
"""`Dependency` providers example."""
|
"""`Dependency` provider example."""
|
||||||
|
|
||||||
import sqlite3
|
import abc
|
||||||
import contextlib
|
import dataclasses
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
from dependency_injector import containers, providers, errors
|
||||||
|
|
||||||
|
|
||||||
class UsersService:
|
class DbAdapter(metaclass=abc.ABCMeta):
|
||||||
"""Example class UsersService.
|
...
|
||||||
|
|
||||||
UsersService has dependency on DBAPI 2.0 database connection.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, database):
|
|
||||||
"""Initialize instance.
|
|
||||||
|
|
||||||
:param database: Database connection.
|
|
||||||
:type database: sqlite3.dbapi2.Connection
|
|
||||||
"""
|
|
||||||
self.database = database
|
|
||||||
self.database.row_factory = sqlite3.dbapi2.Row
|
|
||||||
|
|
||||||
def init_database(self):
|
|
||||||
"""Initialize database, if it has not been initialized yet."""
|
|
||||||
with contextlib.closing(self.database.cursor()) as cursor:
|
|
||||||
cursor.execute("""
|
|
||||||
CREATE TABLE IF NOT EXISTS users(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
name VARCHAR(32)
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
def create(self, name):
|
|
||||||
"""Create user with provided name and return his id."""
|
|
||||||
with contextlib.closing(self.database.cursor()) as cursor:
|
|
||||||
cursor.execute('INSERT INTO users(name) VALUES (?)', (name,))
|
|
||||||
return cursor.lastrowid
|
|
||||||
|
|
||||||
def get_by_id(self, id):
|
|
||||||
"""Return user info by user id."""
|
|
||||||
with contextlib.closing(self.database.cursor()) as cursor:
|
|
||||||
cursor.execute('SELECT id, name FROM users WHERE id=?', (id,))
|
|
||||||
return cursor.fetchone()
|
|
||||||
|
|
||||||
|
|
||||||
# Database and UsersService providers:
|
class SqliteDbAdapter(DbAdapter):
|
||||||
database = providers.Dependency(instance_of=sqlite3.dbapi2.Connection)
|
...
|
||||||
users_service_factory = providers.Factory(UsersService,
|
|
||||||
database=database)
|
|
||||||
|
|
||||||
# Out of library's scope.
|
|
||||||
#
|
|
||||||
# Setting database provider:
|
|
||||||
database.provided_by(providers.Singleton(sqlite3.dbapi2.Connection,
|
|
||||||
database=':memory:',
|
|
||||||
timeout=30,
|
|
||||||
detect_types=True,
|
|
||||||
isolation_level='EXCLUSIVE'))
|
|
||||||
|
|
||||||
# Creating UsersService instance:
|
class PostgresDbAdapter(DbAdapter):
|
||||||
users_service = users_service_factory()
|
...
|
||||||
|
|
||||||
# Initializing UsersService database:
|
|
||||||
users_service.init_database()
|
|
||||||
|
|
||||||
# Creating test user and retrieving full information about him:
|
@dataclasses.dataclass
|
||||||
test_user_id = users_service.create(name='test_user')
|
class UserService:
|
||||||
test_user = users_service.get_by_id(test_user_id)
|
database: DbAdapter
|
||||||
|
|
||||||
# Making some asserts:
|
|
||||||
assert test_user['id'] == 1
|
class Container(containers.DeclarativeContainer):
|
||||||
assert test_user['name'] == 'test_user'
|
|
||||||
|
database = providers.Dependency(instance_of=DbAdapter)
|
||||||
|
|
||||||
|
user_service = providers.Factory(
|
||||||
|
UserService,
|
||||||
|
database=database,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container1 = Container(database=providers.Singleton(SqliteDbAdapter))
|
||||||
|
container2 = Container(database=providers.Singleton(PostgresDbAdapter))
|
||||||
|
|
||||||
|
assert isinstance(container1.user_service().database, SqliteDbAdapter)
|
||||||
|
assert isinstance(container2.user_service().database, PostgresDbAdapter)
|
||||||
|
|
||||||
|
container3 = Container(database=providers.Singleton(object))
|
||||||
|
try:
|
||||||
|
container3.user_service()
|
||||||
|
except errors.Error as exception:
|
||||||
|
print(exception)
|
||||||
|
# The output is:
|
||||||
|
# <object object at 0x107ce5c40> is not an
|
||||||
|
# instance of <class '__main__.DbAdapter'>
|
||||||
|
|
|
@ -8,15 +8,11 @@ from dependency_injector import providers
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class Module:
|
class Module:
|
||||||
"""Example module."""
|
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class Dispatcher:
|
class Dispatcher:
|
||||||
"""Example dispatcher."""
|
|
||||||
|
|
||||||
modules: List[Module]
|
modules: List[Module]
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +24,7 @@ dispatcher_factory = providers.Factory(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
dispatcher = dispatcher_factory()
|
dispatcher = dispatcher_factory()
|
||||||
|
|
||||||
|
@ -35,11 +32,10 @@ if __name__ == '__main__':
|
||||||
assert dispatcher.modules[0].name == 'm1'
|
assert dispatcher.modules[0].name == 'm1'
|
||||||
assert dispatcher.modules[1].name == 'm2'
|
assert dispatcher.modules[1].name == 'm2'
|
||||||
|
|
||||||
# Call of dispatcher_factory() is equivalent to:
|
# Call "dispatcher = dispatcher_factory()" is an equivalent for:
|
||||||
|
# dispatcher = Dispatcher(
|
||||||
dispatcher = Dispatcher(
|
# modules=[
|
||||||
modules=[
|
# Module(name='m1'),
|
||||||
Module(name='m1'),
|
# Module(name='m2'),
|
||||||
Module(name='m2'),
|
# ],
|
||||||
],
|
# )
|
||||||
)
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
"""Object providers example."""
|
"""`Object` provider example."""
|
||||||
|
|
||||||
import dependency_injector.providers as providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
# Creating object provider:
|
|
||||||
object_provider = providers.Object(1)
|
object_provider = providers.Object(1)
|
||||||
|
|
||||||
# Making some asserts:
|
|
||||||
assert object_provider() == 1
|
if __name__ == '__main__':
|
||||||
|
assert object_provider() == 1
|
||||||
|
|
|
@ -19,10 +19,11 @@ selector = providers.Selector(
|
||||||
another=providers.Factory(SomeOtherClass),
|
another=providers.Factory(SomeOtherClass),
|
||||||
)
|
)
|
||||||
|
|
||||||
config.override({'one_or_another': 'one'})
|
if __name__ == '__main__':
|
||||||
instance_1 = selector()
|
config.override({'one_or_another': 'one'})
|
||||||
assert isinstance(instance_1, SomeClass)
|
instance_1 = selector()
|
||||||
|
assert isinstance(instance_1, SomeClass)
|
||||||
|
|
||||||
config.override({'one_or_another': 'another'})
|
config.override({'one_or_another': 'another'})
|
||||||
instance_2 = selector()
|
instance_2 = selector()
|
||||||
assert isinstance(instance_2, SomeOtherClass)
|
assert isinstance(instance_2, SomeOtherClass)
|
||||||
|
|
|
@ -24,6 +24,7 @@ class DynamicContainer(Container): ...
|
||||||
class DeclarativeContainer(Container):
|
class DeclarativeContainer(Container):
|
||||||
cls_providers: ClassVar[Dict[str, Provider]]
|
cls_providers: ClassVar[Dict[str, Provider]]
|
||||||
inherited_providers: ClassVar[Dict[str, Provider]]
|
inherited_providers: ClassVar[Dict[str, Provider]]
|
||||||
|
def __init__(self, **overriding_providers: Provider) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
def override(container: Container) -> _Callable[[Container], Container]: ...
|
def override(container: Container) -> _Callable[[Container], Container]: ...
|
||||||
|
|
Loading…
Reference in New Issue
Block a user