mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Merge branch 'release/3.30.3' into master
This commit is contained in:
commit
597f6794a9
94
README.rst
94
README.rst
|
@ -52,7 +52,7 @@ What is ``Dependency Injector``?
|
|||
|
||||
``Dependency Injector`` is a dependency injection framework for Python.
|
||||
|
||||
It helps you implement the dependency injection principle.
|
||||
It helps you in implementing the dependency injection principle.
|
||||
|
||||
What is dependency injection?
|
||||
-----------------------------
|
||||
|
@ -70,6 +70,9 @@ Before:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class ApiClient:
|
||||
|
||||
def __init__(self):
|
||||
|
@ -82,10 +85,18 @@ Before:
|
|||
def __init__(self):
|
||||
self.api_client = ApiClient()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
service = Service()
|
||||
|
||||
|
||||
After:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class ApiClient:
|
||||
|
||||
def __init__(self, api_key: str, timeout: int):
|
||||
|
@ -98,55 +109,82 @@ After:
|
|||
def __init__(self, api_client: ApiClient):
|
||||
self.api_client = api_client
|
||||
|
||||
Who creates the objects now? Look at the next section.
|
||||
|
||||
if __name__ == '__main__':
|
||||
service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
|
||||
|
||||
|
||||
Flexibility comes with a price: now you need to assemble your objects like this
|
||||
``Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))``. The assembly code might get
|
||||
duplicated and it'll become harder to change the application structure.
|
||||
|
||||
What does Dependency Injector do?
|
||||
---------------------------------
|
||||
|
||||
``Dependency Injector`` provides you with the container and the providers that help you build
|
||||
your application objects when you apply dependency injection principle:
|
||||
``Dependency Injector`` helps you assemble the objects.
|
||||
|
||||
It provides you the container and the providers that help you describe objects assembly. When you
|
||||
need an object you get it from the container. The rest of the assembly work is done by the
|
||||
framework:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class ApiClient:
|
||||
class ApiClient:
|
||||
|
||||
def __init__(self, api_key: str, timeout: int):
|
||||
self.api_key = api_key
|
||||
self.timeout = timeout
|
||||
def __init__(self, api_key: str, timeout: int):
|
||||
self.api_key = api_key
|
||||
self.timeout = timeout
|
||||
|
||||
|
||||
class Service:
|
||||
class Service:
|
||||
|
||||
def __init__(self, api_client: ApiClient):
|
||||
self.api_client = api_client
|
||||
def __init__(self, api_client: ApiClient):
|
||||
self.api_client = api_client
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
config = providers.Configuration()
|
||||
|
||||
api_client = providers.Singleton(
|
||||
ApiClient,
|
||||
api_key=config.api_key,
|
||||
timeout=config.timeout,
|
||||
)
|
||||
api_client = providers.Singleton(
|
||||
ApiClient,
|
||||
api_key=config.api_key,
|
||||
timeout=config.timeout,
|
||||
)
|
||||
|
||||
service = providers.Factory(
|
||||
Service,
|
||||
api_client=api_client,
|
||||
)
|
||||
service = providers.Factory(
|
||||
Service,
|
||||
api_client=api_client,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
container.config.from_yaml('config.yml')
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
container.config.api_key.from_env('API_KEY')
|
||||
container.config.timeout.from_env('TIMEOUT')
|
||||
|
||||
service = container.service()
|
||||
service = container.service()
|
||||
assert isinstance(service.api_client, ApiClient)
|
||||
|
||||
assert isinstance(service.api_client, ApiClient)
|
||||
Retrieving of the ``Service`` instance now is done like this ``container.service()``.
|
||||
|
||||
Also ``Dependency Injector`` provides a bonus in overriding any of the providers with the
|
||||
``.override()`` method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from unittest import mock
|
||||
|
||||
|
||||
with container.api_client.override(mock.Mock()):
|
||||
service = container.service()
|
||||
assert isinstance(service.api_client, mock.Mock)
|
||||
|
||||
It helps in a testing. Also you can use it for configuring project for the different environments:
|
||||
replace an API client with a stub on the dev or stage.
|
||||
|
||||
`More examples <https://github.com/ets-labs/python-dependency-injector/tree/master/examples>`_
|
||||
|
||||
|
|
|
@ -1,55 +1,43 @@
|
|||
Declarative containers
|
||||
----------------------
|
||||
Declarative container
|
||||
---------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
:py:class:`DeclarativeContainer` is inversion of control container that
|
||||
could be defined in declarative manner. It should cover most of the cases
|
||||
when list of providers that would be included in container is deterministic
|
||||
(container will not change its structure in runtime).
|
||||
:py:class:`DeclarativeContainer` is a class-based style of the providers definition.
|
||||
|
||||
Declarative containers have to extend base declarative container class -
|
||||
:py:class:`dependency_injector.containers.DeclarativeContainer`.
|
||||
|
||||
Declarative container's providers have to be defined like container's class
|
||||
attributes. Every provider in container has name. This name should follow
|
||||
``some_provider`` convention, that is standard naming convention for
|
||||
attribute names in Python.
|
||||
|
||||
.. note::
|
||||
|
||||
Declarative containers have several features that could be useful
|
||||
for some kind of operations on container's providers, please visit API
|
||||
documentation for getting full list of features -
|
||||
:py:class:`dependency_injector.containers.DeclarativeContainer`.
|
||||
|
||||
Here is an simple example of defining declarative container with several
|
||||
factories:
|
||||
|
||||
.. image:: /images/containers/declarative.png
|
||||
:width: 85%
|
||||
:align: center
|
||||
You create the declarative container subclass, put the providers as attributes and create the
|
||||
container instance.
|
||||
|
||||
.. literalinclude:: ../../examples/containers/declarative.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Example of declarative containers inheritance:
|
||||
The declarative container providers should only be used when you have the container instance.
|
||||
Working with the providers of the container on the class level will influence all further
|
||||
instances.
|
||||
|
||||
.. image:: /images/containers/declarative_inheritance.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
The declarative container can not have any methods or any other attributes then providers.
|
||||
|
||||
The container class provides next attributes:
|
||||
|
||||
- ``providers`` - the dictionary of all the container providers
|
||||
- ``cls_providers`` - the dictionary of the container providers of the current container
|
||||
- ``inherited_providers`` - the dictionary of all the inherited container providers
|
||||
|
||||
.. literalinclude:: ../../examples/containers/declarative_inheritance.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Example of declarative containers's provider injections:
|
||||
|
||||
.. image:: /images/containers/declarative_injections.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
Injections in the declarative container are done the usual way:
|
||||
|
||||
.. literalinclude:: ../../examples/containers/declarative_injections.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
You can override the container providers when you create the container instance:
|
||||
|
||||
.. literalinclude:: ../../examples/containers/declarative_override_providers.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,28 +1,25 @@
|
|||
Dynamic containers
|
||||
------------------
|
||||
Dynamic container
|
||||
-----------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
:py:class:`DynamicContainer` is an inversion of control container with dynamic
|
||||
structure. It should cover most of the cases when list of providers that
|
||||
would be included in container is non-deterministic and depends on
|
||||
application's flow or its configuration (container's structure could be
|
||||
determined just after application will be started and will do some initial
|
||||
work, like parsing list of container's providers from the configuration).
|
||||
:py:class:`DynamicContainer` is a collection of the providers defined in the runtime.
|
||||
|
||||
While :py:class:`DeclarativeContainer` acts on class-level,
|
||||
:py:class:`DynamicContainer` does the same on instance-level.
|
||||
|
||||
Here is an simple example of defining dynamic container with several factories:
|
||||
You create the dynamic container instance and put the providers as attributes.
|
||||
|
||||
.. literalinclude:: ../../examples/containers/dynamic.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Next example demonstrates creation of dynamic container based on some
|
||||
configuration:
|
||||
The dynamic container is good for the case when your application structure depends on the
|
||||
configuration file or some other source that you can reach only after application is already
|
||||
running (database, api, etc).
|
||||
|
||||
In this example we use the configuration to fill in the dynamic container with the providers:
|
||||
|
||||
.. literalinclude:: ../../examples/containers/dynamic_runtime_creation.py
|
||||
:language: python
|
||||
|
||||
:lines: 3-
|
||||
|
||||
.. disqus::
|
||||
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
IoC Containers
|
||||
==============
|
||||
Containers
|
||||
==========
|
||||
|
||||
Containers are collections of providers. Main purpose of containers is to group
|
||||
providers.
|
||||
Containers are collections of the providers.
|
||||
|
||||
There are, actually, several popular cases of containers usage:
|
||||
There are several use cases how you can use containers:
|
||||
|
||||
+ Keeping all providers in a single container.
|
||||
+ Grouping of providers from the same architectural layer (for example,
|
||||
+ Keeping all the providers in a single container (most common).
|
||||
+ Grouping of the providers from the same architectural layer (for example,
|
||||
``Services``, ``Models`` and ``Forms`` containers).
|
||||
+ Grouping of providers from the same functional groups (for example,
|
||||
container ``Users``, that contains all functional parts of ``Users``
|
||||
component).
|
||||
|
||||
Also, for both of these and some other cases, it might be useful to attach
|
||||
some init / shutdown functionality or something else, that deals with group
|
||||
of providers.
|
||||
container ``Users``, that contains all functional parts of the ``users``
|
||||
package).
|
||||
|
||||
Containers package API docs - :py:mod:`dependency_injector.containers`.
|
||||
|
||||
|
|
|
@ -1,41 +1,24 @@
|
|||
Overriding of containers
|
||||
------------------------
|
||||
Overriding of the container
|
||||
---------------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
Containers can be overridden by other containers. This, actually, means that
|
||||
all of the providers from overriding container will override providers with
|
||||
the same names in overridden container.
|
||||
The container can be overridden by the other container. All of the providers from the overriding
|
||||
container will override the providers with the same names in the overridden container.
|
||||
|
||||
There are two ways to override :py:class:`DeclarativeContainer` with another
|
||||
container:
|
||||
|
||||
- Use :py:meth:`DeclarativeContainer.override` method.
|
||||
- Use :py:func:`override` class decorator.
|
||||
|
||||
Example of overriding container using :py:meth:`DeclarativeContainer.override`
|
||||
method:
|
||||
|
||||
.. literalinclude:: ../../examples/containers/override_declarative.py
|
||||
.. literalinclude:: ../../examples/containers/override.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
|
||||
Example of overriding container using :py:func:`override` decorator:
|
||||
It helps in a testing. Also you can use it for configuring project for the different
|
||||
environments: replace an API client with a stub on the dev or stage.
|
||||
|
||||
.. literalinclude:: ../../examples/containers/override_declarative_decorator.py
|
||||
:language: python
|
||||
The container also has:
|
||||
|
||||
Also there are several useful :py:class:`DeclarativeContainer` methods and
|
||||
properties that help to work with container overridings:
|
||||
|
||||
- :py:attr:`DeclarativeContainer.overridden` - tuple of all overriding
|
||||
containers.
|
||||
- :py:meth:`DeclarativeContainer.reset_last_overriding()` - reset last
|
||||
overriding provider for each container providers.
|
||||
- :py:meth:`DeclarativeContainer.reset_override()` - reset all overridings
|
||||
for each container providers.
|
||||
|
||||
:py:class:`DynamicContainer` has exactly the same functionality, except of
|
||||
:py:func:`override` decorator.
|
||||
- ``container.overridden`` - tuple of all overriding containers.
|
||||
- ``container.reset_last_overriding()`` - reset last overriding for each provider in the container.
|
||||
- ``container.reset_override()`` - reset all overriding in the container.
|
||||
|
||||
:py:class:`DynamicContainer` has the same functionality.
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
Specialization of containers
|
||||
----------------------------
|
||||
Specialization of the container provider type
|
||||
---------------------------------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
:py:class:`DeclarativeContainer` could be specialized for any kind of needs
|
||||
via declaring its subclasses.
|
||||
|
||||
One of such `builtin` features is a limitation for providers type.
|
||||
|
||||
Next example shows usage of this feature with :py:class:`DeclarativeContainer`
|
||||
in couple with feature of :py:class:`dependency_injector.providers.Factory`
|
||||
for limitation of its provided type:
|
||||
You can make a restriction of the :py:class:`DeclarativeContainer` provider type:
|
||||
|
||||
.. literalinclude:: ../../examples/containers/declarative_provider_type.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 29-31
|
||||
|
||||
Limitation for providers type could be used with :py:class:`DynamicContainer`
|
||||
as well:
|
||||
The emphasized lines will cause an error because ``other_provider`` is not a subtype of the
|
||||
``ServiceProvider``. This helps to control the content of the container.
|
||||
|
||||
The same works for the :py:class:`DynamicContainer`:
|
||||
|
||||
.. literalinclude:: ../../examples/containers/dynamic_provider_type.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 23
|
||||
|
||||
The emphasized line will also cause an error.
|
||||
|
||||
.. disqus::
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
Before Width: | Height: | Size: 112 KiB |
|
@ -7,6 +7,11 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
3.30.3
|
||||
------
|
||||
- Update README.
|
||||
- Update containers documentation and examples.
|
||||
|
||||
3.30.2
|
||||
------
|
||||
- Update README.
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
"""Declarative IoC container simple example."""
|
||||
"""Declarative container example."""
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
# Defining declarative IoC container:
|
||||
class Container(containers.DeclarativeContainer):
|
||||
"""Example IoC container."""
|
||||
|
||||
factory1 = providers.Factory(object)
|
||||
|
||||
factory2 = providers.Factory(object)
|
||||
|
||||
|
||||
# Creating some objects:
|
||||
object1 = Container.factory1()
|
||||
object2 = Container.factory2()
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
# Making some asserts:
|
||||
assert object1 is not object2
|
||||
assert isinstance(object1, object)
|
||||
assert isinstance(object2, object)
|
||||
object1 = container.factory1()
|
||||
object2 = container.factory2()
|
||||
|
||||
print(container.providers)
|
||||
# {
|
||||
# 'factory1': <dependency_injector.providers.Factory(...),
|
||||
# 'factory2': <dependency_injector.providers.Factory(...),
|
||||
# }
|
||||
|
|
|
@ -1,30 +1,34 @@
|
|||
"""Declarative IoC containers inheritance example."""
|
||||
"""Declarative containers inheritance example."""
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class ContainerA(containers.DeclarativeContainer):
|
||||
"""Example IoC container A."""
|
||||
|
||||
provider1 = providers.Factory(object)
|
||||
|
||||
|
||||
class ContainerB(ContainerA):
|
||||
"""Example IoC container B."""
|
||||
|
||||
provider2 = providers.Singleton(object)
|
||||
|
||||
|
||||
# Making some asserts for `providers` attribute:
|
||||
assert ContainerA.providers == dict(provider1=ContainerA.provider1)
|
||||
assert ContainerB.providers == dict(provider1=ContainerA.provider1,
|
||||
provider2=ContainerB.provider2)
|
||||
assert ContainerA.providers == {
|
||||
'provider1': ContainerA.provider1,
|
||||
}
|
||||
assert ContainerB.providers == {
|
||||
'provider1': ContainerA.provider1,
|
||||
'provider2': ContainerB.provider2,
|
||||
}
|
||||
|
||||
# Making some asserts for `cls_providers` attribute:
|
||||
assert ContainerA.cls_providers == dict(provider1=ContainerA.provider1)
|
||||
assert ContainerB.cls_providers == dict(provider2=ContainerB.provider2)
|
||||
assert ContainerA.cls_providers == {
|
||||
'provider1': ContainerA.provider1,
|
||||
}
|
||||
assert ContainerB.cls_providers == {
|
||||
'provider2': ContainerB.provider2,
|
||||
}
|
||||
|
||||
# Making some asserts for `inherited_providers` attribute:
|
||||
assert ContainerA.inherited_providers == dict()
|
||||
assert ContainerB.inherited_providers == dict(provider1=ContainerB.provider1)
|
||||
assert ContainerA.inherited_providers == {}
|
||||
assert ContainerB.inherited_providers == {
|
||||
'provider1': ContainerA.provider1,
|
||||
}
|
||||
|
|
|
@ -1,35 +1,42 @@
|
|||
"""Declarative IoC container's provider injections example."""
|
||||
"""Declarative container injections example."""
|
||||
|
||||
import sqlite3
|
||||
import collections
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
UsersService = collections.namedtuple('UsersService', ['db'])
|
||||
AuthService = collections.namedtuple('AuthService', ['db', 'users_service'])
|
||||
class UserService:
|
||||
def __init__(self, db: sqlite3.Connection):
|
||||
self.db = db
|
||||
|
||||
|
||||
class Services(containers.DeclarativeContainer):
|
||||
"""IoC container of service providers."""
|
||||
class AuthService:
|
||||
def __init__(self, db: sqlite3.Connection, user_service: UserService):
|
||||
self.db = db
|
||||
self.user_service = user_service
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||
|
||||
users = providers.Factory(UsersService,
|
||||
db=database)
|
||||
user_service = providers.Factory(
|
||||
UserService,
|
||||
db=database,
|
||||
)
|
||||
|
||||
auth = providers.Factory(AuthService,
|
||||
db=database,
|
||||
users_service=users)
|
||||
auth_service = providers.Factory(
|
||||
AuthService,
|
||||
db=database,
|
||||
user_service=user_service,
|
||||
)
|
||||
|
||||
|
||||
# Retrieving service providers from container:
|
||||
users_service = Services.users()
|
||||
auth_service = Services.auth()
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
# Making some asserts:
|
||||
assert users_service.db is auth_service.db is Services.database()
|
||||
assert isinstance(auth_service.users_service, UsersService)
|
||||
assert users_service is not Services.users()
|
||||
assert auth_service is not Services.auth()
|
||||
user_service = container.user_service()
|
||||
auth_service = container.auth_service()
|
||||
|
||||
assert user_service.db is auth_service.db is container.database()
|
||||
assert isinstance(auth_service.user_service, UserService)
|
||||
|
|
18
examples/containers/declarative_override_providers.py
Normal file
18
examples/containers/declarative_override_providers.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
"""Declarative container provider override example."""
|
||||
|
||||
import sqlite3
|
||||
from unittest import mock
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container(database=mock.Mock(sqlite3.Connection))
|
||||
|
||||
database = container.database()
|
||||
assert isinstance(database, mock.Mock)
|
|
@ -1,48 +1,33 @@
|
|||
"""Specializing declarative container and factory provider example."""
|
||||
"""Declarative container provider type restriction example."""
|
||||
|
||||
import collections
|
||||
import abc
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
import dependency_injector.errors as errors
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class SequenceProvider(providers.Factory):
|
||||
"""Sequence factory.
|
||||
|
||||
Can provide only sequence objects.
|
||||
"""
|
||||
|
||||
provided_type = collections.Sequence
|
||||
class Service(metaclass=abc.ABCMeta):
|
||||
...
|
||||
|
||||
|
||||
class SequencesContainer(containers.DeclarativeContainer):
|
||||
"""IoC container.
|
||||
|
||||
Can contain only sequence providers.
|
||||
"""
|
||||
|
||||
provider_type = SequenceProvider
|
||||
class UserService(Service):
|
||||
...
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
class _SequenceContainer1(SequencesContainer):
|
||||
object_provider = providers.Factory(object)
|
||||
except errors.Error as exception:
|
||||
print(exception)
|
||||
# <class '__main__._SequenceContainer1'> can contain only
|
||||
# <class '__main__.SequenceProvider'> instances
|
||||
class ServiceProvider(providers.Factory):
|
||||
|
||||
try:
|
||||
class _SequenceContainer2(SequencesContainer):
|
||||
object_provider = SequenceProvider(object)
|
||||
except errors.Error as exception:
|
||||
print(exception)
|
||||
# <class '__main__.SequenceProvider'> can provide only
|
||||
# <class '_abcoll.Sequence'> instances
|
||||
provided_type = Service
|
||||
|
||||
class _SequenceContaier3(SequencesContainer):
|
||||
list_provider = SequenceProvider(list)
|
||||
|
||||
assert _SequenceContaier3.list_provider() == list()
|
||||
class ServiceContainer(containers.DeclarativeContainer):
|
||||
|
||||
provider_type = ServiceProvider
|
||||
|
||||
|
||||
class MyServices(ServiceContainer):
|
||||
|
||||
user_service = ServiceProvider(UserService)
|
||||
|
||||
|
||||
class ImproperServices(ServiceContainer):
|
||||
|
||||
other_provider = providers.Factory(object)
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
"""Dynamic container simple example."""
|
||||
"""Dynamic container example."""
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
# Defining dynamic container:
|
||||
container = containers.DynamicContainer()
|
||||
container.factory1 = providers.Factory(object)
|
||||
container.factory2 = providers.Factory(object)
|
||||
if __name__ == '__main__':
|
||||
container = containers.DynamicContainer()
|
||||
container.factory1 = providers.Factory(object)
|
||||
container.factory2 = providers.Factory(object)
|
||||
|
||||
# Creating some objects:
|
||||
object1 = container.factory1()
|
||||
object2 = container.factory2()
|
||||
object1 = container.factory1()
|
||||
object2 = container.factory2()
|
||||
|
||||
# Making some asserts:
|
||||
assert object1 is not object2
|
||||
assert isinstance(object1, object) and isinstance(object2, object)
|
||||
print(container.providers)
|
||||
# {
|
||||
# 'factory1': <dependency_injector.providers.Factory(...),
|
||||
# 'factory2': <dependency_injector.providers.Factory(...),
|
||||
# }
|
||||
|
|
|
@ -1,41 +1,25 @@
|
|||
"""Specializing dynamic container and factory provider example."""
|
||||
"""Dynamic container provider type restriction example."""
|
||||
|
||||
import collections
|
||||
import abc
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
import dependency_injector.errors as errors
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class SequenceProvider(providers.Factory):
|
||||
"""Sequence factory.
|
||||
|
||||
Can provide only sequence objects.
|
||||
"""
|
||||
|
||||
provided_type = collections.Sequence
|
||||
class Service(metaclass=abc.ABCMeta):
|
||||
...
|
||||
|
||||
|
||||
sequences_container = containers.DynamicContainer()
|
||||
sequences_container.provider_type = SequenceProvider
|
||||
class UserService(Service):
|
||||
...
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
sequences_container.object_provider = providers.Factory(object)
|
||||
except errors.Error as exception:
|
||||
print(exception)
|
||||
# <dependency_injector.containers.DynamicContainer object at
|
||||
# 0x107820ed0> can contain only <class '__main__.SequenceProvider'>
|
||||
# instances
|
||||
class ServiceProvider(providers.Factory):
|
||||
|
||||
try:
|
||||
sequences_container.object_provider = SequenceProvider(object)
|
||||
except errors.Error as exception:
|
||||
print(exception)
|
||||
# <class '__main__.SequenceProvider'> can provide only
|
||||
# <class '_abcoll.Sequence'> instances
|
||||
provided_type = Service
|
||||
|
||||
sequences_container.list_provider = SequenceProvider(list)
|
||||
|
||||
assert sequences_container.list_provider() == list()
|
||||
services = containers.DynamicContainer()
|
||||
services.provider_type = ServiceProvider
|
||||
|
||||
services.user_service = ServiceProvider(UserService)
|
||||
services.other_provider = providers.Factory(object)
|
||||
|
|
|
@ -1,59 +1,40 @@
|
|||
"""Creation of dynamic container based on some configuration example."""
|
||||
"""Creation of dynamic container based on the configuration example."""
|
||||
|
||||
import collections
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
# Defining several example services:
|
||||
UsersService = collections.namedtuple('UsersService', [])
|
||||
AuthService = collections.namedtuple('AuthService', [])
|
||||
class UserService:
|
||||
...
|
||||
|
||||
|
||||
def import_cls(cls_name):
|
||||
"""Import class by its fully qualified name.
|
||||
|
||||
In terms of current example it is just a small helper function. Please,
|
||||
don't use it in production approaches.
|
||||
"""
|
||||
path_components = cls_name.split('.')
|
||||
module = __import__('.'.join(path_components[:-1]),
|
||||
locals(),
|
||||
globals(),
|
||||
fromlist=path_components[-1:])
|
||||
return getattr(module, path_components[-1])
|
||||
class AuthService:
|
||||
...
|
||||
|
||||
|
||||
# "Parsing" some configuration:
|
||||
config = {
|
||||
'services': {
|
||||
'users': {
|
||||
'class': '__main__.UsersService',
|
||||
'provider_class': 'dependency_injector.providers.Factory',
|
||||
def populate_container(container, providers_config):
|
||||
for provider_name, provider_info in providers_config.items():
|
||||
provided_cls = globals().get(provider_info['class'])
|
||||
provider_cls = getattr(providers, provider_info['provider_class'])
|
||||
setattr(container, provider_name, provider_cls(provided_cls))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
services_config = {
|
||||
'user': {
|
||||
'class': 'UserService',
|
||||
'provider_class': 'Factory',
|
||||
},
|
||||
'auth': {
|
||||
'class': '__main__.AuthService',
|
||||
'provider_class': 'dependency_injector.providers.Factory',
|
||||
}
|
||||
'class': 'AuthService',
|
||||
'provider_class': 'Factory',
|
||||
},
|
||||
}
|
||||
}
|
||||
services = containers.DynamicContainer()
|
||||
|
||||
# Creating empty container of service providers:
|
||||
services = containers.DynamicContainer()
|
||||
populate_container(services, services_config)
|
||||
|
||||
# Filling dynamic container with service providers using configuration:
|
||||
for service_name, service_info in config['services'].iteritems():
|
||||
# Runtime importing of service and service provider classes:
|
||||
service_cls = import_cls(service_info['class'])
|
||||
service_provider_cls = import_cls(service_info['provider_class'])
|
||||
user_service = services.user()
|
||||
auth_service = services.auth()
|
||||
|
||||
# Binding service provider to the dynamic service providers catalog:
|
||||
setattr(services, service_name, service_provider_cls(service_cls))
|
||||
|
||||
# Creating some objects:
|
||||
users_service = services.users()
|
||||
auth_service = services.auth()
|
||||
|
||||
# Making some asserts:
|
||||
assert isinstance(users_service, UsersService)
|
||||
assert isinstance(auth_service, AuthService)
|
||||
assert isinstance(user_service, UserService)
|
||||
assert isinstance(auth_service, AuthService)
|
||||
|
|
31
examples/containers/override.py
Normal file
31
examples/containers/override.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
"""Container overriding example."""
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
class Service:
|
||||
...
|
||||
|
||||
|
||||
class ServiceStub:
|
||||
...
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
service = providers.Factory(Service)
|
||||
|
||||
|
||||
class OverridingContainer(containers.DeclarativeContainer):
|
||||
|
||||
service = providers.Factory(ServiceStub)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
overriding_container = OverridingContainer()
|
||||
|
||||
container.override(overriding_container)
|
||||
|
||||
service = container.service()
|
||||
assert isinstance(service, ServiceStub)
|
|
@ -1,28 +0,0 @@
|
|||
"""Declarative IoC container overriding example."""
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
"""IoC container."""
|
||||
|
||||
sequence_factory = providers.Factory(list)
|
||||
|
||||
|
||||
class OverridingContainer(containers.DeclarativeContainer):
|
||||
"""Overriding IoC container."""
|
||||
|
||||
sequence_factory = providers.Factory(tuple)
|
||||
|
||||
|
||||
# Overriding `Container` with `OverridingContainer`:
|
||||
Container.override(OverridingContainer)
|
||||
|
||||
# Creating some objects using overridden container:
|
||||
sequence_1 = Container.sequence_factory([1, 2, 3])
|
||||
sequence_2 = Container.sequence_factory([3, 2, 1])
|
||||
|
||||
# Making some asserts:
|
||||
assert Container.overridden == (OverridingContainer,)
|
||||
assert sequence_1 == (1, 2, 3) and sequence_2 == (3, 2, 1)
|
|
@ -1,27 +0,0 @@
|
|||
"""Declarative IoC container overriding using `@override()` decorator."""
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
"""IoC container."""
|
||||
|
||||
sequence_factory = providers.Factory(list)
|
||||
|
||||
|
||||
# Overriding `Container` with `OverridingContainer`:
|
||||
@containers.override(Container)
|
||||
class OverridingContainer(containers.DeclarativeContainer):
|
||||
"""Overriding IoC container."""
|
||||
|
||||
sequence_factory = providers.Factory(tuple)
|
||||
|
||||
|
||||
# Creating some objects using overridden container:
|
||||
sequence_1 = Container.sequence_factory([1, 2, 3])
|
||||
sequence_2 = Container.sequence_factory([3, 2, 1])
|
||||
|
||||
# Making some asserts:
|
||||
assert Container.overridden == (OverridingContainer,)
|
||||
assert sequence_1 == (1, 2, 3) and sequence_2 == (3, 2, 1)
|
|
@ -1,2 +0,0 @@
|
|||
api_key: test-key
|
||||
timeout: 5
|
|
@ -32,8 +32,8 @@ class Container(containers.DeclarativeContainer):
|
|||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
container.config.from_yaml('config.yml')
|
||||
container.config.api_key.from_env('API_KEY')
|
||||
container.config.timeout.from_env('TIMEOUT')
|
||||
|
||||
service = container.service()
|
||||
|
||||
assert isinstance(service.api_client, ApiClient)
|
||||
|
|
18
examples/di_demo2/example_di.py
Normal file
18
examples/di_demo2/example_di.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
import os
|
||||
|
||||
|
||||
class ApiClient:
|
||||
|
||||
def __init__(self, api_key: str, timeout: int):
|
||||
self.api_key = api_key
|
||||
self.timeout = timeout
|
||||
|
||||
|
||||
class Service:
|
||||
|
||||
def __init__(self, api_client: ApiClient):
|
||||
self.api_client = api_client
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
|
18
examples/di_demo2/example_no_di.py
Normal file
18
examples/di_demo2/example_no_di.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
import os
|
||||
|
||||
|
||||
class ApiClient:
|
||||
|
||||
def __init__(self):
|
||||
self.api_key = os.getenv('API_KEY')
|
||||
self.timeout = os.getenv('TIMEOUT')
|
||||
|
||||
|
||||
class Service:
|
||||
|
||||
def __init__(self):
|
||||
self.api_client = ApiClient()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
service = Service()
|
11
examples/di_demo2/test.py
Normal file
11
examples/di_demo2/test.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from unittest import mock
|
||||
|
||||
from demo import Container
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
container = Container()
|
||||
|
||||
with container.api_client.override(mock.Mock()):
|
||||
service = container.service()
|
||||
assert isinstance(service.api_client, mock.Mock)
|
|
@ -1,6 +1,6 @@
|
|||
"""Dependency injector top-level package."""
|
||||
|
||||
__version__ = '3.30.2'
|
||||
__version__ = '3.30.3'
|
||||
"""Version number that follows semantic versioning.
|
||||
|
||||
:type: str
|
||||
|
|
Loading…
Reference in New Issue
Block a user