Add dynamic containers

+ Drop catalogs
This commit is contained in:
Roman Mogilatov 2016-06-01 18:53:35 +03:00
parent be94a1badc
commit 3416728309
13 changed files with 257 additions and 1736 deletions

View File

@ -1,20 +0,0 @@
"""Dependency injector catalogs package."""
from dependency_injector.catalogs.dynamic import DynamicCatalog
from dependency_injector.catalogs.declarative import (
DeclarativeCatalogMetaClass,
DeclarativeCatalog,
)
from dependency_injector.catalogs.utils import (
copy,
override
)
__all__ = (
'DynamicCatalog',
'DeclarativeCatalogMetaClass',
'DeclarativeCatalog',
'copy',
'override',
)

View File

@ -1,440 +0,0 @@
"""Dependency injector declarative catalog module."""
import six
from dependency_injector.catalogs.dynamic import DynamicCatalog
from dependency_injector.utils import (
is_provider,
is_catalog,
is_declarative_catalog,
)
from dependency_injector.errors import (
Error,
UndefinedProviderError,
)
@six.python_2_unicode_compatible
class DeclarativeCatalogMetaClass(type):
"""Declarative catalog meta class."""
def __new__(mcs, class_name, bases, attributes):
"""Declarative catalog class factory."""
cls_providers = tuple((name, provider)
for name, provider in six.iteritems(attributes)
if is_provider(provider))
inherited_providers = tuple((name, provider)
for base in bases if is_catalog(base)
for name, provider in six.iteritems(
base.providers))
providers = cls_providers + inherited_providers
cls = type.__new__(mcs, class_name, bases, attributes)
if cls.provider_type:
cls._catalog = type('DynamicCatalog',
(DynamicCatalog,),
dict(provider_type=cls.provider_type))()
else:
cls._catalog = DynamicCatalog()
cls._catalog.bind_providers(dict(providers))
cls._cls_providers = dict(cls_providers)
cls._inherited_providers = dict(inherited_providers)
return cls
@property
def providers(cls):
"""Read-only dictionary of all providers.
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return cls._catalog.providers
@property
def cls_providers(cls):
"""Read-only dictionary of current catalog providers.
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return cls._cls_providers
@property
def inherited_providers(cls):
"""Read-only dictionary of inherited providers.
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return cls._inherited_providers
@property
def overridden_by(cls):
"""Tuple of overriding catalogs.
:type: tuple[
:py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`]
"""
return cls._catalog.overridden_by
@property
def is_overridden(cls):
"""Read-only property that is set to ``True`` if catalog is overridden.
:rtype: bool
"""
return cls._catalog.is_overridden
@property
def last_overriding(cls):
"""Read-only reference to the last overriding catalog, if any.
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog` |
None
"""
return cls._catalog.last_overriding
def __getattr__(cls, name):
"""Return provider with specified name or raise en error.
:param name: Attribute's name.
:type name: str
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
"""
raise UndefinedProviderError('There is no provider "{0}" in '
'catalog {1}'.format(name, cls))
def __setattr__(cls, name, value):
"""Handle setting of catalog attributes.
Setting of attributes works as usual, but if value of attribute is
provider, this provider will be bound to catalog.
:param name: Attribute's name.
:type name: str
:param value: Attribute's value.
:type value: :py:class:`dependency_injector.providers.Provider` |
object
:rtype: None
"""
if is_provider(value):
cls.bind_provider(name, value, _set_as_attribute=False)
return super(DeclarativeCatalogMetaClass, cls).__setattr__(name, value)
def __delattr__(cls, name):
"""Handle deleting of catalog attibute.
Deleting of attributes works as usual, but if value of attribute is
provider, this provider will be unbound from catalog.
:param name: Attribute's name.
:type name: str
:rtype: None
"""
if is_provider(getattr(cls, name)):
delattr(cls._catalog, name)
return super(DeclarativeCatalogMetaClass, cls).__delattr__(name)
def __repr__(cls):
"""Return string representation of the catalog.
:rtype: str
"""
return '<{0}({1})>'.format('.'.join((cls.__module__, cls.__name__)),
', '.join(six.iterkeys(cls.providers)))
__str__ = __repr__
@six.add_metaclass(DeclarativeCatalogMetaClass)
class DeclarativeCatalog(object):
"""Declarative catalog of providers.
:py:class:`DeclarativeCatalog` is a catalog 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 catalog is deterministic (catalog
will not change its structure in runtime).
.. code-block:: python
class Services(DeclarativeCatalog):
auth = providers.Factory(AuthService)
users = providers.Factory(UsersService)
users_service = Services.users()
.. py:attribute:: provider_type
If provider type is defined, :py:class:`DeclarativeCatalog` checks that
all of its providers are instances of
:py:attr:`DeclarativeCatalog.provider_type`.
:type: type | None
"""
provider_type = None
_catalog = DynamicCatalog
_cls_providers = dict()
_inherited_providers = dict()
__IS_CATALOG__ = True
@property
def providers(self):
"""Read-only dictionary of all providers.
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return self.__class__.providers
@property
def cls_providers(self):
"""Read-only dictionary of current catalog providers.
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return self.__class__.cls_providers
@property
def inherited_providers(self):
"""Read-only dictionary of inherited providers.
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return self.__class__.inherited_providers
@property
def overridden_by(self):
"""Tuple of overriding catalogs.
:rtype: tuple[:py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`]
"""
return self.__class__.overridden_by
@property
def is_overridden(self):
"""Read-only property that is set to ``True`` if catalog is overridden.
:rtype: bool
"""
return self.__class__.is_overridden
@property
def last_overriding(self):
"""Read-only reference to the last overriding catalog, if any.
:rtype: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog` |
None
"""
return self.__class__.last_overriding
@classmethod
def get_provider_bind_name(cls, provider):
"""Return provider's name in catalog.
:param provider: Provider instance.
:type provider: :py:class:`dependency_injector.providers.Provider`
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
:return: Provider's name.
:rtype: str
"""
return cls._catalog.get_provider_bind_name(provider)
@classmethod
def is_provider_bound(cls, provider):
"""Check if provider is bound to the catalog.
:param provider: Provider instance.
:type provider: :py:class:`dependency_injector.providers.Provider`
:rtype: bool
"""
return cls._catalog.is_provider_bound(provider)
@classmethod
def filter(cls, provider_type):
"""Return dictionary of providers, that are instance of provided type.
:param provider_type: Provider's type.
:type provider_type: :py:class:`dependency_injector.providers.Provider`
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return cls._catalog.filter(provider_type)
@classmethod
def override(cls, overriding):
"""Override current catalog providers by overriding catalog providers.
:param overriding: Overriding catalog.
:type overriding: :py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`
:raise: :py:exc:`dependency_injector.errors.Error` if trying to
override catalog by itself or its subclasses
:rtype: None
"""
if is_declarative_catalog(overriding) and issubclass(cls, overriding):
raise Error('Catalog {0} could not be overridden '
'with itself or its subclasses'.format(cls))
return cls._catalog.override(overriding)
@classmethod
def reset_last_overriding(cls):
"""Reset last overriding catalog.
:rtype: None
"""
cls._catalog.reset_last_overriding()
@classmethod
def reset_override(cls):
"""Reset all overridings for all catalog providers.
:rtype: None
"""
cls._catalog.reset_override()
@classmethod
def get_provider(cls, name):
"""Return provider with specified name or raise an error.
:param name: Provider's name.
:type name: str
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
:return: Provider with specified name.
:rtype: :py:class:`dependency_injector.providers.Provider`
"""
return cls._catalog.get_provider(name)
@classmethod
def bind_provider(cls, name, provider, force=False,
_set_as_attribute=True):
"""Bind provider to catalog with specified name.
:param name: Name of the provider.
:type name: str
:param provider: Provider instance.
:type provider: :py:class:`dependency_injector.providers.Provider`
:param force: Force binding of provider.
:type force: bool
:raise: :py:exc:`dependency_injector.errors.Error`
:rtype: None
"""
if cls._catalog.is_provider_bound(provider):
bindind_name = cls._catalog.get_provider_bind_name(provider)
if bindind_name == name and not force:
return
cls._catalog.bind_provider(name, provider, force)
cls.cls_providers[name] = provider
if _set_as_attribute:
setattr(cls, name, provider)
@classmethod
def bind_providers(cls, providers, force=False):
"""Bind providers dictionary to catalog.
:param providers: Dictionary of providers, where key is a name
and value is a provider.
:type providers:
dict[str, :py:class:`dependency_injector.providers.Provider`]
:param force: Force binding of providers.
:type force: bool
:raise: :py:exc:`dependency_injector.errors.Error`
:rtype: None
"""
for name, provider in six.iteritems(providers):
cls.bind_provider(name, provider, force=force)
@classmethod
def has_provider(cls, name):
"""Check if there is provider with certain name.
:param name: Provider's name.
:type name: str
:rtype: bool
"""
return hasattr(cls, name)
@classmethod
def unbind_provider(cls, name):
"""Remove provider binding.
:param name: Provider's name.
:type name: str
:rtype: None
"""
delattr(cls, name)
del cls.cls_providers[name]
@classmethod
def __getattr__(cls, name): # pragma: no cover
"""Return provider with specified name or raise en error.
:param name: Attribute's name.
:type name: str
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
"""
raise NotImplementedError('Implementated in metaclass')
@classmethod
def __setattr__(cls, name, value): # pragma: no cover
"""Handle setting of catalog attributes.
Setting of attributes works as usual, but if value of attribute is
provider, this provider will be bound to catalog.
:param name: Attribute's name.
:type name: str
:param value: Attribute's value.
:type value: :py:class:`dependency_injector.providers.Provider` |
object
:rtype: None
"""
raise NotImplementedError('Implementated in metaclass')
@classmethod
def __delattr__(cls, name): # pragma: no cover
"""Handle deleting of catalog attibute.
Deleting of attributes works as usual, but if value of attribute is
provider, this provider will be unbound from catalog.
:param name: Attribute's name.
:type name: str
:rtype: None
"""
raise NotImplementedError('Implementated in metaclass')

View File

@ -1,309 +0,0 @@
"""Dependency injector dynamic catalog module."""
import six
from dependency_injector.utils import (
is_provider,
ensure_is_provider,
)
from dependency_injector.errors import (
Error,
UndefinedProviderError,
)
@six.python_2_unicode_compatible
class DynamicCatalog(object):
"""Dynamic catalog of providers.
: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).
.. code-block:: python
services = DynamicCatalog(auth=providers.Factory(AuthService),
users=providers.Factory(UsersService))
users_service = services.users()
.. py:attribute:: providers
Dictionary of all providers.
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
.. py:attribute:: overridden_by
Tuple of overriding catalogs.
:type: tuple[
:py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`]
.. py:attribute:: provider_type
If provider type is defined, :py:class:`DynamicCatalog` checks that
all of its providers are instances of
:py:attr:`DynamicCatalog.provider_type`.
:type: type | None
"""
provider_type = None
__IS_CATALOG__ = True
__slots__ = ('providers', 'provider_names', 'overridden_by')
def __init__(self, **providers):
"""Initializer.
:param providers: Dictionary of catalog providers.
:type providers:
dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
self.providers = dict()
self.provider_names = dict()
self.overridden_by = tuple()
self.bind_providers(providers)
super(DynamicCatalog, self).__init__()
def get_provider_bind_name(self, provider):
"""Return provider's name in catalog.
:param provider: Provider instance.
:type provider: :py:class:`dependency_injector.providers.Provider`
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
:return: Provider's name.
:rtype: str
"""
if not self.is_provider_bound(provider):
raise Error('Can not find bind name for {0} in catalog {1}'.format(
provider, self))
return self.provider_names[provider]
def is_provider_bound(self, provider):
"""Check if provider is bound to the catalog.
:param provider: Provider instance.
:type provider: :py:class:`dependency_injector.providers.Provider`
:rtype: bool
"""
return provider in self.provider_names
def filter(self, provider_type):
"""Return dictionary of providers, that are instance of provided type.
:param provider_type: Provider's type.
:type provider_type: :py:class:`dependency_injector.providers.Provider`
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return dict((name, provider)
for name, provider in six.iteritems(self.providers)
if isinstance(provider, provider_type))
@property
def is_overridden(self):
"""Read-only property that is set to ``True`` if catalog is overridden.
:rtype: bool
"""
return bool(self.overridden_by)
@property
def last_overriding(self):
"""Read-only reference to the last overriding catalog, if any.
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog` |
None
"""
return self.overridden_by[-1] if self.overridden_by else None
def override(self, overriding):
"""Override current catalog providers by overriding catalog providers.
:param overriding: Overriding catalog.
:type overriding: :py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`
:raise: :py:exc:`dependency_injector.errors.Error` if trying to
override catalog by itself
:rtype: None
"""
if overriding is self:
raise Error('Catalog {0} could not be overridden '
'with itself'.format(self))
self.overridden_by += (overriding,)
for name, provider in six.iteritems(overriding.providers):
self.get_provider(name).override(provider)
def reset_last_overriding(self):
"""Reset last overriding catalog.
:rtype: None
"""
if not self.is_overridden:
raise Error('Catalog {0} is not overridden'.format(self))
self.overridden_by = self.overridden_by[:-1]
for provider in six.itervalues(self.providers):
provider.reset_last_overriding()
def reset_override(self):
"""Reset all overridings for all catalog providers.
:rtype: None
"""
self.overridden_by = tuple()
for provider in six.itervalues(self.providers):
provider.reset_override()
def get_provider(self, name):
"""Return provider with specified name or raise an error.
:param name: Provider's name.
:type name: str
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
:return: Provider with specified name.
:rtype: :py:class:`dependency_injector.providers.Provider`
"""
try:
return self.providers[name]
except KeyError:
raise UndefinedProviderError('{0} has no provider with such '
'name - {1}'.format(self, name))
def bind_provider(self, name, provider, force=False):
"""Bind provider to catalog with specified name.
:param name: Name of the provider.
:type name: str
:param provider: Provider instance.
:type provider: :py:class:`dependency_injector.providers.Provider`
:param force: Force binding of provider.
:type force: bool
:raise: :py:exc:`dependency_injector.errors.Error`
:rtype: None
"""
provider = ensure_is_provider(provider)
if (self.__class__.provider_type and
not isinstance(provider, self.__class__.provider_type)):
raise Error('{0} can contain only {1} instances'.format(
self, self.__class__.provider_type))
if not force:
if name in self.providers:
raise Error('Catalog {0} already has provider with '
'such name - {1}'.format(self, name))
if provider in self.provider_names:
raise Error('Catalog {0} already has such provider '
'instance - {1}'.format(self, provider))
self.providers[name] = provider
self.provider_names[provider] = name
def bind_providers(self, providers, force=False):
"""Bind providers dictionary to catalog.
:param providers: Dictionary of providers, where key is a name
and value is a provider.
:type providers:
dict[str, :py:class:`dependency_injector.providers.Provider`]
:param force: Force binding of providers.
:type force: bool
:raise: :py:exc:`dependency_injector.errors.Error`
:rtype: None
"""
for name, provider in six.iteritems(providers):
self.bind_provider(name, provider, force)
def has_provider(self, name):
"""Check if there is provider with certain name.
:param name: Provider's name.
:type name: str
:rtype: bool
"""
return name in self.providers
def unbind_provider(self, name):
"""Remove provider binding.
:param name: Provider's name.
:type name: str
:rtype: None
"""
provider = self.get_provider(name)
del self.providers[name]
del self.provider_names[provider]
def __getattr__(self, name):
"""Return provider with specified name or raise en error.
:param name: Attribute's name.
:type name: str
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
"""
return self.get_provider(name)
def __setattr__(self, name, value):
"""Handle setting of catalog attributes.
Setting of attributes works as usual, but if value of attribute is
provider, this provider will be bound to catalog.
:param name: Attribute's name.
:type name: str
:param value: Attribute's value.
:type value: :py:class:`dependency_injector.providers.Provider` |
object
:rtype: None
"""
if is_provider(value):
return self.bind_provider(name, value)
return super(DynamicCatalog, self).__setattr__(name, value)
def __delattr__(self, name):
"""Handle deleting of catalog attibute.
Deleting of attributes works as usual, but if value of attribute is
provider, this provider will be unbound from catalog.
:param name: Attribute's name.
:type name: str
:rtype: None
"""
self.unbind_provider(name)
def __repr__(self):
"""Return Python representation of catalog.
:rtype: str
"""
return '<{0}({1})>'.format('.'.join((self.__class__.__module__,
self.__class__.__name__)),
', '.join(six.iterkeys(self.providers)))
__str__ = __repr__

View File

@ -1,62 +0,0 @@
"""Dependency injector catalog utils."""
import six
from dependency_injector.utils import _copy_providers
from dependency_injector.errors import UndefinedProviderError
def copy(catalog):
""":py:class:`DeclarativeCatalog` copying decorator.
This decorator copy all providers from provided catalog to decorated one.
If one of the decorated catalog providers matches to source catalog
providers by name, it would be replaced by reference.
:param catalog: Catalog that should be copied by decorated catalog.
:type catalog: :py:class:`DeclarativeCatalog`
:return: Declarative catalog's copying decorator.
:rtype:
callable(:py:class:`DeclarativeCatalog`)
"""
def decorator(copied_catalog):
"""Copying decorator.
:param copied_catalog: Decorated catalog.
:type copied_catalog: :py:class:`DeclarativeCatalog`
:return: Decorated catalog.
:rtype:
:py:class:`DeclarativeCatalog`
"""
memo = dict()
for name, provider in six.iteritems(copied_catalog.cls_providers):
try:
source_provider = catalog.get_provider(name)
except UndefinedProviderError:
pass
else:
memo[id(source_provider)] = provider
copied_catalog.bind_providers(_copy_providers(catalog.providers, memo),
force=True)
return copied_catalog
return decorator
def override(catalog):
""":py:class:`DeclarativeCatalog` overriding decorator.
:param catalog: Catalog that should be overridden by decorated catalog.
:type catalog: :py:class:`DeclarativeCatalog`
:return: Declarative catalog's overriding decorator.
:rtype: callable(:py:class:`DeclarativeCatalog`)
"""
def decorator(overriding_catalog):
"""Overriding decorator."""
catalog.override(overriding_catalog)
return overriding_catalog
return decorator

View File

@ -9,6 +9,86 @@ from dependency_injector import (
)
class DynamicContainer(object):
"""Dynamic inversion of control container."""
__IS_CONTAINER__ = True
def __init__(self):
"""Initializer."""
self.provider_type = providers.Provider
self.providers = dict()
self.overridden_by = tuple()
super(DynamicContainer, self).__init__()
def __setattr__(self, name, value):
"""Set instance attribute.
If value of attribute is provider, it will be added into providers
dictionary.
"""
if utils.is_provider(value):
_check_provider_type(self, value)
self.providers[name] = value
super(DynamicContainer, self).__setattr__(name, value)
def __delattr__(self, name):
"""Delete instance attribute.
If value of attribute is provider, it will be deleted from providers
dictionary.
"""
if name in self.providers:
del self.providers[name]
super(DynamicContainer, self).__delattr__(name)
def override(self, overriding):
"""Override current container by overriding container.
:param overriding: Overriding container.
:type overriding: :py:class:`DeclarativeContainer`
:raise: :py:exc:`dependency_injector.errors.Error` if trying to
override container by itself or its subclasses
:rtype: None
"""
if overriding is self:
raise errors.Error('Container {0} could not be overridden '
'with itself'.format(self))
self.overridden_by += (overriding,)
for name, provider in six.iteritems(overriding.providers):
try:
getattr(self, name).override(provider)
except AttributeError:
pass
def reset_last_overriding(self):
"""Reset last overriding provider for each container providers.
:rtype: None
"""
if not self.overridden_by:
raise errors.Error('Container {0} is not overridden'.format(self))
self.overridden_by = self.overridden_by[:-1]
for provider in six.itervalues(self.providers):
provider.reset_last_overriding()
def reset_override(self):
"""Reset all overridings for each container providers.
:rtype: None
"""
self.overridden_by = tuple()
for provider in six.itervalues(self.providers):
provider.reset_override()
class DeclarativeContainerMetaClass(type):
"""Declarative inversion of control container meta class."""
@ -20,7 +100,7 @@ class DeclarativeContainerMetaClass(type):
inherited_providers = tuple((name, provider)
for base in bases if utils.is_container(
base)
base) and base is not DynamicContainer
for name, provider in six.iteritems(
base.cls_providers))
@ -70,9 +150,20 @@ class DeclarativeContainer(object):
providers = dict()
cls_providers = dict()
inherited_providers = dict()
overridden_by = tuple()
instance_type = DynamicContainer
def __new__(cls, *args, **kwargs):
"""Constructor."""
container = cls.instance_type(*args, **kwargs)
container.provider_type = cls.provider_type
for name, provider in six.iteritems(utils.deepcopy(cls.providers)):
setattr(container, name, provider)
return container
@classmethod
def override(cls, overriding):
"""Override current container by overriding container.
@ -163,7 +254,7 @@ def copy(container):
else:
memo[id(source_provider)] = provider
providers_copy = utils._copy_providers(container.providers, memo)
providers_copy = utils.deepcopy(container.providers, memo)
for name, provider in six.iteritems(providers_copy):
setattr(copied_container, name, provider)

View File

@ -1,7 +1,7 @@
"""Utils module."""
import sys
import copy
import copy as _copy
import types
import threading
@ -23,9 +23,9 @@ else: # pragma: no cover
_OBJECT_INIT = None
if six.PY2: # pragma: no cover
copy._deepcopy_dispatch[types.MethodType] = \
_copy._deepcopy_dispatch[types.MethodType] = \
lambda obj, memo: type(obj)(obj.im_func,
copy.deepcopy(obj.im_self, memo),
_copy.deepcopy(obj.im_self, memo),
obj.im_class)
@ -71,40 +71,6 @@ def is_container(instance):
getattr(instance, '__IS_CONTAINER__', False) is True)
def is_catalog(instance):
"""Check if instance is catalog instance.
:param instance: Instance to be checked.
:type instance: object
:rtype: bool
"""
return (hasattr(instance, '__IS_CATALOG__') and
getattr(instance, '__IS_CATALOG__', False) is True)
def is_dynamic_catalog(instance):
"""Check if instance is dynamic catalog instance.
:param instance: Instance to be checked.
:type instance: object
:rtype: bool
"""
return (not isinstance(instance, six.class_types) and is_catalog(instance))
def is_declarative_catalog(instance):
"""Check if instance is declarative catalog instance.
:param instance: Instance to be checked.
:type instance: object
:rtype: bool
"""
return (isinstance(instance, six.class_types) and is_catalog(instance))
def represent_provider(provider, provides):
"""Return string representation of provider.
@ -142,6 +108,6 @@ def fetch_cls_init(cls):
return cls_init
def _copy_providers(providers, memo=None):
"""Make full copy of providers dictionary."""
return copy.deepcopy(providers, memo)
def deepcopy(instance, memo=None):
"""Make full copy of instance."""
return _copy.deepcopy(instance, memo)

View File

@ -54,7 +54,6 @@ setup(name='dependency_injector',
download_url='https://pypi.python.org/pypi/dependency_injector',
license='BSD New',
packages=['dependency_injector',
'dependency_injector.catalogs',
'dependency_injector.providers'],
platforms=['any'],
zip_safe=True,

View File

@ -1 +0,0 @@
"""Dependency injector catalogs unittests."""

View File

@ -1,443 +0,0 @@
"""Dependency injector declarative catalog unittests."""
import unittest2 as unittest
from dependency_injector import (
catalogs,
providers,
injections,
errors,
)
class CatalogA(catalogs.DeclarativeCatalog):
"""Test catalog A."""
p11 = providers.Provider()
p12 = providers.Provider()
class CatalogB(CatalogA):
"""Test catalog B."""
p21 = providers.Provider()
p22 = providers.Provider()
class DeclarativeCatalogTests(unittest.TestCase):
"""Declarative catalog tests."""
def test_cls_providers(self):
"""Test `di.DeclarativeCatalog.cls_providers` contents."""
class CatalogA(catalogs.DeclarativeCatalog):
"""Test catalog A."""
p11 = providers.Provider()
p12 = providers.Provider()
class CatalogB(CatalogA):
"""Test catalog B."""
p21 = providers.Provider()
p22 = providers.Provider()
self.assertDictEqual(CatalogA.cls_providers,
dict(p11=CatalogA.p11,
p12=CatalogA.p12))
self.assertDictEqual(CatalogB.cls_providers,
dict(p21=CatalogB.p21,
p22=CatalogB.p22))
def test_inherited_providers(self):
"""Test `di.DeclarativeCatalog.inherited_providers` contents."""
self.assertDictEqual(CatalogA.inherited_providers, dict())
self.assertDictEqual(CatalogB.inherited_providers,
dict(p11=CatalogA.p11,
p12=CatalogA.p12))
def test_providers(self):
"""Test `di.DeclarativeCatalog.inherited_providers` contents."""
self.assertDictEqual(CatalogA.providers,
dict(p11=CatalogA.p11,
p12=CatalogA.p12))
self.assertDictEqual(CatalogB.providers,
dict(p11=CatalogA.p11,
p12=CatalogA.p12,
p21=CatalogB.p21,
p22=CatalogB.p22))
def test_bind_provider(self):
"""Test setting of provider via bind_provider() to catalog."""
px = providers.Provider()
py = providers.Provider()
CatalogA.bind_provider('px', px)
CatalogA.bind_provider('py', py)
self.assertIs(CatalogA.px, px)
self.assertIs(CatalogA.get_provider('px'), px)
self.assertIs(CatalogA.py, py)
self.assertIs(CatalogA.get_provider('py'), py)
del CatalogA.px
del CatalogA.py
def test_bind_existing_provider(self):
"""Test setting of provider via bind_provider() to catalog."""
with self.assertRaises(errors.Error):
CatalogA.p11 = providers.Provider()
with self.assertRaises(errors.Error):
CatalogA.bind_provider('p11', providers.Provider())
def test_bind_provider_with_valid_provided_type(self):
"""Test setting of provider with provider type restriction."""
class SomeProvider(providers.Provider):
"""Some provider."""
class SomeCatalog(catalogs.DeclarativeCatalog):
"""Some catalog with provider type restriction."""
provider_type = SomeProvider
px = SomeProvider()
py = SomeProvider()
SomeCatalog.bind_provider('px', px)
SomeCatalog.py = py
self.assertIs(SomeCatalog.px, px)
self.assertIs(SomeCatalog.get_provider('px'), px)
self.assertIs(SomeCatalog.py, py)
self.assertIs(SomeCatalog.get_provider('py'), py)
def test_bind_provider_with_invalid_provided_type(self):
"""Test setting of provider with provider type restriction."""
class SomeProvider(providers.Provider):
"""Some provider."""
class SomeCatalog(catalogs.DeclarativeCatalog):
"""Some catalog with provider type restriction."""
provider_type = SomeProvider
px = providers.Provider()
with self.assertRaises(errors.Error):
SomeCatalog.bind_provider('px', px)
with self.assertRaises(errors.Error):
SomeCatalog.px = px
with self.assertRaises(errors.Error):
SomeCatalog.bind_providers(dict(px=px))
def test_bind_providers(self):
"""Test setting of provider via bind_providers() to catalog."""
px = providers.Provider()
py = providers.Provider()
CatalogB.bind_providers(dict(px=px, py=py))
self.assertIs(CatalogB.px, px)
self.assertIs(CatalogB.get_provider('px'), px)
self.assertIs(CatalogB.py, py)
self.assertIs(CatalogB.get_provider('py'), py)
del CatalogB.px
del CatalogB.py
def test_setattr(self):
"""Test setting of providers via attributes to catalog."""
px = providers.Provider()
py = providers.Provider()
CatalogB.px = px
CatalogB.py = py
self.assertIs(CatalogB.px, px)
self.assertIs(CatalogB.get_provider('px'), px)
self.assertIs(CatalogB.py, py)
self.assertIs(CatalogB.get_provider('py'), py)
del CatalogB.px
del CatalogB.py
def test_unbind_provider(self):
"""Test that catalog unbinds provider correct."""
CatalogB.px = providers.Provider()
CatalogB.unbind_provider('px')
self.assertFalse(CatalogB.has_provider('px'))
def test_unbind_via_delattr(self):
"""Test that catalog unbinds provider correct."""
CatalogB.px = providers.Provider()
del CatalogB.px
self.assertFalse(CatalogB.has_provider('px'))
def test_provider_is_bound(self):
"""Test that providers are bound to the catalogs."""
self.assertTrue(CatalogA.is_provider_bound(CatalogA.p11))
self.assertEquals(CatalogA.get_provider_bind_name(CatalogA.p11), 'p11')
self.assertTrue(CatalogA.is_provider_bound(CatalogA.p12))
self.assertEquals(CatalogA.get_provider_bind_name(CatalogA.p12), 'p12')
def test_provider_binding_to_different_catalogs(self):
"""Test that provider could be bound to different catalogs."""
p11 = CatalogA.p11
p12 = CatalogA.p12
class CatalogD(catalogs.DeclarativeCatalog):
"""Test catalog."""
pd1 = p11
pd2 = p12
class CatalogE(catalogs.DeclarativeCatalog):
"""Test catalog."""
pe1 = p11
pe2 = p12
self.assertTrue(CatalogA.is_provider_bound(p11))
self.assertTrue(CatalogD.is_provider_bound(p11))
self.assertTrue(CatalogE.is_provider_bound(p11))
self.assertEquals(CatalogA.get_provider_bind_name(p11), 'p11')
self.assertEquals(CatalogD.get_provider_bind_name(p11), 'pd1')
self.assertEquals(CatalogE.get_provider_bind_name(p11), 'pe1')
self.assertTrue(CatalogA.is_provider_bound(p12))
self.assertTrue(CatalogD.is_provider_bound(p12))
self.assertTrue(CatalogE.is_provider_bound(p12))
self.assertEquals(CatalogA.get_provider_bind_name(p12), 'p12')
self.assertEquals(CatalogD.get_provider_bind_name(p12), 'pd2')
self.assertEquals(CatalogE.get_provider_bind_name(p12), 'pe2')
def test_provider_rebinding_to_the_same_catalog(self):
"""Test provider rebinding to the same catalog."""
with self.assertRaises(errors.Error):
class TestCatalog(catalogs.DeclarativeCatalog):
"""Test catalog."""
p1 = providers.Provider()
p2 = p1
def test_provider_rebinding_to_the_same_catalogs_hierarchy(self):
"""Test provider rebinding to the same catalogs hierarchy."""
class TestCatalog1(catalogs.DeclarativeCatalog):
"""Test catalog."""
p1 = providers.Provider()
with self.assertRaises(errors.Error):
class TestCatalog2(TestCatalog1):
"""Test catalog."""
p2 = TestCatalog1.p1
def test_get(self):
"""Test getting of providers using get() method."""
self.assertIs(CatalogB.get_provider('p11'), CatalogB.p11)
self.assertIs(CatalogB.get_provider('p12'), CatalogB.p12)
self.assertIs(CatalogB.get_provider('p22'), CatalogB.p22)
self.assertIs(CatalogB.get_provider('p22'), CatalogB.p22)
def test_get_undefined(self):
"""Test getting of undefined providers using get() method."""
with self.assertRaises(errors.UndefinedProviderError):
CatalogB.get('undefined')
with self.assertRaises(errors.UndefinedProviderError):
CatalogB.get_provider('undefined')
with self.assertRaises(errors.UndefinedProviderError):
CatalogB.undefined
def test_has(self):
"""Test checks of providers availability in catalog."""
self.assertTrue(CatalogB.has_provider('p11'))
self.assertTrue(CatalogB.has_provider('p12'))
self.assertTrue(CatalogB.has_provider('p21'))
self.assertTrue(CatalogB.has_provider('p22'))
self.assertFalse(CatalogB.has_provider('undefined'))
def test_filter_all_providers_by_type(self):
"""Test getting of all catalog providers of specific type."""
self.assertTrue(len(CatalogB.filter(providers.Provider)) == 4)
self.assertTrue(len(CatalogB.filter(providers.Object)) == 0)
def test_repr(self):
"""Test catalog representation."""
self.assertIn('CatalogA', repr(CatalogA))
self.assertIn('p11', repr(CatalogA))
self.assertIn('p12', repr(CatalogA))
self.assertIn('CatalogB', repr(CatalogB))
self.assertIn('p11', repr(CatalogB))
self.assertIn('p12', repr(CatalogB))
self.assertIn('p21', repr(CatalogB))
self.assertIn('p22', repr(CatalogB))
class TestCatalogWithProvidingCallbacks(unittest.TestCase):
"""Catalog with providing callback tests."""
def test_concept(self):
"""Test concept."""
class UsersService(object):
"""Users service, that has dependency on database."""
class AuthService(object):
"""Auth service, that has dependencies on users service."""
def __init__(self, users_service):
"""Initializer."""
self.users_service = users_service
class Services(catalogs.DeclarativeCatalog):
"""Catalog of service providers."""
@providers.Factory
def users():
"""Provide users service.
:rtype: providers.Provider -> UsersService
"""
return UsersService()
@providers.Factory
@injections.inject(users_service=users)
def auth(**kwargs):
"""Provide users service.
:rtype: providers.Provider -> AuthService
"""
return AuthService(**kwargs)
# Retrieving catalog providers:
users_service = Services.users()
auth_service = Services.auth()
# Making some asserts:
self.assertIsInstance(auth_service.users_service, UsersService)
self.assertIsNot(users_service, Services.users())
self.assertIsNot(auth_service, Services.auth())
# Overriding auth service provider and making some asserts:
class ExtendedAuthService(AuthService):
"""Extended version of auth service."""
def __init__(self, users_service, ttl):
"""Initializer."""
self.ttl = ttl
super(ExtendedAuthService, self).__init__(
users_service=users_service)
class OverriddenServices(Services):
"""Catalog of service providers."""
@providers.override(Services.auth)
@providers.Factory
@injections.inject(users_service=Services.users)
@injections.inject(ttl=3600)
def auth(**kwargs):
"""Provide users service.
:rtype: providers.Provider -> AuthService
"""
return ExtendedAuthService(**kwargs)
auth_service = Services.auth()
self.assertIsInstance(auth_service, ExtendedAuthService)
class CopyingTests(unittest.TestCase):
"""Declarative catalogs copying tests."""
def test_copy(self):
"""Test catalog providers copying."""
@catalogs.copy(CatalogA)
class CatalogA1(CatalogA):
pass
@catalogs.copy(CatalogA)
class CatalogA2(CatalogA):
pass
self.assertIsNot(CatalogA.p11, CatalogA1.p11)
self.assertIsNot(CatalogA.p12, CatalogA1.p12)
self.assertIsNot(CatalogA.p11, CatalogA2.p11)
self.assertIsNot(CatalogA.p12, CatalogA2.p12)
self.assertIsNot(CatalogA1.p11, CatalogA2.p11)
self.assertIsNot(CatalogA1.p12, CatalogA2.p12)
def test_copy_with_replacing(self):
"""Test catalog providers copying."""
class CatalogA(catalogs.DeclarativeCatalog):
p11 = providers.Object(0)
p12 = providers.Factory(dict) \
.add_kwargs(p11=p11)
@catalogs.copy(CatalogA)
class CatalogA1(CatalogA):
p11 = providers.Object(1)
p13 = providers.Object(11)
@catalogs.copy(CatalogA)
class CatalogA2(CatalogA):
p11 = providers.Object(2)
p13 = providers.Object(22)
self.assertIsNot(CatalogA.p11, CatalogA1.p11)
self.assertIsNot(CatalogA.p12, CatalogA1.p12)
self.assertIsNot(CatalogA.p11, CatalogA2.p11)
self.assertIsNot(CatalogA.p12, CatalogA2.p12)
self.assertIsNot(CatalogA1.p11, CatalogA2.p11)
self.assertIsNot(CatalogA1.p12, CatalogA2.p12)
self.assertIs(CatalogA.p12.kwargs['p11'], CatalogA.p11)
self.assertIs(CatalogA1.p12.kwargs['p11'], CatalogA1.p11)
self.assertIs(CatalogA2.p12.kwargs['p11'], CatalogA2.p11)
self.assertEqual(CatalogA.p12(), dict(p11=0))
self.assertEqual(CatalogA1.p12(), dict(p11=1))
self.assertEqual(CatalogA2.p12(), dict(p11=2))
self.assertEqual(CatalogA1.p13(), 11)
self.assertEqual(CatalogA2.p13(), 22)
class InstantiationTests(unittest.TestCase):
"""Declarative catalogs instantiation tests."""
def setUp(self):
"""Set test environment up."""
self.catalog = CatalogA()
def tearDown(self):
"""Tear test environment down."""
self.catalog = None
def test_access_instance_attributes(self):
"""Test accessing declarative catalog instance attributes."""
self.assertEqual(self.catalog.providers,
CatalogA.providers)
self.assertEqual(self.catalog.cls_providers,
CatalogA.cls_providers)
self.assertEqual(self.catalog.inherited_providers,
CatalogA.inherited_providers)
self.assertEqual(self.catalog.overridden_by,
CatalogA.overridden_by)
self.assertEqual(self.catalog.is_overridden,
CatalogA.is_overridden)
self.assertEqual(self.catalog.last_overriding,
CatalogA.last_overriding)

View File

@ -1,221 +0,0 @@
"""Dependency injector dynamic catalog unittests."""
import unittest2 as unittest
from dependency_injector import (
catalogs,
providers,
errors,
)
class DynamicCatalogTests(unittest.TestCase):
"""Dynamic catalog tests."""
catalog = None
""":type: di.DynamicCatalog"""
def setUp(self):
"""Set test environment up."""
self.catalog = catalogs.DynamicCatalog(p1=providers.Provider(),
p2=providers.Provider())
def test_providers(self):
"""Test `di.DeclarativeCatalog.inherited_providers` contents."""
self.assertDictEqual(self.catalog.providers,
dict(p1=self.catalog.p1,
p2=self.catalog.p2))
def test_bind_provider(self):
"""Test setting of provider via bind_provider() to catalog."""
px = providers.Provider()
py = providers.Provider()
self.catalog.bind_provider('px', px)
self.catalog.bind_provider('py', py)
self.assertIs(self.catalog.px, px)
self.assertIs(self.catalog.get_provider('px'), px)
self.assertIs(self.catalog.py, py)
self.assertIs(self.catalog.get_provider('py'), py)
def test_bind_existing_provider(self):
"""Test setting of provider via bind_provider() to catalog."""
with self.assertRaises(errors.Error):
self.catalog.bind_provider('p1', providers.Factory(object))
def test_force_bind_existing_provider(self):
"""Test setting of provider via bind_provider() to catalog."""
p1 = providers.Factory(object)
self.catalog.bind_provider('p1', p1, force=True)
self.assertIs(self.catalog.p1, p1)
def test_bind_provider_with_valid_provided_type(self):
"""Test setting of provider with provider type restriction."""
class SomeProvider(providers.Provider):
"""Some provider."""
class SomeCatalog(catalogs.DynamicCatalog):
"""Some catalog with provider type restriction."""
provider_type = SomeProvider
px = SomeProvider()
py = SomeProvider()
catalog = SomeCatalog()
catalog.bind_provider('px', px)
catalog.py = py
self.assertIs(catalog.px, px)
self.assertIs(catalog.get_provider('px'), px)
self.assertIs(catalog.py, py)
self.assertIs(catalog.get_provider('py'), py)
def test_bind_provider_with_invalid_provided_type(self):
"""Test setting of provider with provider type restriction."""
class SomeProvider(providers.Provider):
"""Some provider."""
class SomeCatalog(catalogs.DynamicCatalog):
"""Some catalog with provider type restriction."""
provider_type = SomeProvider
px = providers.Provider()
catalog = SomeCatalog()
with self.assertRaises(errors.Error):
catalog.bind_provider('px', px)
with self.assertRaises(errors.Error):
catalog.px = px
with self.assertRaises(errors.Error):
catalog.bind_providers(dict(px=px))
def test_bind_providers(self):
"""Test setting of provider via bind_providers() to catalog."""
px = providers.Provider()
py = providers.Provider()
self.catalog.bind_providers(dict(px=px, py=py))
self.assertIs(self.catalog.px, px)
self.assertIs(self.catalog.get_provider('px'), px)
self.assertIs(self.catalog.py, py)
self.assertIs(self.catalog.get_provider('py'), py)
def test_bind_providers_with_existing(self):
"""Test setting of provider via bind_providers() to catalog."""
with self.assertRaises(errors.Error):
self.catalog.bind_providers(dict(p1=providers.Factory(object)))
def test_bind_providers_force(self):
"""Test setting of provider via bind_providers() to catalog."""
p1 = providers.Factory(object)
self.catalog.bind_providers(dict(p1=p1), force=True)
self.assertIs(self.catalog.p1, p1)
def test_setattr(self):
"""Test setting of providers via attributes to catalog."""
px = providers.Provider()
py = providers.Provider()
self.catalog.px = px
self.catalog.py = py
self.assertIs(self.catalog.px, px)
self.assertIs(self.catalog.get_provider('px'), px)
self.assertIs(self.catalog.py, py)
self.assertIs(self.catalog.get_provider('py'), py)
def test_unbind_provider(self):
"""Test that catalog unbinds provider correct."""
self.catalog.px = providers.Provider()
self.catalog.unbind_provider('px')
self.assertFalse(self.catalog.has_provider('px'))
def test_unbind_via_delattr(self):
"""Test that catalog unbinds provider correct."""
self.catalog.px = providers.Provider()
del self.catalog.px
self.assertFalse(self.catalog.has_provider('px'))
def test_provider_is_bound(self):
"""Test that providers are bound to the catalogs."""
self.assertTrue(self.catalog.is_provider_bound(self.catalog.p1))
self.assertEquals(
self.catalog.get_provider_bind_name(self.catalog.p1), 'p1')
self.assertTrue(self.catalog.is_provider_bound(self.catalog.p2))
self.assertEquals(
self.catalog.get_provider_bind_name(self.catalog.p2), 'p2')
def test_provider_binding_to_different_catalogs(self):
"""Test that provider could be bound to different catalogs."""
p1 = self.catalog.p1
p2 = self.catalog.p2
catalog_a = catalogs.DynamicCatalog(pa1=p1, pa2=p2)
catalog_b = catalogs.DynamicCatalog(pb1=p1, pb2=p2)
self.assertTrue(self.catalog.is_provider_bound(p1))
self.assertTrue(catalog_a.is_provider_bound(p1))
self.assertTrue(catalog_b.is_provider_bound(p1))
self.assertEquals(self.catalog.get_provider_bind_name(p1), 'p1')
self.assertEquals(catalog_a.get_provider_bind_name(p1), 'pa1')
self.assertEquals(catalog_b.get_provider_bind_name(p1), 'pb1')
self.assertTrue(self.catalog.is_provider_bound(p2))
self.assertTrue(catalog_a.is_provider_bound(p2))
self.assertTrue(catalog_b.is_provider_bound(p2))
self.assertEquals(self.catalog.get_provider_bind_name(p2), 'p2')
self.assertEquals(catalog_a.get_provider_bind_name(p2), 'pa2')
self.assertEquals(catalog_b.get_provider_bind_name(p2), 'pb2')
def test_provider_rebinding_to_the_same_catalog(self):
"""Test provider rebinding to the same catalog."""
with self.assertRaises(errors.Error):
self.catalog.p3 = self.catalog.p1
def test_provider_binding_with_the_same_name(self):
"""Test binding of provider with the same name."""
with self.assertRaises(errors.Error):
self.catalog.bind_provider('p1', providers.Provider())
def test_get(self):
"""Test getting of providers using get() method."""
self.assertIs(self.catalog.get_provider('p1'), self.catalog.p1)
self.assertIs(self.catalog.get_provider('p2'), self.catalog.p2)
def test_get_undefined(self):
"""Test getting of undefined providers using get() method."""
with self.assertRaises(errors.UndefinedProviderError):
self.catalog.get_provider('undefined')
with self.assertRaises(errors.UndefinedProviderError):
self.catalog.undefined
def test_has_provider(self):
"""Test checks of providers availability in catalog."""
self.assertTrue(self.catalog.has_provider('p1'))
self.assertTrue(self.catalog.has_provider('p2'))
self.assertFalse(self.catalog.has_provider('undefined'))
def test_filter_all_providers_by_type(self):
"""Test getting of all catalog providers of specific type."""
self.assertTrue(len(self.catalog.filter(providers.Provider)) == 2)
self.assertTrue(len(self.catalog.filter(providers.Object)) == 0)
def test_repr(self):
"""Test catalog representation."""
representation = repr(self.catalog)
self.assertIn('dependency_injector.catalogs.dynamic.DynamicCatalog',
representation)
self.assertIn('p1', representation)
self.assertIn('p2', representation)

View File

@ -1,142 +0,0 @@
"""Dependency injector catalogs overriding unittests."""
import unittest2 as unittest
from dependency_injector import (
catalogs,
providers,
errors,
)
class CatalogA(catalogs.DeclarativeCatalog):
"""Test catalog A."""
p11 = providers.Provider()
p12 = providers.Provider()
class CatalogB(CatalogA):
"""Test catalog B."""
p21 = providers.Provider()
p22 = providers.Provider()
class OverrideTests(unittest.TestCase):
"""Catalog overriding and override decorator test cases."""
def tearDown(self):
"""Tear test environment down."""
CatalogA.reset_override()
def test_overriding(self):
"""Test catalog overriding with another catalog."""
@catalogs.override(CatalogA)
class OverridingCatalog(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
p11 = providers.Object(1)
p12 = providers.Object(2)
self.assertEqual(CatalogA.p11(), 1)
self.assertEqual(CatalogA.p12(), 2)
self.assertEqual(len(CatalogA.overridden_by), 1)
def test_override_declarative_catalog_with_itself(self):
"""Test catalog overriding of declarative catalog with itself."""
with self.assertRaises(errors.Error):
CatalogA.override(CatalogA)
def test_override_declarative_catalog_with_subclass(self):
"""Test catalog overriding of declarative catalog with subclass."""
with self.assertRaises(errors.Error):
CatalogB.override(CatalogA)
def test_override_dynamic_catalog_with_itself(self):
"""Test catalog overriding of dynamic catalog with itself."""
catalog = catalogs.DynamicCatalog(p11=providers.Object(1),
p12=providers.Object(2))
with self.assertRaises(errors.Error):
catalog.override(catalog)
def test_overriding_with_dynamic_catalog(self):
"""Test catalog overriding with another dynamic catalog."""
CatalogA.override(catalogs.DynamicCatalog(p11=providers.Object(1),
p12=providers.Object(2)))
self.assertEqual(CatalogA.p11(), 1)
self.assertEqual(CatalogA.p12(), 2)
self.assertEqual(len(CatalogA.overridden_by), 1)
def test_is_overridden(self):
"""Test catalog is_overridden property."""
self.assertFalse(CatalogA.is_overridden)
@catalogs.override(CatalogA)
class OverridingCatalog(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
self.assertTrue(CatalogA.is_overridden)
def test_last_overriding(self):
"""Test catalog last_overriding property."""
@catalogs.override(CatalogA)
class OverridingCatalog1(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
@catalogs.override(CatalogA)
class OverridingCatalog2(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
self.assertIs(CatalogA.last_overriding, OverridingCatalog2)
def test_last_overriding_on_not_overridden(self):
"""Test catalog last_overriding property on not overridden catalog."""
self.assertIsNone(CatalogA.last_overriding)
def test_reset_last_overriding(self):
"""Test resetting last overriding catalog."""
@catalogs.override(CatalogA)
class OverridingCatalog1(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
p11 = providers.Object(1)
p12 = providers.Object(2)
@catalogs.override(CatalogA)
class OverridingCatalog2(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
p11 = providers.Object(3)
p12 = providers.Object(4)
CatalogA.reset_last_overriding()
self.assertEqual(CatalogA.p11(), 1)
self.assertEqual(CatalogA.p12(), 2)
def test_reset_last_overriding_when_not_overridden(self):
"""Test resetting last overriding catalog when it is not overridden."""
with self.assertRaises(errors.Error):
CatalogA.reset_last_overriding()
def test_reset_override(self):
"""Test resetting all catalog overrides."""
@catalogs.override(CatalogA)
class OverridingCatalog1(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
p11 = providers.Object(1)
p12 = providers.Object(2)
@catalogs.override(CatalogA)
class OverridingCatalog2(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
p11 = providers.Object(3)
p12 = providers.Object(4)
CatalogA.reset_override()
self.assertFalse(CatalogA.p11.is_overridden)
self.assertFalse(CatalogA.p12.is_overridden)

View File

@ -276,5 +276,162 @@ class DeclarativeContainerTests(unittest.TestCase):
self.assertEqual(_Container1.p13(), 11)
self.assertEqual(_Container2.p13(), 22)
class DeclarativeContainerInstanceTests(unittest.TestCase):
"""Declarative container instance tests."""
def test_providers_attribute(self):
"""Test providers attribute."""
container_a1 = ContainerA()
container_a2 = ContainerA()
self.assertIsNot(container_a1.p11, container_a2.p11)
self.assertIsNot(container_a1.p12, container_a2.p12)
self.assertNotEqual(container_a1.providers, container_a2.providers)
def test_set_get_del_providers(self):
"""Test set/get/del provider attributes."""
p13 = providers.Provider()
container_a1 = ContainerA()
container_a2 = ContainerA()
container_a1.p13 = p13
container_a2.p13 = p13
self.assertEqual(ContainerA.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
self.assertEqual(ContainerA.cls_providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
self.assertEqual(container_a1.providers, dict(p11=container_a1.p11,
p12=container_a1.p12,
p13=p13))
self.assertEqual(container_a2.providers, dict(p11=container_a2.p11,
p12=container_a2.p12,
p13=p13))
del container_a1.p13
self.assertEqual(container_a1.providers, dict(p11=container_a1.p11,
p12=container_a1.p12))
del container_a2.p13
self.assertEqual(container_a2.providers, dict(p11=container_a2.p11,
p12=container_a2.p12))
del container_a1.p11
del container_a1.p12
self.assertEqual(container_a1.providers, dict())
self.assertEqual(ContainerA.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
del container_a2.p11
del container_a2.p12
self.assertEqual(container_a2.providers, dict())
self.assertEqual(ContainerA.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
def test_set_invalid_provider_type(self):
"""Test setting of invalid provider."""
container_a = ContainerA()
container_a.provider_type = providers.Object
with self.assertRaises(errors.Error):
container_a.px = providers.Provider()
self.assertIs(ContainerA.provider_type,
containers.DeclarativeContainer.provider_type)
def test_override(self):
"""Test override."""
class _Container(containers.DeclarativeContainer):
p11 = providers.Provider()
class _OverridingContainer1(containers.DeclarativeContainer):
p11 = providers.Provider()
class _OverridingContainer2(containers.DeclarativeContainer):
p11 = providers.Provider()
p12 = providers.Provider()
container = _Container()
overriding_container1 = _OverridingContainer1()
overriding_container2 = _OverridingContainer2()
container.override(overriding_container1)
container.override(overriding_container2)
self.assertEqual(container.overridden_by,
(overriding_container1,
overriding_container2))
self.assertEqual(container.p11.overridden_by,
(overriding_container1.p11,
overriding_container2.p11))
self.assertEqual(_Container.overridden_by, tuple())
self.assertEqual(_Container.p11.overridden_by, tuple())
def test_override_with_itself(self):
"""Test override container with itself."""
container = ContainerA()
with self.assertRaises(errors.Error):
container.override(container)
def test_reset_last_overridding(self):
"""Test reset of last overriding."""
class _Container(containers.DeclarativeContainer):
p11 = providers.Provider()
class _OverridingContainer1(containers.DeclarativeContainer):
p11 = providers.Provider()
class _OverridingContainer2(containers.DeclarativeContainer):
p11 = providers.Provider()
p12 = providers.Provider()
container = _Container()
overriding_container1 = _OverridingContainer1()
overriding_container2 = _OverridingContainer2()
container.override(overriding_container1)
container.override(overriding_container2)
container.reset_last_overriding()
self.assertEqual(container.overridden_by,
(overriding_container1,))
self.assertEqual(container.p11.overridden_by,
(overriding_container1.p11,))
def test_reset_last_overridding_when_not_overridden(self):
"""Test reset of last overriding."""
container = ContainerA()
with self.assertRaises(errors.Error):
container.reset_last_overriding()
def test_reset_override(self):
"""Test reset all overridings."""
class _Container(containers.DeclarativeContainer):
p11 = providers.Provider()
class _OverridingContainer1(containers.DeclarativeContainer):
p11 = providers.Provider()
class _OverridingContainer2(containers.DeclarativeContainer):
p11 = providers.Provider()
p12 = providers.Provider()
container = _Container()
overriding_container1 = _OverridingContainer1()
overriding_container2 = _OverridingContainer2()
container.override(overriding_container1)
container.override(overriding_container2)
container.reset_override()
self.assertEqual(container.overridden_by, tuple())
self.assertEqual(container.p11.overridden_by, tuple())
if __name__ == '__main__':
unittest.main()

View File

@ -4,7 +4,6 @@ import unittest2 as unittest
from dependency_injector import utils
from dependency_injector import providers
from dependency_injector import catalogs
from dependency_injector import errors
@ -69,56 +68,3 @@ class EnsureIsProviderTests(unittest.TestCase):
def test_with_object(self):
"""Test with object."""
self.assertRaises(errors.Error, utils.ensure_is_provider, object())
class IsCatalogTests(unittest.TestCase):
"""`is_catalog()` test cases."""
def test_with_declarative_catalog(self):
"""Test with class."""
self.assertTrue(utils.is_catalog(catalogs.DeclarativeCatalog))
def test_with_dynamic_catalog(self):
"""Test with class."""
self.assertTrue(utils.is_catalog(catalogs.DynamicCatalog()))
def test_with_child_class(self):
"""Test with parent class."""
class Catalog(catalogs.DeclarativeCatalog):
"""Example catalog child class."""
self.assertTrue(utils.is_catalog(Catalog))
def test_with_string(self):
"""Test with string."""
self.assertFalse(utils.is_catalog('some_string'))
def test_with_object(self):
"""Test with object."""
self.assertFalse(utils.is_catalog(object()))
class IsDynamicCatalogTests(unittest.TestCase):
"""`is_dynamic_catalog()` test cases."""
def test_with_declarative_catalog(self):
"""Test with declarative catalog."""
self.assertFalse(utils.is_dynamic_catalog(catalogs.DeclarativeCatalog))
def test_with_dynamic_catalog(self):
"""Test with dynamic catalog."""
self.assertTrue(utils.is_dynamic_catalog(catalogs.DynamicCatalog()))
class IsDeclarativeCatalogTests(unittest.TestCase):
"""`is_declarative_catalog()` test cases."""
def test_with_declarative_catalog(self):
"""Test with declarative catalog."""
self.assertTrue(utils.is_declarative_catalog(
catalogs.DeclarativeCatalog))
def test_with_dynamic_catalog(self):
"""Test with dynamic catalog."""
self.assertFalse(utils.is_declarative_catalog(
catalogs.DynamicCatalog()))