mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-01-30 19:24:31 +03:00
Merge branch 'release/3.35.0' into master
This commit is contained in:
commit
89fec6c905
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 42 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
|
@ -7,6 +7,12 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
3.35.0
|
||||
------
|
||||
- Update documentation and rework examples for: ``Singleton``, ``Callable``, ``Coroutine``,
|
||||
``Object``, ``List``, ``Configuration``, ``Selector``, and ``Dependency`` providers.
|
||||
- Fix mypy stub of the ``DeclarativeContainer`` to specify the ``__init__`` interface.
|
||||
|
||||
3.34.0
|
||||
------
|
||||
- Update ``Factory`` provider documentation.
|
||||
|
|
|
@ -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
|
||||
|
||||
: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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
: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
|
||||
.. literalinclude:: ../../examples/providers/callable.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Next one example shows usage of :py:class:`Callable` with keyword argument
|
||||
injections:
|
||||
|
||||
.. 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`).
|
||||
``Callable`` provider handles an injection of the dependencies the same way like a
|
||||
:ref:`factory-provider`.
|
||||
|
||||
.. 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
|
||||
|
||||
|
@ -10,13 +17,13 @@ Configuration providers
|
|||
:emphasize-lines: 4,9-10
|
||||
: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
|
||||
:py:meth:`Configuration.from_ini`:
|
||||
``Configuration`` provider can load configuration from an ``ini`` file using the
|
||||
:py:meth:`Configuration.from_ini` method:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_ini.py
|
||||
:language: python
|
||||
|
@ -28,15 +35,15 @@ where ``examples/providers/configuration/config.ini`` is:
|
|||
.. literalinclude:: ../../examples/providers/configuration/config.ini
|
||||
:language: ini
|
||||
|
||||
:py:meth:`Configuration.from_ini` supports environment variables interpolation. Use
|
||||
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
||||
:py:meth:`Configuration.from_ini` method supports environment variables interpolation. Use
|
||||
``${ENV_NAME}`` format in the configuration file to substitute value of the environment
|
||||
variable ``ENV_NAME``.
|
||||
|
||||
Loading from ``yaml`` file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Loading from a YAML file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Configuration` provider can load configuration from ``yaml`` file using
|
||||
:py:meth:`Configuration.from_yaml`:
|
||||
``Configuration`` provider can load configuration from a ``yaml`` file using the
|
||||
:py:meth:`Configuration.from_yaml` method:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_yaml.py
|
||||
:language: python
|
||||
|
@ -48,43 +55,51 @@ where ``examples/providers/configuration/config.yml`` is:
|
|||
.. literalinclude:: ../../examples/providers/configuration/config.yml
|
||||
:language: ini
|
||||
|
||||
:py:meth:`Configuration.from_yaml` supports environment variables interpolation. Use
|
||||
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
||||
:py:meth:`Configuration.from_yaml` method supports environment variables interpolation. Use
|
||||
``${ENV_NAME}`` format in the configuration file to substitute value of the environment
|
||||
variable ``ENV_NAME``.
|
||||
|
||||
.. note::
|
||||
|
||||
Loading configuration from yaml requires ``PyYAML`` package. You can install
|
||||
`Dependency Injector` with extras ``pip install dependency-injector[yaml]`` or install
|
||||
``PyYAML`` separately ``pip install pyyaml``.
|
||||
Loading of a yaml configuration requires ``PyYAML`` package.
|
||||
|
||||
Loading from ``dict``
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
You can install the ``Dependency Injector`` with an extra dependency::
|
||||
|
||||
:py:class:`Configuration` provider can load configuration from Python ``dict`` using
|
||||
:py:meth:`Configuration.from_dict`:
|
||||
pip install dependency-injector[yaml]
|
||||
|
||||
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
|
||||
:language: python
|
||||
:lines: 3-5,6-
|
||||
:emphasize-lines: 6-13
|
||||
|
||||
Loading from environment variable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Loading from an environment variable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Configuration` provider can load configuration from environment variable using
|
||||
:py:meth:`Configuration.from_env`:
|
||||
``Configuration`` provider can load configuration from an environment variable using the
|
||||
:py:meth:`Configuration.from_env` method:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_env.py
|
||||
:language: python
|
||||
:lines: 5-7,13-21
|
||||
: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 is merged recursively over existing configuration.
|
||||
``Configuration`` provider can load configuration from the multiple sources. Loaded
|
||||
configuration is merged recursively over the existing configuration.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_multiple.py
|
||||
:language: python
|
||||
|
@ -96,12 +111,12 @@ where ``examples/providers/configuration/config.local.yml`` is:
|
|||
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
|
||||
:language: ini
|
||||
|
||||
Specifying value type
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
Specifying the value type
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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``.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_type.py
|
||||
|
@ -109,20 +124,20 @@ convert it into an ``int`` or a ``float``.
|
|||
:lines: 3-
|
||||
:emphasize-lines: 17
|
||||
|
||||
:py:class:`Configuration` provider has next helper methods:
|
||||
``Configuration`` provider has next helper methods:
|
||||
|
||||
- ``.as_int()``
|
||||
- ``.as_float()``
|
||||
- ``.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
|
||||
:language: python
|
||||
:lines: 3-
|
||||
: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
|
||||
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
|
||||
|
||||
: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
|
||||
``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
|
||||
.. literalinclude:: ../../examples/providers/coroutine.py
|
||||
:language: python
|
||||
|
||||
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.
|
||||
:lines: 3-
|
||||
|
||||
.. 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 -
|
||||
:py:class:`Coroutine`.
|
||||
``Coroutine`` provider handles an injection of the dependencies the same way like a
|
||||
:ref:`factory-provider`.
|
||||
|
||||
.. _coroutine_providers_delegation:
|
||||
|
||||
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`).
|
||||
.. note::
|
||||
``Coroutine`` provider returns ``True`` for ``asyncio.iscoroutinefunction()`` check.
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,43 +1,21 @@
|
|||
Dependency providers
|
||||
--------------------
|
||||
Dependency provider
|
||||
-------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.providers
|
||||
|
||||
:py:class:`Dependency` provider can be useful for development of
|
||||
self-sufficient libraries / modules / applications that have required external
|
||||
dependencies.
|
||||
:py:class:`Dependency` provider is a placeholder for the dependency of the specified type.
|
||||
|
||||
For example, you have created self-sufficient library / module / application,
|
||||
that has dependency on *database connection*.
|
||||
The first argument of the ``Dependency`` provider specifies a type of the dependency. It is
|
||||
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
|
||||
reusable by wide amount of developers and to be easily integrated into many
|
||||
applications.
|
||||
|
||||
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
|
||||
The ``Dependency`` provider must be overridden before usage. It can be overridden by any type of
|
||||
the provider. The only rule is that overriding provider must return an instance of ``instance_of``
|
||||
dependency type.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/dependency.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 26
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
.. _factory-provider:
|
||||
|
||||
Factory provider
|
||||
----------------
|
||||
================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Factory,Abstract Factory,
|
||||
|
@ -100,6 +102,8 @@ attribute of the provider that you're going to inject.
|
|||
|
||||
.. note:: Any provider has a ``.provider`` attribute.
|
||||
|
||||
.. _factory-specialize-provided-type:
|
||||
|
||||
Specializing the provided type
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -112,6 +116,8 @@ class attribute.
|
|||
:lines: 3-
|
||||
:emphasize-lines: 12-14
|
||||
|
||||
.. _abstract-factory:
|
||||
|
||||
Abstract factory
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -7,28 +12,12 @@ List providers
|
|||
|
||||
.. literalinclude:: ../../examples/providers/list.py
|
||||
: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-
|
||||
:emphasize-lines: 19-22
|
||||
|
||||
``List`` provider handles positional arguments the same way as a :ref:`factory-provider`.
|
||||
|
||||
.. note::
|
||||
|
||||
Keyword argument injections are not supported.
|
||||
Keyword argument are not supported.
|
||||
|
||||
.. 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
|
||||
|
||||
:py:class:`Object` provider returns provided instance "as is".
|
||||
|
||||
Example:
|
||||
:py:class:`Object` provider returns an object "as is".
|
||||
|
||||
.. literalinclude:: ../../examples/providers/object.py
|
||||
:language: python
|
||||
|
||||
:lines: 3-
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -3,29 +3,31 @@
|
|||
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
|
||||
|
||||
: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
|
||||
: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-
|
||||
: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::
|
||||
|
|
|
@ -1,111 +1,100 @@
|
|||
Singleton providers
|
||||
-------------------
|
||||
Singleton provider
|
||||
------------------
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Singleton,Pattern,Example,
|
||||
Threads,Multithreading,Scoped
|
||||
:description: Singleton provider helps to provide a single object. This page
|
||||
demonstrates how to use a Singleton provider. It also provides the example
|
||||
of using a singleton and thread locals singleton in the multi-threaded
|
||||
environment.
|
||||
|
||||
.. currentmodule:: dependency_injector.providers
|
||||
|
||||
:py:class:`Singleton` provider creates new instance of specified class on
|
||||
first call and returns same instance on every next call.
|
||||
|
||||
Example:
|
||||
|
||||
.. image:: /images/providers/singleton.png
|
||||
:width: 80%
|
||||
:align: center
|
||||
:py:class:`Singleton` provider provides single object. It memorizes the first created object and
|
||||
returns it on the rest of the calls.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/singleton.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Singleton providers resetting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Created and memorized by :py:class:`Singleton` instance can be reset. Reset of
|
||||
:py:class:`Singleton`'s memorized instance is done by clearing reference to
|
||||
it. Further lifecycle of memorized instance is out of :py:class:`Singleton`
|
||||
provider's control and depends on garbage collection strategy.
|
||||
|
||||
Example:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/singleton_resetting.py
|
||||
:language: python
|
||||
|
||||
Singleton providers and injections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Singleton` provider has same interface as :py:class:`Factory`
|
||||
provider, so, all of the rules about injections are the same, as for
|
||||
:py:class:`Factory` provider.
|
||||
``Singleton`` provider handles an injection of the dependencies the same way like a
|
||||
:ref:`factory-provider`.
|
||||
|
||||
.. note::
|
||||
|
||||
Due that :py:class:`Singleton` provider creates specified class instance
|
||||
only on the first call, all injections are done once, during the first
|
||||
call. Every next call, while instance has been already created
|
||||
and memorized, no injections are done, :py:class:`Singleton` provider just
|
||||
returns memorized earlier instance.
|
||||
``Singleton`` provider does dependencies injection only when creates the object. When the object
|
||||
is created and memorized ``Singleton`` provider just returns it without applying the injections.
|
||||
|
||||
This may cause some problems, for example, in case of trying to bind
|
||||
:py:class:`Factory` provider with :py:class:`Singleton` provider (provided
|
||||
by dependent :py:class:`Factory` instance will be injected only once,
|
||||
during the first call). Be aware that such behaviour was made with opened
|
||||
eyes and is not a bug.
|
||||
Specialization of the provided type and abstract singletons work the same like like for the
|
||||
factories:
|
||||
|
||||
By the way, in such case, :py:class:`Delegate` or
|
||||
:py:class:`DelegatedSingleton` provider can be useful
|
||||
. It makes possible to inject providers *as is*. Please check out
|
||||
`Singleton providers delegation`_ section.
|
||||
- :ref:`factory-specialize-provided-type`
|
||||
- :ref:`abstract-factory`
|
||||
|
||||
Singleton providers delegation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Resetting memorized object
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Singleton` provider could be delegated to any other provider via
|
||||
any kind of injection.
|
||||
To reset a memorized object you need to call the ``.reset()`` method of the ``Singleton``
|
||||
provider.
|
||||
|
||||
Delegation of :py:class:`Singleton` 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:`DelegatedSingleton` instead of
|
||||
:py:class:`DelegatedFactory`).
|
||||
.. literalinclude:: ../../examples/providers/singleton_resetting.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 14
|
||||
|
||||
Singleton providers specialization
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.. note::
|
||||
Resetting of the memorized object clears the reference to it. Further object's lifecycle is
|
||||
managed by the garbage collector.
|
||||
|
||||
:py:class:`Singleton` provider could be specialized for any kind of needs via
|
||||
declaring its subclasses.
|
||||
Using singleton with multiple threads
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Specialization of :py:class:`Singleton` providers is the same as
|
||||
:py:class:`Factory` providers specialization, please follow
|
||||
:ref:`factory_providers_specialization` section for examples.
|
||||
``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
|
||||
into the race condition problem: ``Singleton`` will create multiple objects.
|
||||
|
||||
Abstract singleton providers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
There are two thread-safe singleton implementations out of the box:
|
||||
|
||||
:py:class:`AbstractSingleton` provider is a :py:class:`Singleton` provider that
|
||||
must be explicitly overridden before calling.
|
||||
|
||||
Behaviour of :py:class:`AbstractSingleton` providers is the same as of
|
||||
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
|
||||
section for examples (with exception of using :py:class:`AbstractSingleton`
|
||||
provider instead of :py:class:`AbstractFactory`).
|
||||
|
||||
Singleton providers and multi-threading
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Singleton` provider is NOT thread-safe and should be used in
|
||||
multi-threading applications with manually controlled locking.
|
||||
|
||||
:py:class:`ThreadSafeSingleton` is a thread-safe version of
|
||||
:py:class:`Singleton` and could be used in multi-threading applications
|
||||
without any additional locking.
|
||||
|
||||
Also there could be a need to use thread-scoped singletons and there is a
|
||||
special provider for such case - :py:class:`ThreadLocalSingleton`.
|
||||
:py:class:`ThreadLocalSingleton` provider creates instance once for each
|
||||
thread and returns it on every call.
|
||||
|
||||
Example:
|
||||
+ :py:class:`ThreadSafeSingleton` - is a thread-safe version of a ``Singleton`` provider. You can use
|
||||
in multi-threading applications without additional synchronization.
|
||||
+ :py:class:`ThreadLocalSingleton` - is a singleton provider that uses thread-locals as a storage.
|
||||
This type of singleton will manage multiple objects - the one object for the one thread.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/singleton_thread_locals.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 11,12
|
||||
|
||||
Implementing scopes
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To implement a scoped singleton provider use a ``Singleton`` provider and reset its scope when
|
||||
needed.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/singleton_scoped.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
The output should look like this (each request a ``Service`` object has a different address):
|
||||
|
||||
.. code-block::
|
||||
|
||||
* Serving Flask app "singleton_scoped" (lazy loading)
|
||||
* Environment: production
|
||||
WARNING: This is a development server. Do not use it in a production deployment.
|
||||
Use a production WSGI server instead.
|
||||
* Debug mode: off
|
||||
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
|
||||
<__main__.Service object at 0x1099a9d90>
|
||||
127.0.0.1 - - [25/Aug/2020 17:33:11] "GET / HTTP/1.1" 200 -
|
||||
<__main__.Service object at 0x1099a9cd0>
|
||||
127.0.0.1 - - [25/Aug/2020 17:33:17] "GET / HTTP/1.1" 200 -
|
||||
<__main__.Service object at 0x1099a9d00>
|
||||
127.0.0.1 - - [25/Aug/2020 17:33:18] "GET / HTTP/1.1" 200 -
|
||||
<__main__.Service object at 0x1099a9e50>
|
||||
127.0.0.1 - - [25/Aug/2020 17:33:18] "GET / HTTP/1.1" 200 -
|
||||
<__main__.Service object at 0x1099a9d90>
|
||||
127.0.0.1 - - [25/Aug/2020 17:33:18] "GET / HTTP/1.1" 200 -
|
||||
|
||||
.. 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.
|
||||
|
||||
Current example works only fot Python 3.4+.
|
||||
"""
|
||||
"""`Coroutine` providers example with async / await syntax."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def coroutine_function(arg1, arg2):
|
||||
"""Sample coroutine function."""
|
||||
yield from asyncio.sleep(0.1)
|
||||
async def coroutine(arg1, arg2):
|
||||
await asyncio.sleep(0.1)
|
||||
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__':
|
||||
loop = asyncio.get_event_loop()
|
||||
arg1, arg2 = loop.run_until_complete(coroutine_provider())
|
||||
|
||||
arg1, arg2 = asyncio.run(coroutine_provider())
|
||||
assert (arg1, arg2) == (1, 2)
|
||||
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 contextlib
|
||||
import abc
|
||||
import dataclasses
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import containers, providers, errors
|
||||
|
||||
|
||||
class UsersService:
|
||||
"""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()
|
||||
class DbAdapter(metaclass=abc.ABCMeta):
|
||||
...
|
||||
|
||||
|
||||
# Database and UsersService providers:
|
||||
database = providers.Dependency(instance_of=sqlite3.dbapi2.Connection)
|
||||
users_service_factory = providers.Factory(UsersService,
|
||||
database=database)
|
||||
class SqliteDbAdapter(DbAdapter):
|
||||
...
|
||||
|
||||
# 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:
|
||||
users_service = users_service_factory()
|
||||
class PostgresDbAdapter(DbAdapter):
|
||||
...
|
||||
|
||||
# Initializing UsersService database:
|
||||
users_service.init_database()
|
||||
|
||||
# Creating test user and retrieving full information about him:
|
||||
test_user_id = users_service.create(name='test_user')
|
||||
test_user = users_service.get_by_id(test_user_id)
|
||||
@dataclasses.dataclass
|
||||
class UserService:
|
||||
database: DbAdapter
|
||||
|
||||
# Making some asserts:
|
||||
assert test_user['id'] == 1
|
||||
assert test_user['name'] == 'test_user'
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
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'>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""`Factory` providers example."""
|
||||
"""`Factory` provider example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""`Factory` providers delegation example."""
|
||||
"""`Factory` provider delegation example."""
|
||||
|
||||
from typing import Callable, List
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""`Factory` providers init injections example."""
|
||||
"""`Factory` provider init injections example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""`Factory` providers - building a complex object graph with deep init injections example."""
|
||||
"""`Factory` provider - passing injections to the underlying providers example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
|
|
@ -8,15 +8,11 @@ from dependency_injector import providers
|
|||
|
||||
@dataclasses.dataclass
|
||||
class Module:
|
||||
"""Example module."""
|
||||
|
||||
name: str
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Dispatcher:
|
||||
"""Example dispatcher."""
|
||||
|
||||
modules: List[Module]
|
||||
|
||||
|
||||
|
@ -28,6 +24,7 @@ dispatcher_factory = providers.Factory(
|
|||
),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
dispatcher = dispatcher_factory()
|
||||
|
||||
|
@ -35,11 +32,10 @@ if __name__ == '__main__':
|
|||
assert dispatcher.modules[0].name == 'm1'
|
||||
assert dispatcher.modules[1].name == 'm2'
|
||||
|
||||
# Call of dispatcher_factory() is equivalent to:
|
||||
|
||||
dispatcher = Dispatcher(
|
||||
modules=[
|
||||
Module(name='m1'),
|
||||
Module(name='m2'),
|
||||
],
|
||||
)
|
||||
# Call "dispatcher = dispatcher_factory()" is an equivalent for:
|
||||
# dispatcher = Dispatcher(
|
||||
# modules=[
|
||||
# Module(name='m1'),
|
||||
# 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)
|
||||
|
||||
# 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),
|
||||
)
|
||||
|
||||
config.override({'one_or_another': 'one'})
|
||||
instance_1 = selector()
|
||||
assert isinstance(instance_1, SomeClass)
|
||||
if __name__ == '__main__':
|
||||
config.override({'one_or_another': 'one'})
|
||||
instance_1 = selector()
|
||||
assert isinstance(instance_1, SomeClass)
|
||||
|
||||
config.override({'one_or_another': 'another'})
|
||||
instance_2 = selector()
|
||||
assert isinstance(instance_2, SomeOtherClass)
|
||||
config.override({'one_or_another': 'another'})
|
||||
instance_2 = selector()
|
||||
assert isinstance(instance_2, SomeOtherClass)
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
"""`Singleton` providers example."""
|
||||
"""`Singleton` provider example."""
|
||||
|
||||
import collections
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
UsersService = collections.namedtuple('UsersService', [])
|
||||
class UserService:
|
||||
...
|
||||
|
||||
# Singleton provider creates new instance of specified class on first call
|
||||
# and returns same instance on every next call.
|
||||
users_service_provider = providers.Singleton(UsersService)
|
||||
|
||||
# Retrieving several UserService objects:
|
||||
users_service1 = users_service_provider()
|
||||
users_service2 = users_service_provider()
|
||||
user_service_provider = providers.Singleton(UserService)
|
||||
|
||||
# Making some asserts:
|
||||
assert users_service1 is users_service2
|
||||
|
||||
if __name__ == '__main__':
|
||||
user_service1 = user_service_provider()
|
||||
user_service2 = user_service_provider()
|
||||
assert user_service1 is user_service2
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
"""`Singleton` specialization for limitation to provided type example."""
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
import dependency_injector.errors as errors
|
||||
|
||||
|
||||
class BaseService:
|
||||
"""Base service class."""
|
||||
|
||||
|
||||
class UsersService(BaseService):
|
||||
"""Users service."""
|
||||
|
||||
|
||||
class PhotosService(BaseService):
|
||||
"""Photos service."""
|
||||
|
||||
|
||||
class ServiceProvider(providers.Singleton):
|
||||
"""Service provider."""
|
||||
|
||||
provided_type = BaseService
|
||||
|
||||
|
||||
# Creating several service providers with BaseService instances:
|
||||
users_service_provider = ServiceProvider(UsersService)
|
||||
photos_service_provider = ServiceProvider(PhotosService)
|
||||
|
||||
# Trying to create service provider with not a BaseService instance:
|
||||
try:
|
||||
some_service_provider = ServiceProvider(object)
|
||||
except errors.Error as exception:
|
||||
print(exception)
|
||||
# <class '__main__.ServiceProvider'> can provide only
|
||||
# <class '__main__.BaseService'> instances
|
|
@ -1,27 +1,19 @@
|
|||
"""`Singleton` providers resetting example."""
|
||||
"""`Singleton` provider resetting example."""
|
||||
|
||||
import collections
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
UsersService = collections.namedtuple('UsersService', [])
|
||||
class UserService:
|
||||
...
|
||||
|
||||
# Users service singleton provider:
|
||||
users_service_provider = providers.Singleton(UsersService)
|
||||
|
||||
# Retrieving several UsersService objects:
|
||||
users_service1 = users_service_provider()
|
||||
users_service2 = users_service_provider()
|
||||
user_service_provider = providers.Singleton(UserService)
|
||||
|
||||
# Making some asserts:
|
||||
assert users_service1 is users_service2
|
||||
|
||||
# Resetting of memorized instance:
|
||||
users_service_provider.reset()
|
||||
if __name__ == '__main__':
|
||||
user_service1 = user_service_provider()
|
||||
|
||||
# Retrieving one more UserService object:
|
||||
users_service3 = users_service_provider()
|
||||
user_service_provider.reset()
|
||||
|
||||
# Making some asserts:
|
||||
assert users_service3 is not users_service1
|
||||
users_service2 = user_service_provider()
|
||||
assert users_service2 is not user_service1
|
||||
|
|
32
examples/providers/singleton_scoped.py
Normal file
32
examples/providers/singleton_scoped.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
"""`Singleton` - flask request scope example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from flask import Flask
|
||||
|
||||
|
||||
class Service:
|
||||
...
|
||||
|
||||
|
||||
service_provider = providers.Singleton(Service)
|
||||
|
||||
|
||||
def index_view():
|
||||
service_1 = service_provider()
|
||||
service_2 = service_provider()
|
||||
assert service_1 is service_2
|
||||
print(service_1)
|
||||
return 'Hello World!'
|
||||
|
||||
|
||||
def teardown_context(request):
|
||||
service_provider.reset()
|
||||
return request
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
app.add_url_rule('/', 'index', view_func=index_view)
|
||||
app.after_request(teardown_context)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
|
@ -1,53 +1,42 @@
|
|||
"""`ThreadLocalSingleton` providers example."""
|
||||
"""`ThreadLocalSingleton` provider example."""
|
||||
|
||||
import threading
|
||||
import queue
|
||||
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
def example(example_object, queue_object):
|
||||
"""Put provided object in the provided queue."""
|
||||
def put_in_queue(example_object, queue_object):
|
||||
queue_object.put(example_object)
|
||||
|
||||
|
||||
# Create thread-local singleton provider for some object (main thread):
|
||||
thread_local_object = providers.ThreadLocalSingleton(object)
|
||||
|
||||
# Create singleton provider for thread-safe queue:
|
||||
queue_factory = providers.ThreadSafeSingleton(queue.Queue)
|
||||
|
||||
# Create callable provider for example(), inject dependencies:
|
||||
example = providers.DelegatedCallable(
|
||||
example,
|
||||
queue_provider = providers.ThreadSafeSingleton(queue.Queue)
|
||||
put_in_queue = providers.Callable(
|
||||
put_in_queue,
|
||||
example_object=thread_local_object,
|
||||
queue_object=queue_factory,
|
||||
queue_object=queue_provider,
|
||||
)
|
||||
thread_factory = providers.Factory(
|
||||
threading.Thread,
|
||||
target=put_in_queue.provider,
|
||||
)
|
||||
|
||||
# Create factory for threads that are targeted to execute example():
|
||||
thread_factory = providers.Factory(threading.Thread, target=example)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Create 10 threads for concurrent execution of example():
|
||||
threads = []
|
||||
for thread_number in range(10):
|
||||
threads.append(
|
||||
thread_factory(name='Thread{0}'.format(thread_number)),
|
||||
)
|
||||
|
||||
# Start execution of all created threads:
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
# Wait while threads would complete their work:
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
# Making some asserts (main thread):
|
||||
all_objects = set()
|
||||
|
||||
while not queue_factory().empty():
|
||||
all_objects.add(queue_factory().get())
|
||||
while not queue_provider().empty():
|
||||
all_objects.add(queue_provider().get())
|
||||
|
||||
assert len(all_objects) == len(threads)
|
||||
# Queue contains same number of objects as number of threads where
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Dependency injector top-level package."""
|
||||
|
||||
__version__ = '3.34.0'
|
||||
__version__ = '3.35.0'
|
||||
"""Version number that follows semantic versioning.
|
||||
|
||||
:type: str
|
||||
|
|
|
@ -24,6 +24,7 @@ class DynamicContainer(Container): ...
|
|||
class DeclarativeContainer(Container):
|
||||
cls_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]: ...
|
||||
|
|
Loading…
Reference in New Issue
Block a user