Update containers documentation

+ Refactor provider overriding system
This commit is contained in:
Roman Mogilatov 2016-06-06 11:26:53 +03:00
parent 71c871caf7
commit 1eee0fe529
19 changed files with 392 additions and 334 deletions

View File

@ -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()

View File

@ -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) +

View File

@ -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`.

View File

@ -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:

View File

@ -1,5 +1,5 @@
Containers
==========
IoC Containers
==============
Containers are collections of providers. Main purpose of containers is to group
providers.

View File

@ -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.

View File

@ -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:

View 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()

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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__()

View 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)

View 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()

View 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)

View File

@ -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)

View File

@ -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)

View File

@ -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."""

View File

@ -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__':