mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Update containers documentation
+ Refactor provider overriding system
This commit is contained in:
parent
71c871caf7
commit
1eee0fe529
|
@ -10,15 +10,44 @@ from dependency_injector import (
|
|||
|
||||
|
||||
class DynamicContainer(object):
|
||||
"""Dynamic inversion of control container."""
|
||||
"""Dynamic inversion of control container.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
services = DynamicContainer()
|
||||
services.auth = providers.Factory(AuthService)
|
||||
services.users = providers.Factory(UsersService,
|
||||
auth_service=services.auth)
|
||||
|
||||
.. py:attribute:: providers
|
||||
|
||||
Read-only dictionary of all providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
|
||||
.. py:attribute:: overridden
|
||||
|
||||
Tuple of overriding containers.
|
||||
|
||||
:type: tuple[:py:class:`DynamicContainer`]
|
||||
|
||||
.. py:attribute:: provider_type
|
||||
|
||||
Type of providers that could be placed in container.
|
||||
|
||||
:type: type
|
||||
"""
|
||||
|
||||
__IS_CONTAINER__ = True
|
||||
|
||||
def __init__(self):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
self.provider_type = providers.Provider
|
||||
self.providers = dict()
|
||||
self.overridden_by = tuple()
|
||||
self.overridden = tuple()
|
||||
super(DynamicContainer, self).__init__()
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
@ -26,6 +55,14 @@ class DynamicContainer(object):
|
|||
|
||||
If value of attribute is provider, it will be added into providers
|
||||
dictionary.
|
||||
|
||||
:param name: Attribute's name
|
||||
:type name: str
|
||||
|
||||
:param value: Attribute's value
|
||||
:type value: object
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if utils.is_provider(value):
|
||||
_check_provider_type(self, value)
|
||||
|
@ -37,6 +74,11 @@ class DynamicContainer(object):
|
|||
|
||||
If value of attribute is provider, it will be deleted from providers
|
||||
dictionary.
|
||||
|
||||
:param name: Attribute's name
|
||||
:type name: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if name in self.providers:
|
||||
del self.providers[name]
|
||||
|
@ -46,10 +88,10 @@ class DynamicContainer(object):
|
|||
"""Override current container by overriding container.
|
||||
|
||||
:param overriding: Overriding container.
|
||||
:type overriding: :py:class:`DeclarativeContainer`
|
||||
:type overriding: :py:class:`DynamicContainer`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error` if trying to
|
||||
override container by itself or its subclasses
|
||||
override container by itself
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
|
@ -57,7 +99,7 @@ class DynamicContainer(object):
|
|||
raise errors.Error('Container {0} could not be overridden '
|
||||
'with itself'.format(self))
|
||||
|
||||
self.overridden_by += (overriding,)
|
||||
self.overridden += (overriding,)
|
||||
|
||||
for name, provider in six.iteritems(overriding.providers):
|
||||
try:
|
||||
|
@ -70,10 +112,10 @@ class DynamicContainer(object):
|
|||
|
||||
:rtype: None
|
||||
"""
|
||||
if not self.overridden_by:
|
||||
if not self.overridden:
|
||||
raise errors.Error('Container {0} is not overridden'.format(self))
|
||||
|
||||
self.overridden_by = self.overridden_by[:-1]
|
||||
self.overridden = self.overridden[:-1]
|
||||
|
||||
for provider in six.itervalues(self.providers):
|
||||
provider.reset_last_overriding()
|
||||
|
@ -83,7 +125,7 @@ class DynamicContainer(object):
|
|||
|
||||
:rtype: None
|
||||
"""
|
||||
self.overridden_by = tuple()
|
||||
self.overridden = tuple()
|
||||
|
||||
for provider in six.itervalues(self.providers):
|
||||
provider.reset_override()
|
||||
|
@ -120,6 +162,14 @@ class DeclarativeContainerMetaClass(type):
|
|||
|
||||
If value of attribute is provider, it will be added into providers
|
||||
dictionary.
|
||||
|
||||
:param name: Attribute's name
|
||||
:type name: str
|
||||
|
||||
:param value: Attribute's value
|
||||
:type value: object
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if utils.is_provider(value):
|
||||
_check_provider_type(cls, value)
|
||||
|
@ -132,6 +182,11 @@ class DeclarativeContainerMetaClass(type):
|
|||
|
||||
If value of attribute is provider, it will be deleted from providers
|
||||
dictionary.
|
||||
|
||||
:param name: Attribute's name
|
||||
:type name: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if name in cls.providers and name in cls.cls_providers:
|
||||
del cls.providers[name]
|
||||
|
@ -141,21 +196,61 @@ class DeclarativeContainerMetaClass(type):
|
|||
|
||||
@six.add_metaclass(DeclarativeContainerMetaClass)
|
||||
class DeclarativeContainer(object):
|
||||
"""Declarative inversion of control container."""
|
||||
"""Declarative inversion of control container.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Services(DeclarativeContainer):
|
||||
auth = providers.Factory(AuthService)
|
||||
users = providers.Factory(UsersService,
|
||||
auth_service=auth)
|
||||
"""
|
||||
|
||||
__IS_CONTAINER__ = True
|
||||
|
||||
provider_type = providers.Provider
|
||||
"""Type of providers that could be placed in container.
|
||||
|
||||
providers = dict()
|
||||
cls_providers = dict()
|
||||
inherited_providers = dict()
|
||||
overridden_by = tuple()
|
||||
:type: type
|
||||
"""
|
||||
|
||||
instance_type = DynamicContainer
|
||||
"""Type of container that is returned on instantiating declarative
|
||||
container.
|
||||
|
||||
:type: type
|
||||
"""
|
||||
|
||||
providers = dict()
|
||||
"""Read-only dictionary of all providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
|
||||
cls_providers = dict()
|
||||
"""Read-only dictionary of current container providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
|
||||
inherited_providers = dict()
|
||||
"""Read-only dictionary of inherited providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
|
||||
overridden = tuple()
|
||||
"""Tuple of overriding containers.
|
||||
|
||||
:type: tuple[:py:class:`DeclarativeContainer`]
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""Constructor."""
|
||||
"""Constructor.
|
||||
|
||||
:return: Dynamic container with copy of all providers.
|
||||
:rtype: :py:class:`DynamicContainer`
|
||||
"""
|
||||
container = cls.instance_type(*args, **kwargs)
|
||||
container.provider_type = cls.provider_type
|
||||
|
||||
|
@ -180,7 +275,7 @@ class DeclarativeContainer(object):
|
|||
raise errors.Error('Container {0} could not be overridden '
|
||||
'with itself or its subclasses'.format(cls))
|
||||
|
||||
cls.overridden_by += (overriding,)
|
||||
cls.overridden += (overriding,)
|
||||
|
||||
for name, provider in six.iteritems(overriding.cls_providers):
|
||||
try:
|
||||
|
@ -194,10 +289,10 @@ class DeclarativeContainer(object):
|
|||
|
||||
:rtype: None
|
||||
"""
|
||||
if not cls.overridden_by:
|
||||
if not cls.overridden:
|
||||
raise errors.Error('Container {0} is not overridden'.format(cls))
|
||||
|
||||
cls.overridden_by = cls.overridden_by[:-1]
|
||||
cls.overridden = cls.overridden[:-1]
|
||||
|
||||
for provider in six.itervalues(cls.providers):
|
||||
provider.reset_last_overriding()
|
||||
|
@ -208,7 +303,7 @@ class DeclarativeContainer(object):
|
|||
|
||||
:rtype: None
|
||||
"""
|
||||
cls.overridden_by = tuple()
|
||||
cls.overridden = tuple()
|
||||
|
||||
for provider in six.itervalues(cls.providers):
|
||||
provider.reset_override()
|
||||
|
|
|
@ -51,7 +51,7 @@ class Provider(object):
|
|||
|
||||
All providers should extend this class.
|
||||
|
||||
.. py:attribute:: overridden_by
|
||||
.. py:attribute:: overridden
|
||||
|
||||
Tuple of overriding providers, if any.
|
||||
|
||||
|
@ -60,11 +60,11 @@ class Provider(object):
|
|||
|
||||
__IS_PROVIDER__ = True
|
||||
__OPTIMIZED_CALLS__ = True
|
||||
__slots__ = ('overridden_by', 'provide', '__call__')
|
||||
__slots__ = ('overridden', 'provide', '__call__')
|
||||
|
||||
def __init__(self):
|
||||
"""Initializer."""
|
||||
self.overridden_by = tuple()
|
||||
self.overridden = tuple()
|
||||
super(Provider, self).__init__()
|
||||
# Enable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
|
@ -81,7 +81,9 @@ class Provider(object):
|
|||
|
||||
def _call_last_overriding(self, *args, **kwargs):
|
||||
"""Call last overriding provider and return result."""
|
||||
return self.last_overriding(*args, **kwargs)
|
||||
return (self.overridden[-1](*args, **kwargs)
|
||||
if self.overridden
|
||||
else None)
|
||||
|
||||
def provide_injection(self):
|
||||
"""Injection strategy implementation.
|
||||
|
@ -90,22 +92,6 @@ class Provider(object):
|
|||
"""
|
||||
return self.provide()
|
||||
|
||||
@property
|
||||
def is_overridden(self):
|
||||
"""Read-only property that is set to ``True`` if provider is overridden.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return bool(self.overridden_by)
|
||||
|
||||
@property
|
||||
def last_overriding(self):
|
||||
"""Read-only reference to the last overriding provider, if any.
|
||||
|
||||
:type: :py:class:`Provider` | None
|
||||
"""
|
||||
return self.overridden_by[-1] if self.overridden_by else None
|
||||
|
||||
def override(self, provider):
|
||||
"""Override provider with another provider.
|
||||
|
||||
|
@ -124,7 +110,7 @@ class Provider(object):
|
|||
if not is_provider(provider):
|
||||
provider = Object(provider)
|
||||
|
||||
self.overridden_by += (ensure_is_provider(provider),)
|
||||
self.overridden += (ensure_is_provider(provider),)
|
||||
|
||||
# Disable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
|
@ -140,12 +126,12 @@ class Provider(object):
|
|||
|
||||
:rtype: None
|
||||
"""
|
||||
if not self.overridden_by:
|
||||
if not self.overridden:
|
||||
raise Error('Provider {0} is not overridden'.format(str(self)))
|
||||
|
||||
self.overridden_by = self.overridden_by[:-1]
|
||||
self.overridden = self.overridden[:-1]
|
||||
|
||||
if not self.is_overridden:
|
||||
if not self.overridden:
|
||||
# Enable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
self.__call__ = self.provide = self._provide
|
||||
|
@ -155,7 +141,7 @@ class Provider(object):
|
|||
|
||||
:rtype: None
|
||||
"""
|
||||
self.overridden_by = tuple()
|
||||
self.overridden = tuple()
|
||||
|
||||
# Enable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
|
@ -324,10 +310,10 @@ class ExternalDependency(Provider):
|
|||
|
||||
:rtype: object
|
||||
"""
|
||||
if not self.is_overridden:
|
||||
if not self.overridden:
|
||||
raise Error('Dependency is not defined')
|
||||
|
||||
instance = self.last_overriding(*args, **kwargs)
|
||||
instance = self._call_last_overriding(*args, **kwargs)
|
||||
|
||||
if not isinstance(instance, self.instance_of):
|
||||
raise Error('{0} is not an '.format(instance) +
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
Declarative containers
|
||||
--------------------
|
||||
----------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
:py:class:`DeclarativeContainer` is a container of providers 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 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).
|
||||
|
||||
Declarative containers have to extend base declarative container class -
|
||||
:py:class:`dependency_injector.containers.DeclarativeContainer`.
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
Dynamic catalogs
|
||||
----------------
|
||||
Dynamic containers
|
||||
------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
:py:class:`DynamicCatalog` is a catalog of providers that could be created in
|
||||
application's runtime. It should cover most of the cases when list of
|
||||
providers that would be included in catalog is non-deterministic in terms of
|
||||
apllication code (catalog's structure could be determined just after
|
||||
application will be started and will do some initial work, like parsing list
|
||||
of catalog's providers from the configuration).
|
||||
: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:`DeclarativeCatalog` and :py:class:`DynamicCatalog` have
|
||||
100% API parity.
|
||||
While :py:class:`DeclarativeContainer` acts on class-level,
|
||||
:py:class:`DynamicContainer` does the same on instance-level.
|
||||
|
||||
Main difference between :py:class:`DeclarativeCatalog` and
|
||||
:py:class:`DynamicCatalog` is that :py:class:`DeclarativeCatalog` acts on
|
||||
class-level, while :py:class:`DynamicCatalog` do the same on
|
||||
instance-level.
|
||||
Here is an simple example of defining dynamic container with several factories:
|
||||
|
||||
Here is an simple example of defining dynamic catalog with several factories:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/dynamic.py
|
||||
.. literalinclude:: ../../examples/containers/dynamic.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
Next one example demonstrates creation and runtime filling of dynamic catalog:
|
||||
Next example demonstrates creation of dynamic container based on some
|
||||
configuration:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/dynamic_runtime_creation.py
|
||||
.. literalinclude:: ../../examples/containers/dynamic_runtime_creation.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Containers
|
||||
==========
|
||||
IoC Containers
|
||||
==============
|
||||
|
||||
Containers are collections of providers. Main purpose of containers is to group
|
||||
providers.
|
||||
|
|
|
@ -1,52 +1,40 @@
|
|||
Overriding of catalogs
|
||||
----------------------
|
||||
Overriding of containers
|
||||
------------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
Catalogs can be overridden by other catalogs. This, actually, means that
|
||||
all of the providers from overriding catalog will override providers with the
|
||||
same names in overridden catalog.
|
||||
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.
|
||||
|
||||
There are two ways to override :py:class:`DeclarativeCatalog` with another
|
||||
catalog:
|
||||
There are two ways to override :py:class:`DeclarativeContainer` with another
|
||||
container:
|
||||
|
||||
- Use :py:meth:`DeclarativeCatalog.override` method.
|
||||
- Use :py:meth:`DeclarativeContainer.override` method.
|
||||
- Use :py:func:`override` class decorator.
|
||||
|
||||
Example of overriding catalog using :py:meth:`DeclarativeCatalog.override`
|
||||
Example of overriding container using :py:meth:`DeclarativeContainer.override`
|
||||
method:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override_declarative.py
|
||||
.. literalinclude:: ../../examples/containers/override_declarative.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
Example of overriding catalog using :py:func:`override` decorator:
|
||||
Example of overriding container using :py:func:`override` decorator:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override_declarative_decorator.py
|
||||
.. literalinclude:: ../../examples/containers/override_declarative_decorator.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
Also there are several useful :py:class:`DeclarativeCatalog` methods and
|
||||
properties that help to work with catalog overridings:
|
||||
Also there are several useful :py:class:`DeclarativeContainer` methods and
|
||||
properties that help to work with container overridings:
|
||||
|
||||
- :py:attr:`DeclarativeCatalog.is_overridden` - read-only property that is set
|
||||
to ``True`` if catalog is overridden.
|
||||
- :py:attr:`DeclarativeCatalog.last_overriding` - read-only reference to
|
||||
the last overriding catalog, if any.
|
||||
- :py:attr:`DeclarativeCatalog.overridden_by` - tuple of all overriding
|
||||
catalogs.
|
||||
- :py:meth:`DeclarativeCatalog.reset_last_overriding()` - reset last
|
||||
overriding catalog.
|
||||
- :py:meth:`DeclarativeCatalog.reset_override()` - reset all overridings for
|
||||
all catalog providers.
|
||||
- :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:`DynamicCatalog` has exactly the same functionality, except of
|
||||
:py:func:`override` decorator. Also :py:class:`DynamicCatalog` can override
|
||||
:py:class:`DeclarativeCatalog` and vise versa.
|
||||
|
||||
Example of overriding :py:class:`DeclarativeCatalog` by
|
||||
:py:class:`DynamicCatalog`:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override_declarative_by_dynamic.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:py:class:`DynamicContainer` has exactly the same functionality, except of
|
||||
:py:func:`override` decorator.
|
||||
|
|
|
@ -1,45 +1,24 @@
|
|||
Specialization of catalogs
|
||||
--------------------------
|
||||
Specialization of containers
|
||||
----------------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.containers
|
||||
|
||||
:py:class:`DeclarativeCatalog` and :py:class:`DynamicCatalog` could be
|
||||
specialized for any kind of needs via declaring its subclasses.
|
||||
:py:class:`DeclarativeContainer` could be specialized for any kind of needs
|
||||
via declaring its subclasses.
|
||||
|
||||
One of such `builtin` features is a limitation to
|
||||
:py:class:`DeclarativeCatalog` (and :py:class:`DynamicCatalog`) provider type.
|
||||
One of such `builtin` features is a limitation for providers type.
|
||||
|
||||
Next example shows usage of this feature with :py:class:`DeclarativeCatalog`
|
||||
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:
|
||||
|
||||
|
||||
Listing of `services.py`:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/declarative_provider_type/services.py
|
||||
.. literalinclude:: ../../examples/containers/declarative_provider_type.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
Listing of `catalog.py`:
|
||||
Limitation for providers type could be used with :py:class:`DynamicContainer`
|
||||
as well:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/declarative_provider_type/catalog.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
Limitation to provider type could be used with :py:class:`DynamicCatalog`
|
||||
as well.
|
||||
|
||||
Next example does the same that previous one, but use
|
||||
:py:class:`DynamicCatalog` instead of :py:class:`DeclarativeCatalog`:
|
||||
|
||||
Listing of `services.py`:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/dynamic_provider_type/services.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
Listing of `catalog.py`:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/dynamic_provider_type/catalog.py
|
||||
.. literalinclude:: ../../examples/containers/dynamic_provider_type.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
|
48
examples/containers/declarative_provider_type.py
Normal file
48
examples/containers/declarative_provider_type.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
"""Specializing declarative container and factory provider example."""
|
||||
|
||||
import collections
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
import dependency_injector.errors as errors
|
||||
|
||||
|
||||
class SequenceProvider(providers.Factory):
|
||||
"""Sequence factory.
|
||||
|
||||
Can provide only sequence objects.
|
||||
"""
|
||||
|
||||
provided_type = collections.Sequence
|
||||
|
||||
|
||||
class SequencesContainer(containers.DeclarativeContainer):
|
||||
"""IoC container.
|
||||
|
||||
Can contain only sequence providers.
|
||||
"""
|
||||
|
||||
provider_type = SequenceProvider
|
||||
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
class _SequenceContaier3(SequencesContainer):
|
||||
list_provider = SequenceProvider(list)
|
||||
|
||||
assert _SequenceContaier3.list_provider() == list()
|
|
@ -1,17 +0,0 @@
|
|||
"""Specialized declarative IoC container example."""
|
||||
|
||||
import core
|
||||
import services
|
||||
|
||||
|
||||
class Services(core.ServicesContainer):
|
||||
"""IoC container of service providers."""
|
||||
|
||||
users = core.ServiceProvider(services.UsersService,
|
||||
config={'option1': '111',
|
||||
'option2': '222'})
|
||||
|
||||
auth = core.ServiceProvider(services.AuthService,
|
||||
config={'option3': '333',
|
||||
'option4': '444'},
|
||||
users_service=users)
|
|
@ -1,26 +0,0 @@
|
|||
"""Base classes for services."""
|
||||
|
||||
from dependency_injector import containers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class BaseService(object):
|
||||
"""Base service class."""
|
||||
|
||||
|
||||
class ServiceProvider(providers.Factory):
|
||||
"""Service provider.
|
||||
|
||||
Can provide :py:class:`Base` only.
|
||||
"""
|
||||
|
||||
provided_type = BaseService
|
||||
|
||||
|
||||
class ServicesContainer(containers.DeclarativeContainer):
|
||||
"""Base IoC container of service providers.
|
||||
|
||||
Can include :py:class:`Provider`'s only.
|
||||
"""
|
||||
|
||||
provider_type = ServiceProvider
|
|
@ -1,42 +0,0 @@
|
|||
"""Main module."""
|
||||
|
||||
import core
|
||||
import services
|
||||
import container
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import errors
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Creating users & auth services:
|
||||
users_service = container.Services.users()
|
||||
auth_service = container.Services.auth()
|
||||
|
||||
# Making some asserts:
|
||||
assert users_service.config == {'option1': '111',
|
||||
'option2': '222'}
|
||||
assert auth_service.config == {'option3': '333',
|
||||
'option4': '444'}
|
||||
assert isinstance(auth_service.users_service, services.UsersService)
|
||||
|
||||
# Trying to declare services container with other provider type:
|
||||
try:
|
||||
class _Services1(core.ServicesContainer):
|
||||
|
||||
users = providers.Factory(services.UsersService)
|
||||
except errors.Error as exception:
|
||||
print exception
|
||||
# <class '__main__._Services1'> can contain only
|
||||
# <class 'core.ServiceProvider'> instances
|
||||
|
||||
# Trying to declare services container with correct provider by invalid
|
||||
# provided type:
|
||||
try:
|
||||
class _Services2(core.ServicesContainer):
|
||||
|
||||
users = core.ServiceProvider(object)
|
||||
except errors.Error as exception:
|
||||
print exception
|
||||
# <class 'core.ServiceProvider'> can provide only
|
||||
# <class 'core.BaseService'> instances
|
|
@ -1,22 +0,0 @@
|
|||
"""Base classes for services."""
|
||||
|
||||
import core
|
||||
|
||||
|
||||
class UsersService(core.BaseService):
|
||||
"""Users service."""
|
||||
|
||||
def __init__(self, config):
|
||||
"""Initializer."""
|
||||
self.config = config
|
||||
super(UsersService, self).__init__()
|
||||
|
||||
|
||||
class AuthService(core.BaseService):
|
||||
"""Auth service."""
|
||||
|
||||
def __init__(self, config, users_service):
|
||||
"""Initializer."""
|
||||
self.config = config
|
||||
self.users_service = users_service
|
||||
super(AuthService, self).__init__()
|
18
examples/containers/dynamic.py
Normal file
18
examples/containers/dynamic.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
"""Dynamic container simple example."""
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
# Defining dynamic container:
|
||||
container = containers.DynamicContainer()
|
||||
container.factory1 = providers.Factory(object)
|
||||
container.factory2 = providers.Factory(object)
|
||||
|
||||
# Creating some objects:
|
||||
object1 = container.factory1()
|
||||
object2 = container.factory2()
|
||||
|
||||
# Making some asserts:
|
||||
assert object1 is not object2
|
||||
assert isinstance(object1, object) and isinstance(object2, object)
|
41
examples/containers/dynamic_provider_type.py
Normal file
41
examples/containers/dynamic_provider_type.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
"""Specializing dynamic container and factory provider example."""
|
||||
|
||||
import collections
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
import dependency_injector.errors as errors
|
||||
|
||||
|
||||
class SequenceProvider(providers.Factory):
|
||||
"""Sequence factory.
|
||||
|
||||
Can provide only sequence objects.
|
||||
"""
|
||||
|
||||
provided_type = collections.Sequence
|
||||
|
||||
|
||||
sequences_container = containers.DynamicContainer()
|
||||
sequences_container.provider_type = SequenceProvider
|
||||
|
||||
|
||||
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
|
||||
|
||||
try:
|
||||
sequences_container.object_provider = SequenceProvider(object)
|
||||
except errors.Error as exception:
|
||||
print exception
|
||||
# <class '__main__.SequenceProvider'> can provide only
|
||||
# <class '_abcoll.Sequence'> instances
|
||||
|
||||
sequences_container.list_provider = SequenceProvider(list)
|
||||
|
||||
assert sequences_container.list_provider() == list()
|
61
examples/containers/dynamic_runtime_creation.py
Normal file
61
examples/containers/dynamic_runtime_creation.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
"""Creation of dynamic container based on some configuration example."""
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
|
||||
|
||||
# Defining several example services:
|
||||
class UsersService(object):
|
||||
"""Example users service."""
|
||||
|
||||
|
||||
class AuthService(object):
|
||||
"""Example auth service."""
|
||||
|
||||
|
||||
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])
|
||||
|
||||
|
||||
# "Parsing" some configuration:
|
||||
config = {
|
||||
'services': {
|
||||
'users': {
|
||||
'class': '__main__.UsersService',
|
||||
'provider_class': 'dependency_injector.providers.Factory',
|
||||
},
|
||||
'auth': {
|
||||
'class': '__main__.AuthService',
|
||||
'provider_class': 'dependency_injector.providers.Factory',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Creating empty container of service providers:
|
||||
services = containers.DynamicContainer()
|
||||
|
||||
# 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'])
|
||||
|
||||
# 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)
|
|
@ -1,45 +1,28 @@
|
|||
"""Declarative IoC container overriding example."""
|
||||
|
||||
import collections
|
||||
|
||||
from dependency_injector import containers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
"""Example IoC container."""
|
||||
"""IoC container."""
|
||||
|
||||
object1_factory = providers.Factory(Object1,
|
||||
arg1=1,
|
||||
arg2=2)
|
||||
|
||||
object2_factory = providers.Factory(Object2,
|
||||
object1=object1_factory)
|
||||
sequence_factory = providers.Factory(list)
|
||||
|
||||
|
||||
class OverridingContainer(containers.DeclarativeContainer):
|
||||
"""Overriding IoC container."""
|
||||
|
||||
object2_factory = providers.Factory(ExtendedObject2)
|
||||
sequence_factory = providers.Factory(tuple)
|
||||
|
||||
|
||||
# Overriding `Container` with `OverridingContainer`:
|
||||
Container.override(OverridingContainer)
|
||||
|
||||
# Creating some objects using overridden container:
|
||||
object2_1 = Container.object2_factory()
|
||||
object2_2 = Container.object2_factory()
|
||||
sequence_1 = Container.sequence_factory([1, 2, 3])
|
||||
sequence_2 = Container.sequence_factory([3, 2, 1])
|
||||
|
||||
# Making some asserts:
|
||||
assert Container.overridden_by == (OverridingContainer,)
|
||||
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, ExtendedObject2)
|
||||
assert isinstance(object2_2, ExtendedObject2)
|
||||
assert Container.overridden == (OverridingContainer,)
|
||||
assert sequence_1 == (1, 2, 3) and sequence_2 == (3, 2, 1)
|
||||
|
|
|
@ -1,23 +1,13 @@
|
|||
"""Declarative IoC container overriding using `@override()` decorator."""
|
||||
|
||||
import collections
|
||||
|
||||
from dependency_injector import containers
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
"""Example IoC container."""
|
||||
"""IoC container."""
|
||||
|
||||
object1_factory = providers.Factory(Object1, arg1=1, arg2=2)
|
||||
|
||||
object2_factory = providers.Factory(Object2, object1=object1_factory)
|
||||
sequence_factory = providers.Factory(list)
|
||||
|
||||
|
||||
# Overriding `Container` with `OverridingContainer`:
|
||||
|
@ -25,17 +15,13 @@ class Container(containers.DeclarativeContainer):
|
|||
class OverridingContainer(containers.DeclarativeContainer):
|
||||
"""Overriding IoC container."""
|
||||
|
||||
object2_factory = providers.Factory(ExtendedObject2)
|
||||
sequence_factory = providers.Factory(tuple)
|
||||
|
||||
|
||||
# Creating some objects using overridden container:
|
||||
object2_1 = Container.object2_factory()
|
||||
object2_2 = Container.object2_factory()
|
||||
sequence_1 = Container.sequence_factory([1, 2, 3])
|
||||
sequence_2 = Container.sequence_factory([3, 2, 1])
|
||||
|
||||
# Making some asserts:
|
||||
assert Container.overridden_by == (OverridingContainer,)
|
||||
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, ExtendedObject2)
|
||||
assert isinstance(object2_2, ExtendedObject2)
|
||||
assert Container.overridden == (OverridingContainer,)
|
||||
assert sequence_1 == (1, 2, 3) and sequence_2 == (3, 2, 1)
|
||||
|
|
|
@ -42,14 +42,14 @@ class ProviderTests(unittest.TestCase):
|
|||
"""Test provider overriding."""
|
||||
overriding_provider = providers.Provider()
|
||||
self.provider.override(overriding_provider)
|
||||
self.assertTrue(self.provider.is_overridden)
|
||||
self.assertTrue(self.provider.overridden)
|
||||
|
||||
def test_overriding_context(self):
|
||||
"""Test provider overriding context."""
|
||||
overriding_provider = providers.Provider()
|
||||
with self.provider.override(overriding_provider):
|
||||
self.assertTrue(self.provider.is_overridden)
|
||||
self.assertFalse(self.provider.is_overridden)
|
||||
self.assertTrue(self.provider.overridden)
|
||||
self.assertFalse(self.provider.overridden)
|
||||
|
||||
def test_override_with_itself(self):
|
||||
"""Test provider overriding with itself."""
|
||||
|
@ -61,21 +61,6 @@ class ProviderTests(unittest.TestCase):
|
|||
self.provider.override(obj)
|
||||
self.assertIs(self.provider(), obj)
|
||||
|
||||
def test_last_overriding(self):
|
||||
"""Test getting last overriding provider."""
|
||||
overriding_provider1 = providers.Provider()
|
||||
overriding_provider2 = providers.Provider()
|
||||
|
||||
self.provider.override(overriding_provider1)
|
||||
self.assertIs(self.provider.last_overriding, overriding_provider1)
|
||||
|
||||
self.provider.override(overriding_provider2)
|
||||
self.assertIs(self.provider.last_overriding, overriding_provider2)
|
||||
|
||||
def test_last_overriding_of_not_overridden_provider(self):
|
||||
"""Test getting last overriding from not overridden provider."""
|
||||
self.assertIsNone(self.provider.last_overriding)
|
||||
|
||||
def test_reset_last_overriding(self):
|
||||
"""Test reseting of last overriding provider."""
|
||||
overriding_provider1 = providers.Provider()
|
||||
|
@ -84,13 +69,13 @@ class ProviderTests(unittest.TestCase):
|
|||
self.provider.override(overriding_provider1)
|
||||
self.provider.override(overriding_provider2)
|
||||
|
||||
self.assertIs(self.provider.last_overriding, overriding_provider2)
|
||||
self.assertIs(self.provider.overridden[-1], overriding_provider2)
|
||||
|
||||
self.provider.reset_last_overriding()
|
||||
self.assertIs(self.provider.last_overriding, overriding_provider1)
|
||||
self.assertIs(self.provider.overridden[-1], overriding_provider1)
|
||||
|
||||
self.provider.reset_last_overriding()
|
||||
self.assertFalse(self.provider.is_overridden)
|
||||
self.assertFalse(self.provider.overridden)
|
||||
|
||||
def test_reset_last_overriding_of_not_overridden_provider(self):
|
||||
"""Test resetting of last overriding on not overridden provier."""
|
||||
|
@ -101,13 +86,12 @@ class ProviderTests(unittest.TestCase):
|
|||
overriding_provider = providers.Provider()
|
||||
self.provider.override(overriding_provider)
|
||||
|
||||
self.assertTrue(self.provider.is_overridden)
|
||||
self.assertIs(self.provider.last_overriding, overriding_provider)
|
||||
self.assertTrue(self.provider.overridden)
|
||||
self.assertEqual(self.provider.overridden, (overriding_provider,))
|
||||
|
||||
self.provider.reset_override()
|
||||
|
||||
self.assertFalse(self.provider.is_overridden)
|
||||
self.assertIsNone(self.provider.last_overriding)
|
||||
self.assertEqual(self.provider.overridden, tuple())
|
||||
|
||||
def test_repr(self):
|
||||
"""Test representation of provider."""
|
||||
|
|
|
@ -138,10 +138,10 @@ class DeclarativeContainerTests(unittest.TestCase):
|
|||
_Container.override(_OverridingContainer1)
|
||||
_Container.override(_OverridingContainer2)
|
||||
|
||||
self.assertEqual(_Container.overridden_by,
|
||||
self.assertEqual(_Container.overridden,
|
||||
(_OverridingContainer1,
|
||||
_OverridingContainer2))
|
||||
self.assertEqual(_Container.p11.overridden_by,
|
||||
self.assertEqual(_Container.p11.overridden,
|
||||
(_OverridingContainer1.p11,
|
||||
_OverridingContainer2.p11))
|
||||
|
||||
|
@ -169,10 +169,10 @@ class DeclarativeContainerTests(unittest.TestCase):
|
|||
p11 = providers.Provider()
|
||||
p12 = providers.Provider()
|
||||
|
||||
self.assertEqual(_Container.overridden_by,
|
||||
self.assertEqual(_Container.overridden,
|
||||
(_OverridingContainer1,
|
||||
_OverridingContainer2))
|
||||
self.assertEqual(_Container.p11.overridden_by,
|
||||
self.assertEqual(_Container.p11.overridden,
|
||||
(_OverridingContainer1.p11,
|
||||
_OverridingContainer2.p11))
|
||||
|
||||
|
@ -192,9 +192,9 @@ class DeclarativeContainerTests(unittest.TestCase):
|
|||
_Container.override(_OverridingContainer2)
|
||||
_Container.reset_last_overriding()
|
||||
|
||||
self.assertEqual(_Container.overridden_by,
|
||||
self.assertEqual(_Container.overridden,
|
||||
(_OverridingContainer1,))
|
||||
self.assertEqual(_Container.p11.overridden_by,
|
||||
self.assertEqual(_Container.p11.overridden,
|
||||
(_OverridingContainer1.p11,))
|
||||
|
||||
def test_reset_last_overridding_when_not_overridden(self):
|
||||
|
@ -218,8 +218,8 @@ class DeclarativeContainerTests(unittest.TestCase):
|
|||
_Container.override(_OverridingContainer2)
|
||||
_Container.reset_override()
|
||||
|
||||
self.assertEqual(_Container.overridden_by, tuple())
|
||||
self.assertEqual(_Container.p11.overridden_by, tuple())
|
||||
self.assertEqual(_Container.overridden, tuple())
|
||||
self.assertEqual(_Container.p11.overridden, tuple())
|
||||
|
||||
def test_copy(self):
|
||||
"""Test copy decorator."""
|
||||
|
@ -361,15 +361,15 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
|
|||
container.override(overriding_container1)
|
||||
container.override(overriding_container2)
|
||||
|
||||
self.assertEqual(container.overridden_by,
|
||||
self.assertEqual(container.overridden,
|
||||
(overriding_container1,
|
||||
overriding_container2))
|
||||
self.assertEqual(container.p11.overridden_by,
|
||||
self.assertEqual(container.p11.overridden,
|
||||
(overriding_container1.p11,
|
||||
overriding_container2.p11))
|
||||
|
||||
self.assertEqual(_Container.overridden_by, tuple())
|
||||
self.assertEqual(_Container.p11.overridden_by, tuple())
|
||||
self.assertEqual(_Container.overridden, tuple())
|
||||
self.assertEqual(_Container.p11.overridden, tuple())
|
||||
|
||||
def test_override_with_itself(self):
|
||||
"""Test override container with itself."""
|
||||
|
@ -397,9 +397,9 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
|
|||
container.override(overriding_container2)
|
||||
container.reset_last_overriding()
|
||||
|
||||
self.assertEqual(container.overridden_by,
|
||||
self.assertEqual(container.overridden,
|
||||
(overriding_container1,))
|
||||
self.assertEqual(container.p11.overridden_by,
|
||||
self.assertEqual(container.p11.overridden,
|
||||
(overriding_container1.p11,))
|
||||
|
||||
def test_reset_last_overridding_when_not_overridden(self):
|
||||
|
@ -429,8 +429,8 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
|
|||
container.override(overriding_container2)
|
||||
container.reset_override()
|
||||
|
||||
self.assertEqual(container.overridden_by, tuple())
|
||||
self.assertEqual(container.p11.overridden_by, tuple())
|
||||
self.assertEqual(container.overridden, tuple())
|
||||
self.assertEqual(container.p11.overridden, tuple())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in New Issue
Block a user