mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-26 11:33:58 +03:00
Merge branch 'release/3.37.0' into master
This commit is contained in:
commit
2cf5efa031
|
@ -52,7 +52,7 @@ What is ``Dependency Injector``?
|
|||
|
||||
``Dependency Injector`` is a dependency injection framework for Python.
|
||||
|
||||
It helps you in implementing the dependency injection principle.
|
||||
It helps implementing the dependency injection principle.
|
||||
|
||||
What is dependency injection?
|
||||
-----------------------------
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _containers:
|
||||
|
||||
Containers
|
||||
==========
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.1 KiB |
|
@ -64,22 +64,49 @@ Dependency Injector --- Dependency injection framework for Python
|
|||
|
||||
``Dependency Injector`` is a dependency injection framework for Python.
|
||||
|
||||
It stands on two principles:
|
||||
It helps implementing the dependency injection principle.
|
||||
|
||||
- Explicit is better than implicit (PEP20).
|
||||
- Do no magic to your code.
|
||||
Key features of the ``Dependency Injector``:
|
||||
|
||||
How does it different from the other frameworks?
|
||||
- **Providers**. Provides ``Factory``, ``Singleton``, ``Callable``, ``Coroutine``, ``Object``,
|
||||
``List``, ``Configuration``, ``Dependency`` and ``Selector`` providers that help assembling your
|
||||
objects. See :ref:`providers`.
|
||||
- **Overriding**. Can override any provider by another provider on the fly. This helps in testing
|
||||
and configuring dev / stage environment to replace API clients with stubs etc. See
|
||||
:ref:`provider-overriding`.
|
||||
- **Configuration**. Read configuration from ``yaml`` & ``ini`` files, environment variables
|
||||
and dictionaries. See :ref:`configuration-provider`.
|
||||
- **Containers**. Provides declarative and dynamic containers. See :ref:`containers`.
|
||||
- **Performance**. Fast. Written in ``Cython``.
|
||||
- **Maturity**. Mature and production-ready. Well-tested, documented and supported.
|
||||
|
||||
- **No autowiring.** The framework does NOT do any autowiring / autoresolving of the dependencies. You need to specify everything explicitly. Because *"Explicit is better than implicit" (PEP20)*.
|
||||
- **Does not pollute your code.** Your application does NOT know and does NOT depend on the framework. No ``@inject`` decorators, annotations, patching or any other magic tricks.
|
||||
.. code-block:: python
|
||||
|
||||
``Dependency Injector`` makes a simple contract with you:
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
- You tell the framework how to assemble your objects
|
||||
- The framework does it for you
|
||||
|
||||
The power of the ``Dependency Injector`` is in its simplicity and straightforwardness. It is a simple tool for the powerful concept.
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
api_client = providers.Singleton(
|
||||
ApiClient,
|
||||
api_key=config.api_key,
|
||||
timeout=config.timeout.as_int(),
|
||||
)
|
||||
|
||||
service = providers.Factory(
|
||||
Service,
|
||||
api_client=api_client,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
container.config.api_key.from_env('API_KEY')
|
||||
container.config.timeout.from_env('TIMEOUT')
|
||||
|
||||
service = container.service()
|
||||
|
||||
With the ``Dependency Injector`` you keep **application structure in one place**.
|
||||
This place is called **the container**. You use the container to manage all the components of the
|
||||
|
|
|
@ -17,4 +17,3 @@ dependency injection pattern, inversion of control principle and
|
|||
what_is_di
|
||||
di_in_python
|
||||
key_features
|
||||
structure
|
||||
|
|
|
@ -3,66 +3,33 @@ Key features
|
|||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
||||
:description: This article describes key features of "Dependency Injector"
|
||||
framework. It also provides some cases and recommendations
|
||||
about usage of "Dependency Injector" framework.
|
||||
:description: This article describes key features of the Dependency Injector
|
||||
framework.
|
||||
|
||||
Key features of the ``Dependency Injector``:
|
||||
|
||||
``Dependency Injector`` is a dependency injection framework for Python.
|
||||
It was designed to be a unified and developer-friendly tool that helps
|
||||
implement a dependency injection design pattern in a formal, pretty, and
|
||||
Pythonic way.
|
||||
- **Providers**. Provides ``Factory``, ``Singleton``, ``Callable``, ``Coroutine``, ``Object``,
|
||||
``List``, ``Configuration``, ``Dependency`` and ``Selector`` providers that help assembling your
|
||||
objects. See :ref:`providers`.
|
||||
- **Overriding**. Can override any provider by another provider on the fly. This helps in testing
|
||||
and configuring dev / stage environment to replace API clients with stubs etc. See
|
||||
:ref:`provider-overriding`.
|
||||
- **Configuration**. Read configuration from ``yaml`` & ``ini`` files, environment variables
|
||||
and dictionaries. See :ref:`configuration-provider`.
|
||||
- **Containers**. Provides declarative and dynamic containers. See :ref:`containers`.
|
||||
- **Performance**. Fast. Written in ``Cython``.
|
||||
- **Maturity**. Mature and production-ready. Well-tested, documented and supported.
|
||||
|
||||
It stands on two principles:
|
||||
The framework stands on two principles:
|
||||
|
||||
- Explicit is better than implicit (PEP20).
|
||||
- Do no magic to your code.
|
||||
- **Explicit is better than implicit (PEP20)**.
|
||||
- **Do not do any magic to your code**.
|
||||
|
||||
How does it different from the other frameworks?
|
||||
How is that different from the other frameworks?
|
||||
|
||||
- **No autowiring.** The framework does NOT do any autowiring / autoresolving of the dependencies. You need to specify everything explicitly. Because *"Explicit is better than implicit" (PEP20)*.
|
||||
- **Does not pollute your code.** Your application does NOT know and does NOT depend on the framework. No ``@inject`` decorators, annotations, patching or any other magic tricks.
|
||||
|
||||
``Dependency Injector`` makes a simple contract with you:
|
||||
|
||||
- You tell the framework how to build you code
|
||||
- The framework does it for you
|
||||
|
||||
The power of the ``Dependency Injector`` is in its simplicity and straightforwardness. It is a simple tool for the powerful concept.
|
||||
|
||||
The key features of the ``Dependency Injector`` framework are:
|
||||
|
||||
+ Easy, smart, and Pythonic style.
|
||||
+ Does NOT pollute client code.
|
||||
+ Obvious and clear structure.
|
||||
+ Extensibility and flexibility.
|
||||
+ High performance.
|
||||
+ Memory efficiency.
|
||||
+ Thread safety.
|
||||
+ Documented.
|
||||
+ Semantically versioned.
|
||||
+ Distributed as pre-compiled wheels.
|
||||
|
||||
``Dependency Injector`` containers and providers are implemented as C extension
|
||||
types using ``Cython``.
|
||||
|
||||
``Dependency Injector`` framework can be used in the different application types:
|
||||
|
||||
+ Web applications based on the ``Flask``, ``Django`` or any other web framework.
|
||||
+ Asynchronous applications ``asyncio``, ``aiohttp``, ``Tornado``, or ``Twisted``.
|
||||
+ Standalone frameworks and libraries.
|
||||
+ GUI applications.
|
||||
|
||||
``Dependency Injector`` framework can be integrated on the different project
|
||||
stages:
|
||||
|
||||
+ It can be used in the beginning of the development of a new application.
|
||||
+ It can be integrated into application that is on its active development stage.
|
||||
+ It can be used for refactoring of legacy application.
|
||||
|
||||
Components of ``Dependency Injector`` framework could be used:
|
||||
|
||||
+ In composition with each other.
|
||||
+ Independently from each other.
|
||||
The power of the framework is in a simplicity. ``Dependency Injector`` is a simple tool for the powerful concept.
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
Structure of Dependency Injector
|
||||
--------------------------------
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
||||
:description: This article describes "Dependency Injector" framework
|
||||
components and their interaction between each other.
|
||||
Providers and containers are the former components of
|
||||
the framework.
|
||||
|
||||
Current section describes *Dependency Injector* main entities and their
|
||||
interaction between each other.
|
||||
|
||||
.. image:: /images/internals.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
There are 2 main entities: providers & containers.
|
||||
|
||||
Providers
|
||||
~~~~~~~~~
|
||||
|
||||
Providers are strategies of accessing objects. For example,
|
||||
:py:class:`dependency_injector.providers.Factory` creates new instance
|
||||
of provided class every time it is called.
|
||||
:py:class:`dependency_injector.providers.Singleton` creates provided
|
||||
instance once and returns it on every next call. Base class is -
|
||||
:py:class:`dependency_injector.providers.Provider`.
|
||||
|
||||
Providers could be:
|
||||
|
||||
+ Injected into each other.
|
||||
+ Overridden by each other.
|
||||
+ Extended.
|
||||
|
||||
Containers
|
||||
~~~~~~~~~~
|
||||
|
||||
Containers are collections of providers. They are used for grouping
|
||||
of providers by some principles. Base class is -
|
||||
:py:class:`dependency_injector.containers.DeclarativeContainer`.
|
||||
|
||||
Containers could be:
|
||||
|
||||
+ Overridden by each other.
|
||||
+ Copied from each other.
|
||||
+ Extended.
|
||||
|
||||
|
||||
.. disqus::
|
|
@ -7,6 +7,14 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
3.37.0
|
||||
------
|
||||
- Update index documentation page.
|
||||
- Make multiple improvements and fixes for the providers documentation.
|
||||
- Update "Key Features" documentation page.
|
||||
- Remove "Structure of Dependency Injector" documentation page.
|
||||
- Edit "Feedback" documentation page.
|
||||
|
||||
3.36.0
|
||||
------
|
||||
- Update providers overriding documentation and rework examples.
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
Feedback
|
||||
========
|
||||
|
||||
Feel free to post questions, bugs, feature requests, proposals etc. on
|
||||
*Dependency Injector* GitHub Issues:
|
||||
|
||||
https://github.com/ets-labs/python-dependency-injector/issues
|
||||
|
||||
Your feedback is quite important!
|
||||
|
||||
To post a question, bug report, a feature proposal or get some help open a
|
||||
`Github Issue <https://github.com/ets-labs/python-dependency-injector/issues>`_ or leave a comment
|
||||
below.
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _configuration-provider:
|
||||
|
||||
Configuration provider
|
||||
======================
|
||||
|
||||
|
@ -14,8 +16,8 @@ Configuration provider
|
|||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration.py
|
||||
:language: python
|
||||
:emphasize-lines: 4,9-10
|
||||
:lines: 4-14
|
||||
:emphasize-lines: 7,12-13
|
||||
:lines: 3-
|
||||
|
||||
It implements the principle "use first, define later".
|
||||
|
||||
|
@ -27,8 +29,8 @@ Loading from an INI file
|
|||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_ini.py
|
||||
:language: python
|
||||
:lines: 3-5,6-
|
||||
:emphasize-lines: 6
|
||||
:lines: 3-
|
||||
:emphasize-lines: 12
|
||||
|
||||
where ``examples/providers/configuration/config.ini`` is:
|
||||
|
||||
|
@ -47,8 +49,8 @@ Loading from a YAML file
|
|||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_yaml.py
|
||||
:language: python
|
||||
:lines: 3-5,6-
|
||||
:emphasize-lines: 6
|
||||
:lines: 3-
|
||||
:emphasize-lines: 12
|
||||
|
||||
where ``examples/providers/configuration/config.yml`` is:
|
||||
|
||||
|
@ -81,8 +83,8 @@ Loading from a dictionary
|
|||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_dict.py
|
||||
:language: python
|
||||
:lines: 3-5,6-
|
||||
:emphasize-lines: 6-13
|
||||
:lines: 3-
|
||||
:emphasize-lines: 12-19
|
||||
|
||||
Loading from an environment variable
|
||||
------------------------------------
|
||||
|
@ -92,8 +94,8 @@ Loading from an environment variable
|
|||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_env.py
|
||||
:language: python
|
||||
:lines: 5-7,13-21
|
||||
:emphasize-lines: 6-8
|
||||
:lines: 3-
|
||||
:emphasize-lines: 18-20
|
||||
|
||||
Loading from the multiple sources
|
||||
---------------------------------
|
||||
|
@ -103,8 +105,8 @@ configuration is merged recursively over the existing configuration.
|
|||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_multiple.py
|
||||
:language: python
|
||||
:lines: 3-5,6-14
|
||||
:emphasize-lines: 6-7
|
||||
:lines: 3-
|
||||
:emphasize-lines: 12-13
|
||||
|
||||
where ``examples/providers/configuration/config.local.yml`` is:
|
||||
|
||||
|
@ -122,7 +124,7 @@ convert it into an ``int`` or a ``float``.
|
|||
.. literalinclude:: ../../examples/providers/configuration/configuration_type.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 17
|
||||
:emphasize-lines: 19
|
||||
|
||||
``Configuration`` provider has next helper methods:
|
||||
|
||||
|
@ -135,10 +137,27 @@ The last method ``.as_(callback, *args, **kwargs)`` helps to implement other con
|
|||
.. literalinclude:: ../../examples/providers/configuration/configuration_type_custom.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 16
|
||||
:emphasize-lines: 18
|
||||
|
||||
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.
|
||||
|
||||
Injecting invariants
|
||||
--------------------
|
||||
|
||||
You can inject invariant configuration options based on the value of the other configuration
|
||||
option.
|
||||
|
||||
To use that you should provide the switch-value as an item of the configuration option that
|
||||
contains sections ``config.options[config.switch]``:
|
||||
|
||||
- When the value of the ``config.switch`` is ``A``, the ``config.options.A`` is injected
|
||||
- When the value of the ``config.switch`` is ``B``, the ``config.options.B`` is injected
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_itemselector.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 15,30-31,38
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -73,7 +73,7 @@ all the classes and use special double-underscore ``__`` syntax for passing the
|
|||
.. literalinclude:: ../../examples/providers/factory_init_injections_underlying.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 24-35,39,42,45
|
||||
:emphasize-lines: 44,49
|
||||
|
||||
When you use ``__`` separator in the name of the keyword argument the ``Factory`` looks for
|
||||
the dependency with the same name as the left part of the ``__`` expression.
|
||||
|
@ -98,7 +98,7 @@ attribute of the provider that you're going to inject.
|
|||
.. literalinclude:: ../../examples/providers/factory_delegation.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 25
|
||||
:emphasize-lines: 28
|
||||
|
||||
.. note:: Any provider has a ``.provider`` attribute.
|
||||
|
||||
|
@ -135,7 +135,7 @@ provider with two peculiarities:
|
|||
.. literalinclude:: ../../examples/providers/abstract_factory.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 32
|
||||
:emphasize-lines: 34
|
||||
|
||||
Factory aggregate
|
||||
-----------------
|
||||
|
@ -155,7 +155,7 @@ rest of the arguments are passed to the delegated ``Factory``.
|
|||
.. literalinclude:: ../../examples/providers/factory_aggregate.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 31-35,43
|
||||
:emphasize-lines: 33-37,47
|
||||
|
||||
You can get a dictionary of the aggregated factories using the ``.factories`` attribute of the
|
||||
``FactoryAggregate``. To get a game factories dictionary from the previous example you can use
|
||||
|
|
|
@ -13,7 +13,7 @@ List provider
|
|||
.. literalinclude:: ../../examples/providers/list.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 19-22
|
||||
:emphasize-lines: 21-24
|
||||
|
||||
``List`` provider handles positional arguments the same way as a :ref:`factory-provider`.
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ You can inject provided object attribute, item or result of its method call.
|
|||
|
||||
.. literalinclude:: ../../examples/providers/provided_instance.py
|
||||
:language: python
|
||||
:emphasize-lines: 26-32
|
||||
:emphasize-lines: 28-34
|
||||
:lines: 3-
|
||||
|
||||
To use the feature you should use the ``.provided`` attribute of the injected provider. This
|
||||
|
@ -32,7 +32,7 @@ You can do nested constructions:
|
|||
|
||||
.. literalinclude:: ../../examples/providers/provided_instance_complex.py
|
||||
:language: python
|
||||
:emphasize-lines: 24-30
|
||||
:emphasize-lines: 26-32
|
||||
:lines: 3-
|
||||
|
||||
The ``.provided`` attribute is available for the next providers:
|
||||
|
|
|
@ -17,7 +17,7 @@ Selector provider
|
|||
.. literalinclude:: ../../examples/providers/selector.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 14-18
|
||||
:emphasize-lines: 16-20
|
||||
|
||||
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
|
||||
|
|
|
@ -32,6 +32,13 @@ factories:
|
|||
- :ref:`factory-specialize-provided-type`
|
||||
- :ref:`abstract-factory`
|
||||
|
||||
``Singleton`` provider scope is tied to the container. Two different containers will provider
|
||||
two different singleton objects:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/singleton_multiple_containers.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Resetting memorized object
|
||||
--------------------------
|
||||
|
||||
|
@ -41,7 +48,7 @@ provider.
|
|||
.. literalinclude:: ../../examples/providers/singleton_resetting.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 14
|
||||
:emphasize-lines: 18
|
||||
|
||||
.. note::
|
||||
Resetting of the memorized object clears the reference to it. Further object's lifecycle is
|
||||
|
@ -64,7 +71,7 @@ There are two thread-safe singleton implementations out of the box:
|
|||
.. literalinclude:: ../../examples/providers/singleton_thread_locals.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 11,12
|
||||
:emphasize-lines: 13,15
|
||||
|
||||
Implementing scopes
|
||||
-------------------
|
||||
|
|
|
@ -5,7 +5,7 @@ import dataclasses
|
|||
import random
|
||||
from typing import List
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class AbstractCacheClient(metaclass=abc.ABCMeta):
|
||||
|
@ -31,18 +31,22 @@ class Service:
|
|||
cache: AbstractCacheClient
|
||||
|
||||
|
||||
cache_client_factory = providers.AbstractFactory(AbstractCacheClient)
|
||||
service_factory = providers.Factory(
|
||||
Service,
|
||||
cache=cache_client_factory,
|
||||
)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
cache_client_factory = providers.AbstractFactory(AbstractCacheClient)
|
||||
|
||||
service_factory = providers.Factory(
|
||||
Service,
|
||||
cache=cache_client_factory,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cache_type = random.choice(['redis', 'memcached', None])
|
||||
container = Container()
|
||||
|
||||
cache_type = random.choice(['redis', 'memcached'])
|
||||
if cache_type == 'redis':
|
||||
cache_client_factory.override(
|
||||
container.cache_client_factory.override(
|
||||
providers.Factory(
|
||||
RedisCacheClient,
|
||||
host='localhost',
|
||||
|
@ -51,7 +55,7 @@ if __name__ == '__main__':
|
|||
),
|
||||
)
|
||||
elif cache_type == 'memcached':
|
||||
cache_client_factory.override(
|
||||
container.cache_client_factory.override(
|
||||
providers.Factory(
|
||||
MemcachedCacheClient,
|
||||
hosts=['10.0.1.1'],
|
||||
|
@ -60,7 +64,7 @@ if __name__ == '__main__':
|
|||
),
|
||||
)
|
||||
|
||||
service = service_factory()
|
||||
service = container.service_factory()
|
||||
print(service.cache)
|
||||
# The output depends on cache_type variable value.
|
||||
#
|
||||
|
|
|
@ -2,17 +2,22 @@
|
|||
|
||||
import passlib.hash
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
password_hasher = providers.Callable(
|
||||
passlib.hash.sha256_crypt.hash,
|
||||
salt_size=16,
|
||||
rounds=10000,
|
||||
)
|
||||
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
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)
|
||||
container = Container()
|
||||
|
||||
hashed_password = container.password_hasher('super secret')
|
||||
assert container.password_verifier('super secret', hashed_password)
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
"""`Configuration` provider example."""
|
||||
|
||||
import boto3
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
s3_client_factory = providers.Factory(
|
||||
boto3.client,
|
||||
's3',
|
||||
aws_access_key_id=config.aws.access_key_id,
|
||||
aws_secret_access_key=config.aws.secret_access_key,
|
||||
)
|
||||
config = providers.Configuration()
|
||||
|
||||
s3_client_factory = providers.Factory(
|
||||
boto3.client,
|
||||
's3',
|
||||
aws_access_key_id=config.aws.access_key_id,
|
||||
aws_secret_access_key=config.aws.secret_access_key,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
config.from_dict(
|
||||
container = Container()
|
||||
container.config.from_dict(
|
||||
{
|
||||
'aws': {
|
||||
'access_key_id': 'KEY',
|
||||
|
@ -23,4 +26,4 @@ if __name__ == '__main__':
|
|||
},
|
||||
},
|
||||
)
|
||||
s3_client = s3_client_factory()
|
||||
s3_client = container.s3_client_factory()
|
||||
|
|
|
@ -1,20 +1,34 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config.from_dict(
|
||||
{
|
||||
config = providers.Configuration()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
container.config.from_dict(
|
||||
{
|
||||
'aws': {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert container.config() == {
|
||||
'aws': {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}}
|
||||
assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}
|
||||
assert config.aws.access_key_id() == 'KEY'
|
||||
assert config.aws.secret_access_key() == 'SECRET'
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
},
|
||||
}
|
||||
assert container.config.aws() == {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
}
|
||||
assert container.config.aws.access_key_id() == 'KEY'
|
||||
assert container.config.aws.secret_access_key() == 'SECRET'
|
||||
|
|
|
@ -2,20 +2,25 @@
|
|||
|
||||
import os
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
# Emulate environment variables
|
||||
os.environ['AWS_ACCESS_KEY_ID'] = 'KEY'
|
||||
os.environ['AWS_SECRET_ACCESS_KEY'] = 'SECRET'
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
config.aws.access_key_id.from_env('AWS_ACCESS_KEY_ID')
|
||||
config.aws.secret_access_key.from_env('AWS_SECRET_ACCESS_KEY')
|
||||
config.optional.from_env('UNDEFINED', 'default_value')
|
||||
# Emulate environment variables
|
||||
os.environ['AWS_ACCESS_KEY_ID'] = 'KEY'
|
||||
os.environ['AWS_SECRET_ACCESS_KEY'] = 'SECRET'
|
||||
|
||||
assert config.aws.access_key_id() == 'KEY'
|
||||
assert config.aws.secret_access_key() == 'SECRET'
|
||||
assert config.optional() == 'default_value'
|
||||
container.config.aws.access_key_id.from_env('AWS_ACCESS_KEY_ID')
|
||||
container.config.aws.secret_access_key.from_env('AWS_SECRET_ACCESS_KEY')
|
||||
container.config.optional.from_env('UNDEFINED', 'default_value')
|
||||
|
||||
assert container.config.aws.access_key_id() == 'KEY'
|
||||
assert container.config.aws.secret_access_key() == 'SECRET'
|
||||
assert container.config.optional() == 'default_value'
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config.from_ini('examples/providers/configuration/config.ini')
|
||||
config = providers.Configuration()
|
||||
|
||||
assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}}
|
||||
assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}
|
||||
assert config.aws.access_key_id() == 'KEY'
|
||||
assert config.aws.secret_access_key() == 'SECRET'
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
container.config.from_ini('examples/providers/configuration/config.ini')
|
||||
|
||||
assert container.config() == {
|
||||
'aws': {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
},
|
||||
}
|
||||
assert container.config.aws() == {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
}
|
||||
assert container.config.aws.access_key_id() == 'KEY'
|
||||
assert container.config.aws.secret_access_key() == 'SECRET'
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
"""`Configuration` provider dynamic item selector.
|
||||
|
||||
Details: https://github.com/ets-labs/python-dependency-injector/issues/274
|
||||
"""
|
||||
"""`Configuration` provider dynamic item selector."""
|
||||
|
||||
import dataclasses
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
|
@ -14,34 +11,37 @@ class Foo:
|
|||
option2: object
|
||||
|
||||
|
||||
config = providers.Configuration(default={
|
||||
'target': 'A',
|
||||
'items': {
|
||||
'A': {
|
||||
'option1': 60,
|
||||
'option2': 80,
|
||||
},
|
||||
'B': {
|
||||
'option1': 10,
|
||||
'option2': 20,
|
||||
},
|
||||
},
|
||||
})
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
foo = providers.Factory(
|
||||
Foo,
|
||||
option1=config.items[config.target].option1,
|
||||
option2=config.items[config.target].option2,
|
||||
)
|
||||
config = providers.Configuration(default={
|
||||
'target': 'A',
|
||||
'items': {
|
||||
'A': {
|
||||
'option1': 60,
|
||||
'option2': 80,
|
||||
},
|
||||
'B': {
|
||||
'option1': 10,
|
||||
'option2': 20,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
foo_factory = providers.Factory(
|
||||
Foo,
|
||||
option1=config.items[config.target].option1,
|
||||
option2=config.items[config.target].option2,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
config.target.from_env('TARGET')
|
||||
f = foo()
|
||||
print(f.option1, f.option2)
|
||||
container = Container()
|
||||
|
||||
container.config.target.from_env('TARGET')
|
||||
foo = container.foo_factory()
|
||||
print(foo.option1, foo.option2)
|
||||
|
||||
# $ TARGET=A python configuration_itemselector.py
|
||||
# 60 80
|
||||
# $ TARGET=B python configuration_itemselector.py
|
||||
# 10 20
|
||||
# $ TARGET=A python configuration_itemselector.py
|
||||
# 60 80
|
||||
# $ TARGET=B python configuration_itemselector.py
|
||||
# 10 20
|
||||
|
|
|
@ -1,14 +1,28 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config.from_yaml('examples/providers/configuration/config.yml')
|
||||
config.from_yaml('examples/providers/configuration/config.local.yml')
|
||||
config = providers.Configuration()
|
||||
|
||||
assert config() == {'aws': {'access_key_id': 'LOCAL-KEY', 'secret_access_key': 'LOCAL-SECRET'}}
|
||||
assert config.aws() == {'access_key_id': 'LOCAL-KEY', 'secret_access_key': 'LOCAL-SECRET'}
|
||||
assert config.aws.access_key_id() == 'LOCAL-KEY'
|
||||
assert config.aws.secret_access_key() == 'LOCAL-SECRET'
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
container.config.from_yaml('examples/providers/configuration/config.yml')
|
||||
container.config.from_yaml('examples/providers/configuration/config.local.yml')
|
||||
|
||||
assert container.config() == {
|
||||
'aws': {
|
||||
'access_key_id': 'LOCAL-KEY',
|
||||
'secret_access_key': 'LOCAL-SECRET',
|
||||
},
|
||||
}
|
||||
assert container.config.aws() == {
|
||||
'access_key_id': 'LOCAL-KEY',
|
||||
'secret_access_key': 'LOCAL-SECRET',
|
||||
}
|
||||
assert container.config.aws.access_key_id() == 'LOCAL-KEY'
|
||||
assert container.config.aws.secret_access_key() == 'LOCAL-SECRET'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import os
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class ApiClient:
|
||||
|
@ -11,24 +11,28 @@ class ApiClient:
|
|||
self.timeout = timeout
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
api_client_factory = providers.Factory(
|
||||
ApiClient,
|
||||
api_key=config.api.key,
|
||||
timeout=config.api.timeout.as_int(),
|
||||
)
|
||||
config = providers.Configuration()
|
||||
|
||||
api_client_factory = providers.Factory(
|
||||
ApiClient,
|
||||
api_key=config.api.key,
|
||||
timeout=config.api.timeout.as_int(),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
# Emulate environment variables
|
||||
os.environ['API_KEY'] = 'secret'
|
||||
os.environ['API_TIMEOUT'] = '5'
|
||||
|
||||
config.api.key.from_env('API_KEY')
|
||||
config.api.timeout.from_env('API_TIMEOUT')
|
||||
container.config.api.key.from_env('API_KEY')
|
||||
container.config.api.timeout.from_env('API_TIMEOUT')
|
||||
|
||||
api_client = api_client_factory()
|
||||
api_client = container.api_client_factory()
|
||||
|
||||
assert api_client.api_key == 'secret'
|
||||
assert api_client.timeout == 5
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import os
|
||||
import decimal
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class Calculator:
|
||||
|
@ -11,20 +11,24 @@ class Calculator:
|
|||
self.pi = pi
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
calculator_factory = providers.Factory(
|
||||
Calculator,
|
||||
pi=config.pi.as_(decimal.Decimal),
|
||||
)
|
||||
config = providers.Configuration()
|
||||
|
||||
calculator_factory = providers.Factory(
|
||||
Calculator,
|
||||
pi=config.pi.as_(decimal.Decimal),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
# Emulate environment variables
|
||||
os.environ['PI'] = '3.1415926535897932384626433832'
|
||||
|
||||
config.pi.from_env('PI')
|
||||
container.config.pi.from_env('PI')
|
||||
|
||||
calculator = calculator_factory()
|
||||
calculator = container.calculator_factory()
|
||||
|
||||
assert calculator.pi == decimal.Decimal('3.1415926535897932384626433832')
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config.from_yaml('examples/providers/configuration/config.yml')
|
||||
config = providers.Configuration()
|
||||
|
||||
assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}}
|
||||
assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}
|
||||
assert config.aws.access_key_id() == 'KEY'
|
||||
assert config.aws.secret_access_key() == 'SECRET'
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
container.config.from_yaml('examples/providers/configuration/config.yml')
|
||||
|
||||
assert container.config() == {
|
||||
'aws': {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
},
|
||||
}
|
||||
assert container.config.aws() == {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
}
|
||||
assert container.config.aws.access_key_id() == 'KEY'
|
||||
assert container.config.aws.secret_access_key() == 'SECRET'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import asyncio
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
async def coroutine(arg1, arg2):
|
||||
|
@ -10,10 +10,14 @@ async def coroutine(arg1, arg2):
|
|||
return arg1, arg2
|
||||
|
||||
|
||||
coroutine_provider = providers.Coroutine(coroutine, arg1=1, arg2=2)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
coroutine_provider = providers.Coroutine(coroutine, arg1=1, arg2=2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
arg1, arg2 = asyncio.run(coroutine_provider())
|
||||
container = Container()
|
||||
|
||||
arg1, arg2 = asyncio.run(container.coroutine_provider())
|
||||
assert (arg1, arg2) == (1, 2)
|
||||
assert asyncio.iscoroutinefunction(coroutine_provider)
|
||||
assert asyncio.iscoroutinefunction(container.coroutine_provider)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Custom provider example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class CustomFactory(providers.Provider):
|
||||
|
@ -29,14 +29,18 @@ class CustomFactory(providers.Provider):
|
|||
return self._factory(*args, **kwargs)
|
||||
|
||||
|
||||
factory = CustomFactory(object)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
factory = CustomFactory(object)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
object1 = factory()
|
||||
container = Container()
|
||||
|
||||
object1 = container.factory()
|
||||
assert isinstance(object1, object)
|
||||
|
||||
object2 = factory()
|
||||
object2 = container.factory()
|
||||
assert isinstance(object1, object)
|
||||
|
||||
assert object1 is not object2
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
"""`Factory` provider example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class User:
|
||||
...
|
||||
|
||||
|
||||
users_factory = providers.Factory(User)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
user_factory = providers.Factory(User)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
user1 = users_factory()
|
||||
user2 = users_factory()
|
||||
container = Container()
|
||||
|
||||
user1 = container.user_factory()
|
||||
user2 = container.user_factory()
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import dataclasses
|
||||
import sys
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
|
@ -30,11 +30,13 @@ class Ludo(Game):
|
|||
...
|
||||
|
||||
|
||||
game_factory = providers.FactoryAggregate(
|
||||
chess=providers.Factory(Chess),
|
||||
checkers=providers.Factory(Checkers),
|
||||
ludo=providers.Factory(Ludo),
|
||||
)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
game_factory = providers.FactoryAggregate(
|
||||
chess=providers.Factory(Chess),
|
||||
checkers=providers.Factory(Checkers),
|
||||
ludo=providers.Factory(Ludo),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -42,7 +44,9 @@ if __name__ == '__main__':
|
|||
player1 = sys.argv[2].capitalize()
|
||||
player2 = sys.argv[3].capitalize()
|
||||
|
||||
selected_game = game_factory(game_type, player1, player2)
|
||||
container = Container()
|
||||
|
||||
selected_game = container.game_factory(game_type, player1, player2)
|
||||
selected_game.play()
|
||||
|
||||
# $ python factory_aggregate.py chess John Jane
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from typing import Callable, List
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class User:
|
||||
|
@ -21,15 +21,20 @@ class UserRepository:
|
|||
]
|
||||
|
||||
|
||||
user_factory = providers.Factory(User)
|
||||
user_repository_factory = providers.Factory(
|
||||
UserRepository,
|
||||
user_factory=user_factory.provider,
|
||||
)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
user_factory = providers.Factory(User)
|
||||
|
||||
user_repository_factory = providers.Factory(
|
||||
UserRepository,
|
||||
user_factory=user_factory.provider,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
user_repository = user_repository_factory()
|
||||
container = Container()
|
||||
|
||||
user_repository = container.user_repository_factory()
|
||||
|
||||
user1, user2 = user_repository.get_all()
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`Factory` provider init injections example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class Photo:
|
||||
|
@ -13,23 +13,27 @@ class User:
|
|||
self.main_photo = main_photo
|
||||
|
||||
|
||||
photo_factory = providers.Factory(Photo)
|
||||
user_factory = providers.Factory(
|
||||
User,
|
||||
main_photo=photo_factory,
|
||||
)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
photo_factory = providers.Factory(Photo)
|
||||
|
||||
user_factory = providers.Factory(
|
||||
User,
|
||||
main_photo=photo_factory,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
user1 = user_factory(1)
|
||||
container = Container()
|
||||
|
||||
user1 = container.user_factory(1)
|
||||
# Same as: # user1 = User(1, main_photo=Photo())
|
||||
|
||||
user2 = user_factory(2)
|
||||
user2 = container.user_factory(2)
|
||||
# Same as: # user2 = User(2, main_photo=Photo())
|
||||
|
||||
# Context keyword arguments have a priority:
|
||||
another_photo = Photo()
|
||||
user3 = user_factory(
|
||||
user3 = container.user_factory(
|
||||
uid=3,
|
||||
main_photo=another_photo,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`Factory` provider - passing injections to the underlying providers example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class Regularizer:
|
||||
|
@ -23,26 +23,31 @@ class Algorithm:
|
|||
self.task = task
|
||||
|
||||
|
||||
algorithm_factory = providers.Factory(
|
||||
Algorithm,
|
||||
task=providers.Factory(
|
||||
ClassificationTask,
|
||||
loss=providers.Factory(
|
||||
Loss,
|
||||
regularizer=providers.Factory(
|
||||
Regularizer,
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
algorithm_factory = providers.Factory(
|
||||
Algorithm,
|
||||
task=providers.Factory(
|
||||
ClassificationTask,
|
||||
loss=providers.Factory(
|
||||
Loss,
|
||||
regularizer=providers.Factory(
|
||||
Regularizer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
algorithm_1 = algorithm_factory(task__loss__regularizer__alpha=0.5)
|
||||
container = Container()
|
||||
|
||||
algorithm_1 = container.algorithm_factory(
|
||||
task__loss__regularizer__alpha=0.5,
|
||||
)
|
||||
assert algorithm_1.task.loss.regularizer.alpha == 0.5
|
||||
|
||||
algorithm_2 = algorithm_factory(task__loss__regularizer__alpha=0.7)
|
||||
algorithm_2 = container.algorithm_factory(
|
||||
task__loss__regularizer__alpha=0.7,
|
||||
)
|
||||
assert algorithm_2.task.loss.regularizer.alpha == 0.7
|
||||
|
||||
algorithm_3 = algorithm_factory(task__loss__regularizer=Regularizer(alpha=0.8))
|
||||
assert algorithm_3.task.loss.regularizer.alpha == 0.8
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`Factory` specialization with limitation to provided type example."""
|
||||
|
||||
from dependency_injector import providers, errors
|
||||
from dependency_injector import containers, providers, errors
|
||||
|
||||
|
||||
class BaseService:
|
||||
|
@ -17,11 +17,15 @@ class ServiceProvider(providers.Factory):
|
|||
|
||||
|
||||
# Creating service provider with a correct provided type:
|
||||
some_service_provider = ServiceProvider(SomeService)
|
||||
class Services(containers.DeclarativeContainer):
|
||||
|
||||
some_service_provider = ServiceProvider(SomeService)
|
||||
|
||||
|
||||
# Trying to create service provider an incorrect provided type:
|
||||
try:
|
||||
some_service_provider = ServiceProvider(object)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
some_service_provider = ServiceProvider(object)
|
||||
except errors.Error as exception:
|
||||
print(exception)
|
||||
# The output is:
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import dataclasses
|
||||
from typing import List
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
|
@ -16,23 +16,27 @@ class Dispatcher:
|
|||
modules: List[Module]
|
||||
|
||||
|
||||
dispatcher_factory = providers.Factory(
|
||||
Dispatcher,
|
||||
modules=providers.List(
|
||||
providers.Factory(Module, name='m1'),
|
||||
providers.Factory(Module, name='m2'),
|
||||
),
|
||||
)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
dispatcher_factory = providers.Factory(
|
||||
Dispatcher,
|
||||
modules=providers.List(
|
||||
providers.Factory(Module, name='m1'),
|
||||
providers.Factory(Module, name='m2'),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
dispatcher = dispatcher_factory()
|
||||
container = Container()
|
||||
|
||||
dispatcher = container.dispatcher_factory()
|
||||
|
||||
assert isinstance(dispatcher.modules, list)
|
||||
assert dispatcher.modules[0].name == 'm1'
|
||||
assert dispatcher.modules[1].name == 'm2'
|
||||
|
||||
# Call "dispatcher = dispatcher_factory()" is an equivalent for:
|
||||
# Call "dispatcher = container.dispatcher_factory()" is equivalent to:
|
||||
# dispatcher = Dispatcher(
|
||||
# modules=[
|
||||
# Module(name='m1'),
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
"""`Object` provider example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
object_provider = providers.Object(1)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
object_provider = providers.Object(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
assert object_provider() == 1
|
||||
container = Container()
|
||||
|
||||
assert container.object_provider() == 1
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
"""Simple providers overriding example."""
|
||||
|
||||
import dataclasses
|
||||
import unittest.mock
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class ApiClient:
|
||||
|
@ -13,30 +14,35 @@ class ApiClientStub(ApiClient):
|
|||
...
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Service:
|
||||
def __init__(self, api_client: ApiClient):
|
||||
self._api_client = api_client
|
||||
api_client: ApiClient
|
||||
|
||||
|
||||
api_client_factory = providers.Factory(ApiClient)
|
||||
service_factory = providers.Factory(
|
||||
Service,
|
||||
api_client=api_client_factory,
|
||||
)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
api_client_factory = providers.Factory(ApiClient)
|
||||
|
||||
service_factory = providers.Factory(
|
||||
Service,
|
||||
api_client=api_client_factory,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
# 1. Use .override() to replace the API client with stub
|
||||
api_client_factory.override(providers.Factory(ApiClientStub))
|
||||
service1 = service_factory()
|
||||
container.api_client_factory.override(providers.Factory(ApiClientStub))
|
||||
service1 = container.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)
|
||||
with container.api_client_factory.override(unittest.mock.Mock(ApiClient)):
|
||||
service2 = container.service_factory()
|
||||
assert isinstance(service2.api_client, unittest.mock.Mock)
|
||||
|
||||
# 3. Use .reset_override() to get back to normal
|
||||
api_client_factory.reset_override()
|
||||
service3 = service_factory()
|
||||
container.api_client_factory.reset_override()
|
||||
service3 = container.service_factory()
|
||||
assert isinstance(service3.api_client, ApiClient)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Example of the injecting of provided instance attributes and items."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class Service:
|
||||
|
@ -23,17 +23,21 @@ class Client:
|
|||
self.value4 = value4
|
||||
|
||||
|
||||
service = providers.Singleton(Service)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
client_factory = providers.Factory(
|
||||
Client,
|
||||
value1=service.provided[0],
|
||||
value2=service.provided.value,
|
||||
value3=service.provided.values[0],
|
||||
value4=service.provided.get_value.call(),
|
||||
)
|
||||
service = providers.Singleton(Service)
|
||||
|
||||
client_factory = providers.Factory(
|
||||
Client,
|
||||
value1=service.provided[0],
|
||||
value2=service.provided.value,
|
||||
value3=service.provided.values[0],
|
||||
value4=service.provided.get_value.call(),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
client = client_factory()
|
||||
container = Container()
|
||||
|
||||
client = container.client_factory()
|
||||
assert client.value1 == client.value2 == client.value3 == 'foo'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Complex example of the injecting of provided instance attributes and items."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class Service:
|
||||
|
@ -12,31 +12,35 @@ class Service:
|
|||
return self.value
|
||||
|
||||
|
||||
service = providers.Singleton(Service, value=42)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
dependency = providers.Object(
|
||||
{
|
||||
'foo': {
|
||||
'bar': 10,
|
||||
'baz': lambda arg: {'arg': arg}
|
||||
service = providers.Singleton(Service, value=42)
|
||||
|
||||
dependency = providers.Object(
|
||||
{
|
||||
'foo': {
|
||||
'bar': 10,
|
||||
'baz': lambda arg: {'arg': arg}
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
demo_list = providers.List(
|
||||
dependency.provided['foo']['bar'],
|
||||
dependency.provided['foo']['baz'].call(22)['arg'],
|
||||
dependency.provided['foo']['baz'].call(service)['arg'],
|
||||
dependency.provided['foo']['baz'].call(service)['arg'].value,
|
||||
dependency.provided['foo']['baz'].call(service)['arg'].get_value.call(),
|
||||
)
|
||||
demo_list = providers.List(
|
||||
dependency.provided['foo']['bar'],
|
||||
dependency.provided['foo']['baz'].call(22)['arg'],
|
||||
dependency.provided['foo']['baz'].call(service)['arg'],
|
||||
dependency.provided['foo']['baz'].call(service)['arg'].value,
|
||||
dependency.provided['foo']['baz'].call(service)['arg'].get_value.call(),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
assert demo_list() == [
|
||||
container = Container()
|
||||
|
||||
assert container.demo_list() == [
|
||||
10,
|
||||
22,
|
||||
service(),
|
||||
container.service(),
|
||||
42,
|
||||
42,
|
||||
]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`Selector` provider example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class SomeClass:
|
||||
|
@ -11,19 +11,24 @@ class SomeOtherClass:
|
|||
...
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
selector = providers.Selector(
|
||||
config.one_or_another,
|
||||
one=providers.Factory(SomeClass),
|
||||
another=providers.Factory(SomeOtherClass),
|
||||
)
|
||||
|
||||
selector = providers.Selector(
|
||||
config.one_or_another,
|
||||
one=providers.Factory(SomeClass),
|
||||
another=providers.Factory(SomeOtherClass),
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
config.override({'one_or_another': 'one'})
|
||||
instance_1 = selector()
|
||||
container = Container()
|
||||
|
||||
container.config.override({'one_or_another': 'one'})
|
||||
instance_1 = container.selector()
|
||||
assert isinstance(instance_1, SomeClass)
|
||||
|
||||
config.override({'one_or_another': 'another'})
|
||||
instance_2 = selector()
|
||||
container.config.override({'one_or_another': 'another'})
|
||||
instance_2 = container.selector()
|
||||
assert isinstance(instance_2, SomeOtherClass)
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
"""`Singleton` provider example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class UserService:
|
||||
...
|
||||
|
||||
|
||||
user_service_provider = providers.Singleton(UserService)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
user_service_provider = providers.Singleton(UserService)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
user_service1 = user_service_provider()
|
||||
user_service2 = user_service_provider()
|
||||
container = Container()
|
||||
|
||||
user_service1 = container.user_service_provider()
|
||||
user_service2 = container.user_service_provider()
|
||||
assert user_service1 is user_service2
|
||||
|
|
24
examples/providers/singleton_multiple_containers.py
Normal file
24
examples/providers/singleton_multiple_containers.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
"""`Singleton` provider resetting example."""
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class UserService:
|
||||
...
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
user_service_provider = providers.Singleton(UserService)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container1 = Container()
|
||||
user_service1 = container1.user_service_provider()
|
||||
assert user_service1 is container1.user_service_provider()
|
||||
|
||||
container2 = Container()
|
||||
user_service2 = container2.user_service_provider()
|
||||
assert user_service2 is container2.user_service_provider()
|
||||
|
||||
assert user_service1 is not user_service2
|
|
@ -1,19 +1,23 @@
|
|||
"""`Singleton` provider resetting example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class UserService:
|
||||
...
|
||||
|
||||
|
||||
user_service_provider = providers.Singleton(UserService)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
user_service_provider = providers.Singleton(UserService)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
user_service1 = user_service_provider()
|
||||
container = Container()
|
||||
|
||||
user_service_provider.reset()
|
||||
user_service1 = container.user_service_provider()
|
||||
|
||||
users_service2 = user_service_provider()
|
||||
assert users_service2 is not user_service1
|
||||
container.user_service_provider.reset()
|
||||
|
||||
user_service2 = container.user_service_provider()
|
||||
assert user_service2 is not user_service1
|
||||
|
|
|
@ -1,30 +1,35 @@
|
|||
"""`Singleton` - Flask request scope example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
from flask import Flask
|
||||
from dependency_injector import containers, providers
|
||||
from flask import Flask, current_app
|
||||
|
||||
|
||||
class Service:
|
||||
...
|
||||
|
||||
|
||||
service_provider = providers.Singleton(Service)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
service_provider = providers.Singleton(Service)
|
||||
|
||||
|
||||
def index_view():
|
||||
service_1 = service_provider()
|
||||
service_2 = service_provider()
|
||||
service_1 = current_app.container.service_provider()
|
||||
service_2 = current_app.container.service_provider()
|
||||
assert service_1 is service_2
|
||||
print(service_1)
|
||||
return 'Hello World!'
|
||||
|
||||
|
||||
def teardown_context(request):
|
||||
service_provider.reset()
|
||||
current_app.container.service_provider.reset()
|
||||
return request
|
||||
|
||||
|
||||
container = Container()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.container = container
|
||||
app.add_url_rule('/', 'index', view_func=index_view)
|
||||
app.after_request(teardown_context)
|
||||
|
||||
|
|
|
@ -3,31 +3,39 @@
|
|||
import threading
|
||||
import queue
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
def put_in_queue(example_object, queue_object):
|
||||
queue_object.put(example_object)
|
||||
|
||||
|
||||
thread_local_object = providers.ThreadLocalSingleton(object)
|
||||
queue_provider = providers.ThreadSafeSingleton(queue.Queue)
|
||||
put_in_queue = providers.Callable(
|
||||
put_in_queue,
|
||||
example_object=thread_local_object,
|
||||
queue_object=queue_provider,
|
||||
)
|
||||
thread_factory = providers.Factory(
|
||||
threading.Thread,
|
||||
target=put_in_queue.provider,
|
||||
)
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
thread_local_object = providers.ThreadLocalSingleton(object)
|
||||
|
||||
queue_provider = providers.ThreadSafeSingleton(queue.Queue)
|
||||
|
||||
put_in_queue = providers.Callable(
|
||||
put_in_queue,
|
||||
example_object=thread_local_object,
|
||||
queue_object=queue_provider,
|
||||
)
|
||||
|
||||
thread_factory = providers.Factory(
|
||||
threading.Thread,
|
||||
target=put_in_queue.provider,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
n = 10
|
||||
threads = []
|
||||
for thread_number in range(10):
|
||||
for thread_number in range(n):
|
||||
threads.append(
|
||||
thread_factory(name='Thread{0}'.format(thread_number)),
|
||||
container.thread_factory(name='Thread{0}'.format(thread_number)),
|
||||
)
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
@ -35,9 +43,9 @@ if __name__ == '__main__':
|
|||
thread.join()
|
||||
|
||||
all_objects = set()
|
||||
while not queue_provider().empty():
|
||||
all_objects.add(queue_provider().get())
|
||||
while not container.queue_provider().empty():
|
||||
all_objects.add(container.queue_provider().get())
|
||||
|
||||
assert len(all_objects) == len(threads)
|
||||
assert len(all_objects) == len(threads) == n
|
||||
# Queue contains same number of objects as number of threads where
|
||||
# thread-local singleton provider was used.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Dependency injector top-level package."""
|
||||
|
||||
__version__ = '3.36.0'
|
||||
__version__ = '3.37.0'
|
||||
"""Version number that follows semantic versioning.
|
||||
|
||||
:type: str
|
||||
|
|
|
@ -283,8 +283,8 @@ class Selector(Provider):
|
|||
|
||||
|
||||
class ProvidedInstanceFluentInterface:
|
||||
def __getattr__(self, item: str) -> AttributeGetter: ...
|
||||
def __getitem__(self, item: str) -> ItemGetter: ...
|
||||
def __getattr__(self, item: Any) -> AttributeGetter: ...
|
||||
def __getitem__(self, item: Any) -> ItemGetter: ...
|
||||
def call(self, *args: Injection, **kwargs: Injection) -> MethodCaller: ...
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user