Merge remote-tracking branch 'origin/2.0-ioc-containers' into 2.0

This commit is contained in:
Roman Mogilatov 2016-06-01 19:11:08 +03:00
commit 5ecb00daba
45 changed files with 997 additions and 2217 deletions

View File

@ -52,7 +52,7 @@ Installation
Example
-------
Brief example below demonstrates usage of *Dependency Injector* catalogs and
Brief example below demonstrates usage of *Dependency Injector* containers and
providers for definition of several IoC containers for some microservice
system that consists from several business and platform services:
@ -64,12 +64,12 @@ system that consists from several business and platform services:
import boto.s3.connection
import example.services
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
class Platform(catalogs.DeclarativeCatalog):
"""Catalog of platform service providers."""
class Platform(containers.DeclarativeContainer):
"""IoC container of platform service providers."""
database = providers.Singleton(sqlite3.connect, ':memory:')
@ -78,8 +78,8 @@ system that consists from several business and platform services:
aws_secret_access_key='SECRET')
class Services(catalogs.DeclarativeCatalog):
"""Catalog of business service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users,
db=Platform.database)
@ -101,7 +101,7 @@ defined above:
from dependency_injector.injections import inject
from catalogs import Services
from containers import Services
@inject(users_service=Services.users)
@ -127,8 +127,8 @@ IoC containers from previous example could look like these:
.. code-block:: python
class Platform(catalogs.DeclarativeCatalog):
"""Catalog of platform service providers."""
class Platform(containers.DeclarativeContainer):
"""IoC container of platform service providers."""
database = providers.Singleton(sqlite3.connect) \
.add_args(':memory:')
@ -138,8 +138,8 @@ IoC containers from previous example could look like these:
aws_secret_access_key='SECRET')
class Services(catalogs.DeclarativeCatalog):
"""Catalog of business service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users) \
.add_kwargs(db=Platform.database)
@ -156,8 +156,8 @@ or like this these:
.. code-block:: python
class Platform(catalogs.DeclarativeCatalog):
"""Catalog of platform service providers."""
class Platform(containers.DeclarativeContainer):
"""IoC container of platform service providers."""
database = providers.Singleton(sqlite3.connect)
database.add_args(':memory:')
@ -167,8 +167,8 @@ or like this these:
aws_secret_access_key='SECRET')
class Services(catalogs.DeclarativeCatalog):
"""Catalog of business service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users)
users.add_kwargs(db=Platform.database)

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

@ -0,0 +1,268 @@
"""IoC containers module."""
import six
from dependency_injector import (
providers,
utils,
errors,
)
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."""
def __new__(mcs, class_name, bases, attributes):
"""Declarative container class factory."""
cls_providers = tuple((name, provider)
for name, provider in six.iteritems(attributes)
if utils.is_provider(provider))
inherited_providers = tuple((name, provider)
for base in bases if utils.is_container(
base) and base is not DynamicContainer
for name, provider in six.iteritems(
base.cls_providers))
attributes['cls_providers'] = dict(cls_providers)
attributes['inherited_providers'] = dict(inherited_providers)
attributes['providers'] = dict(cls_providers + inherited_providers)
cls = type.__new__(mcs, class_name, bases, attributes)
for provider in six.itervalues(cls.providers):
_check_provider_type(cls, provider)
return cls
def __setattr__(cls, name, value):
"""Set class attribute.
If value of attribute is provider, it will be added into providers
dictionary.
"""
if utils.is_provider(value):
_check_provider_type(cls, value)
cls.providers[name] = value
cls.cls_providers[name] = value
super(DeclarativeContainerMetaClass, cls).__setattr__(name, value)
def __delattr__(cls, name):
"""Delete class attribute.
If value of attribute is provider, it will be deleted from providers
dictionary.
"""
if name in cls.providers and name in cls.cls_providers:
del cls.providers[name]
del cls.cls_providers[name]
super(DeclarativeContainerMetaClass, cls).__delattr__(name)
@six.add_metaclass(DeclarativeContainerMetaClass)
class DeclarativeContainer(object):
"""Declarative inversion of control container."""
__IS_CONTAINER__ = True
provider_type = providers.Provider
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.
: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 issubclass(cls, overriding):
raise errors.Error('Container {0} could not be overridden '
'with itself or its subclasses'.format(cls))
cls.overridden_by += (overriding,)
for name, provider in six.iteritems(overriding.cls_providers):
try:
getattr(cls, name).override(provider)
except AttributeError:
pass
@classmethod
def reset_last_overriding(cls):
"""Reset last overriding provider for each container providers.
:rtype: None
"""
if not cls.overridden_by:
raise errors.Error('Container {0} is not overridden'.format(cls))
cls.overridden_by = cls.overridden_by[:-1]
for provider in six.itervalues(cls.providers):
provider.reset_last_overriding()
@classmethod
def reset_override(cls):
"""Reset all overridings for each container providers.
:rtype: None
"""
cls.overridden_by = tuple()
for provider in six.itervalues(cls.providers):
provider.reset_override()
def override(container):
""":py:class:`DeclarativeContainer` overriding decorator.
:param container: Container that should be overridden by decorated
container.
:type container: :py:class:`DeclarativeContainer`
:return: Declarative container's overriding decorator.
:rtype: callable(:py:class:`DeclarativeContainer`)
"""
def _decorator(overriding_container):
"""Overriding decorator."""
container.override(overriding_container)
return overriding_container
return _decorator
def copy(container):
""":py:class:`DeclarativeContainer` copying decorator.
This decorator copy all providers from provided container to decorated one.
If one of the decorated container providers matches to source container
providers by name, it would be replaced by reference.
:param container: Container that should be copied by decorated container.
:type container :py:class:`DeclarativeContainer`
:return: Declarative container's copying decorator.
:rtype: callable(:py:class:`DeclarativeContainer`)
"""
def _decorator(copied_container):
memo = dict()
for name, provider in six.iteritems(copied_container.cls_providers):
try:
source_provider = getattr(container, name)
except AttributeError:
pass
else:
memo[id(source_provider)] = provider
providers_copy = utils.deepcopy(container.providers, memo)
for name, provider in six.iteritems(providers_copy):
setattr(copied_container, name, provider)
return copied_container
return _decorator
def _check_provider_type(cls, provider):
if not isinstance(provider, cls.provider_type):
raise errors.Error('{0} can contain only {1} '
'instances'.format(cls, cls.provider_type))

View File

@ -64,7 +64,7 @@ class Provider(object):
def __init__(self):
"""Initializer."""
self.overridden_by = None
self.overridden_by = tuple()
super(Provider, self).__init__()
# Enable __call__() / _provide() optimization
if self.__class__.__OPTIMIZED_CALLS__:
@ -124,9 +124,6 @@ class Provider(object):
if not is_provider(provider):
provider = Object(provider)
if not self.is_overridden:
self.overridden_by = (ensure_is_provider(provider),)
else:
self.overridden_by += (ensure_is_provider(provider),)
# Disable __call__() / _provide() optimization
@ -145,6 +142,7 @@ class Provider(object):
"""
if not self.overridden_by:
raise Error('Provider {0} is not overridden'.format(str(self)))
self.overridden_by = self.overridden_by[:-1]
if not self.is_overridden:
@ -157,7 +155,7 @@ class Provider(object):
:rtype: None
"""
self.overridden_by = None
self.overridden_by = tuple()
# Enable __call__() / _provide() optimization
if self.__class__.__OPTIMIZED_CALLS__:

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)
@ -59,38 +59,16 @@ def ensure_is_provider(instance):
return instance
def is_catalog(instance):
"""Check if instance is catalog instance.
def is_container(instance):
"""Check if instance is container 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))
return (hasattr(instance, '__IS_CONTAINER__') and
getattr(instance, '__IS_CONTAINER__', False) is True)
def represent_provider(provider, provides):
@ -130,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

@ -1,30 +0,0 @@
"""Declarative catalogs inheritance example."""
from dependency_injector import catalogs
from dependency_injector import providers
class CatalogA(catalogs.DeclarativeCatalog):
"""Example catalog A."""
provider1 = providers.Factory(object)
class CatalogB(CatalogA):
"""Example catalog B."""
provider2 = providers.Singleton(object)
# Making some asserts for `providers` attribute:
assert CatalogA.providers == dict(provider1=CatalogA.provider1)
assert CatalogB.providers == dict(provider1=CatalogA.provider1,
provider2=CatalogB.provider2)
# Making some asserts for `cls_providers` attribute:
assert CatalogA.cls_providers == dict(provider1=CatalogA.provider1)
assert CatalogB.cls_providers == dict(provider2=CatalogB.provider2)
# Making some asserts for `inherited_providers` attribute:
assert CatalogA.inherited_providers == dict()
assert CatalogB.inherited_providers == dict(provider1=CatalogA.provider1)

View File

@ -1,73 +0,0 @@
"""Specialized declarative catalog example."""
import services
from dependency_injector import providers
from dependency_injector import errors
class UsersService(services.Base):
"""Users service."""
def __init__(self, config):
"""Initializer."""
self.config = config
super(UsersService, self).__init__()
class AuthService(services.Base):
"""Auth service."""
def __init__(self, config, users_service):
"""Initializer."""
self.config = config
self.users_service = users_service
super(AuthService, self).__init__()
class Services(services.Catalog):
"""Services catalog."""
users = services.Provider(UsersService,
config={'option1': '111',
'option2': '222'})
auth = services.Provider(AuthService,
config={'option3': '333',
'option4': '444'},
users_service=users)
# Creating users & auth services:
users_service = Services.users()
auth_service = 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, UsersService)
# Trying to declare services catalog with other provider type:
try:
class Services1(services.Catalog):
"""Services catalog."""
users = providers.Factory(UsersService)
except errors.Error as exception:
print exception
# <__main__.Services1()> can contain only <class 'services.Provider'>
# instances
# Trying to declare services catalog with correct provider by invalid provided
# type:
try:
class Services2(services.Catalog):
"""Services catalog."""
users = services.Provider(object)
except errors.Error as exception:
print exception
# <class 'services.Provider'> can provide only <class 'services.Base'>
# instances

View File

@ -1,26 +0,0 @@
"""Base classes for services."""
from dependency_injector import catalogs
from dependency_injector import providers
class Base(object):
"""Base service class."""
class Provider(providers.Factory):
"""Service provider.
Can provide :py:class:`Base` only.
"""
provided_type = Base
class Catalog(catalogs.DeclarativeCatalog):
"""Base catalog of services.
Can include :py:class:`Provider`'s only.
"""
provider_type = Provider

View File

@ -1,18 +0,0 @@
"""Dynamic catalog simple example."""
from dependency_injector import catalogs
from dependency_injector import providers
# Defining dynamic catalog:
catalog = catalogs.DynamicCatalog(factory1=providers.Factory(object),
factory2=providers.Factory(object))
# Creating some objects:
object1 = catalog.factory1()
object2 = catalog.factory2()
# Making some asserts:
assert object1 is not object2
assert isinstance(object1, object)
assert isinstance(object2, object)

View File

@ -1,63 +0,0 @@
"""Specialized dynamic catalog example."""
import services
from dependency_injector import providers
from dependency_injector import errors
class UsersService(services.Base):
"""Users service."""
def __init__(self, config):
"""Initializer."""
self.config = config
super(UsersService, self).__init__()
class AuthService(services.Base):
"""Auth service."""
def __init__(self, config, users_service):
"""Initializer."""
self.config = config
self.users_service = users_service
super(AuthService, self).__init__()
services_catalog = services.Catalog()
services_catalog.users = services.Provider(UsersService,
config={'option1': '111',
'option2': '222'})
services_catalog.auth = services.Provider(AuthService,
config={'option3': '333',
'option4': '444'},
users_service=services_catalog.users)
# Creating users & auth services:
users_service = services_catalog.users()
auth_service = services_catalog.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, UsersService)
# Trying to declare services catalog with other provider type:
try:
services_catalog.users = providers.Factory(UsersService)
except errors.Error as exception:
print exception
# <services.Catalog(users, auth)> can contain only
# <class 'services.Provider'> instances
# Trying to declare services catalog with correct provider by invalid provided
# type:
try:
services_catalog.users = services.Provider(object)
except errors.Error as exception:
print exception
# <class 'services.Provider'> can provide only <class 'services.Base'>
# instances

View File

@ -1,26 +0,0 @@
"""Base classes for services."""
from dependency_injector import catalogs
from dependency_injector import providers
class Base(object):
"""Base service class."""
class Provider(providers.Factory):
"""Service provider.
Can provide :py:class:`Base` only.
"""
provided_type = Base
class Catalog(catalogs.DynamicCatalog):
"""Base catalog of services.
Can include :py:class:`Provider`'s only.
"""
provider_type = Provider

View File

@ -1,66 +0,0 @@
"""Dynamic catalog creation and runtime filling of it example."""
from dependency_injector import catalogs
# 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('.')
if len(path_components) == 1:
path_components.insert(0, '__main__')
module = __import__('.'.join(path_components[0:-1]),
locals(),
globals(),
fromlist=path_components[-1:])
return getattr(module, path_components[-1])
# "Parsing" some configuration:
config = {
'services': {
'users': {
'class': 'UsersService',
'provider_class': 'dependency_injector.providers.Factory',
},
'auth': {
'class': 'AuthService',
'provider_class': 'dependency_injector.providers.Factory',
}
}
}
# Defining dynamic service providers catalog:
services = catalogs.DynamicCatalog()
# Filling dynamic service providers catalog according to the 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'])
# Creating service provider:
service_provider = service_provider_cls(service_cls)
# Binding service provider to the dynamic service providers catalog:
services.bind_provider(service_name, service_provider)
# 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,41 +0,0 @@
"""Declarative catalog overriding by dynamic catalog example."""
import collections
from dependency_injector import catalogs
from dependency_injector import providers
# Creating some example classes:
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
Object2 = collections.namedtuple('Object2', ['object1'])
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
class Catalog(catalogs.DeclarativeCatalog):
"""Catalog of some providers."""
object1_factory = providers.Factory(Object1,
arg1=1,
arg2=2)
object2_factory = providers.Factory(Object2,
object1=object1_factory)
# Overriding `Catalog` with some `DynamicCatalog` instance:
overriding_catalog = catalogs.DynamicCatalog(
object2_factory=providers.Factory(ExtendedObject2))
Catalog.override(overriding_catalog)
# Creating some objects using overridden catalog:
object2_1 = Catalog.object2_factory()
object2_2 = Catalog.object2_factory()
# Making some asserts:
assert Catalog.is_overridden
assert object2_1 is not object2_2
assert isinstance(object2_1, ExtendedObject2)
assert isinstance(object2_2, ExtendedObject2)

View File

@ -1,43 +0,0 @@
"""Declarative catalog overriding using `@override()` decorator example."""
import collections
from dependency_injector import catalogs
from dependency_injector import providers
# Creating some example classes:
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
Object2 = collections.namedtuple('Object2', ['object1'])
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
class Catalog(catalogs.DeclarativeCatalog):
"""Catalog of some providers."""
object1_factory = providers.Factory(Object1,
arg1=1,
arg2=2)
object2_factory = providers.Factory(Object2,
object1=object1_factory)
# Overriding `Catalog` with `AnotherCatalog`:
@catalogs.override(Catalog)
class AnotherCatalog(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
object2_factory = providers.Factory(ExtendedObject2)
# Creating some objects using overridden catalog:
object2_1 = Catalog.object2_factory()
object2_2 = Catalog.object2_factory()
# Making some asserts:
assert Catalog.is_overridden
assert object2_1 is not object2_2
assert isinstance(object2_1, ExtendedObject2)
assert isinstance(object2_2, ExtendedObject2)

View File

@ -1,20 +1,20 @@
"""Declarative catalog simple example."""
"""Declarative IoC container simple example."""
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
# Defining declarative catalog:
class Catalog(catalogs.DeclarativeCatalog):
"""Providers catalog."""
# Defining declarative IoC container:
class Container(containers.DeclarativeContainer):
"""Example IoC container."""
factory1 = providers.Factory(object)
factory2 = providers.Factory(object)
# Creating some objects:
object1 = Catalog.factory1()
object2 = Catalog.factory2()
object1 = Container.factory1()
object2 = Container.factory2()
# Making some asserts:
assert object1 is not object2

View File

@ -0,0 +1,30 @@
"""Declarative IoC containers inheritance example."""
from dependency_injector import containers
from dependency_injector import providers
class ContainerA(containers.DeclarativeContainer):
"""Example IoC container A."""
provider1 = providers.Factory(object)
class ContainerB(ContainerA):
"""Example IoC container B."""
provider2 = providers.Singleton(object)
# Making some asserts for `providers` attribute:
assert ContainerA.providers == dict(provider1=ContainerA.provider1)
assert ContainerB.providers == dict(provider1=ContainerA.provider1,
provider2=ContainerB.provider2)
# Making some asserts for `cls_providers` attribute:
assert ContainerA.cls_providers == dict(provider1=ContainerA.provider1)
assert ContainerB.cls_providers == dict(provider2=ContainerB.provider2)
# Making some asserts for `inherited_providers` attribute:
assert ContainerA.inherited_providers == dict()
assert ContainerB.inherited_providers == dict(provider1=ContainerB.provider1)

View File

@ -1,8 +1,8 @@
"""Declarative catalog's provider injections example."""
"""Declarative IoC container's provider injections example."""
import sqlite3
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
@ -23,8 +23,8 @@ class AuthService(object):
self.users_service = users_service
class Services(catalogs.DeclarativeCatalog):
"""Catalog of service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of service providers."""
database = providers.Singleton(sqlite3.connect, ':memory:')
@ -36,7 +36,7 @@ class Services(catalogs.DeclarativeCatalog):
users_service=users)
# Retrieving service providers from catalog:
# Retrieving service providers from container:
users_service = Services.users()
auth_service = Services.auth()

View File

@ -0,0 +1,17 @@
"""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

@ -0,0 +1,26 @@
"""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

@ -0,0 +1,42 @@
"""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

@ -0,0 +1,22 @@
"""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

@ -1,8 +1,8 @@
"""Declarative catalog overriding example."""
"""Declarative IoC container overriding example."""
import collections
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
@ -12,8 +12,8 @@ Object2 = collections.namedtuple('Object2', ['object1'])
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
class Catalog(catalogs.DeclarativeCatalog):
"""Catalog of some providers."""
class Container(containers.DeclarativeContainer):
"""Example IoC container."""
object1_factory = providers.Factory(Object1,
arg1=1,
@ -23,21 +23,21 @@ class Catalog(catalogs.DeclarativeCatalog):
object1=object1_factory)
class AnotherCatalog(catalogs.DeclarativeCatalog):
"""Overriding catalog."""
class OverridingContainer(containers.DeclarativeContainer):
"""Overriding IoC container."""
object2_factory = providers.Factory(ExtendedObject2)
# Overriding `Catalog` with `AnotherCatalog`:
Catalog.override(AnotherCatalog)
# Overriding `Container` with `OverridingContainer`:
Container.override(OverridingContainer)
# Creating some objects using overridden catalog:
object2_1 = Catalog.object2_factory()
object2_2 = Catalog.object2_factory()
# Creating some objects using overridden container:
object2_1 = Container.object2_factory()
object2_2 = Container.object2_factory()
# Making some asserts:
assert Catalog.is_overridden
assert Container.overridden_by == (OverridingContainer,)
assert object2_1 is not object2_2

View File

@ -0,0 +1,41 @@
"""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', [])
class Container(containers.DeclarativeContainer):
"""Example IoC container."""
object1_factory = providers.Factory(Object1, arg1=1, arg2=2)
object2_factory = providers.Factory(Object2, object1=object1_factory)
# Overriding `Container` with `OverridingContainer`:
@containers.override(Container)
class OverridingContainer(containers.DeclarativeContainer):
"""Overriding IoC container."""
object2_factory = providers.Factory(ExtendedObject2)
# Creating some objects using overridden container:
object2_1 = Container.object2_factory()
object2_2 = Container.object2_factory()
# 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)

View File

@ -10,7 +10,7 @@ class Car(object):
def __init__(self):
"""Initializer."""
self.engine = Engine()
self.engine = Engine() # Engine is a "hardcoded" dependency
if __name__ == '__main__':

View File

@ -10,7 +10,7 @@ class Car(object):
def __init__(self, engine):
"""Initializer."""
self.engine = engine
self.engine = engine # Engine is an "injected" dependency
if __name__ == '__main__':

View File

@ -1,14 +1,14 @@
"""Example of inversion of control container for Car & Engine example."""
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
from car_engine_ioc import Car
from car_engine_ioc import Engine
class Components(catalogs.DeclarativeCatalog):
"""Catalog of component providers."""
class Components(containers.DeclarativeContainer):
"""IoC container of component providers."""
engine = providers.Factory(Engine)

View File

@ -9,7 +9,7 @@ This mini application uses ``movies`` library, that is configured to work with
csv file movies database.
"""
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
from dependency_injector import injections
@ -19,14 +19,14 @@ from movies import finders
from settings import MOVIES_CSV_PATH
@catalogs.override(MoviesModule)
class MyMoviesModule(catalogs.DeclarativeCatalog):
"""Customized catalog of movies module component providers."""
@containers.override(MoviesModule)
class MyMoviesModule(containers.DeclarativeContainer):
"""IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(finders.CsvMovieFinder,
*MoviesModule.movie_finder.injections,
csv_file=MOVIES_CSV_PATH,
delimeter=',')
delimeter=',',
**MoviesModule.movie_finder.kwargs)
@injections.inject(MoviesModule.movie_lister)

View File

@ -11,7 +11,7 @@ sqlite movies database.
import sqlite3
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
from dependency_injector import injections
@ -21,19 +21,19 @@ from movies import finders
from settings import MOVIES_DB_PATH
class ApplicationModule(catalogs.DeclarativeCatalog):
"""Catalog of application component providers."""
class ApplicationModule(containers.DeclarativeContainer):
"""IoC container of application component providers."""
database = providers.Singleton(sqlite3.connect, MOVIES_DB_PATH)
@catalogs.override(MoviesModule)
class MyMoviesModule(catalogs.DeclarativeCatalog):
"""Customized catalog of movies module component providers."""
@containers.override(MoviesModule)
class MyMoviesModule(containers.DeclarativeContainer):
"""IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(finders.SqliteMovieFinder,
*MoviesModule.movie_finder.injections,
database=ApplicationModule.database)
database=ApplicationModule.database,
**MoviesModule.movie_finder.kwargs)
@injections.inject(MoviesModule.movie_lister)

View File

@ -11,7 +11,7 @@ sqlite movies database and csv file movies database.
import sqlite3
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
from dependency_injector import injections
@ -22,29 +22,29 @@ from settings import MOVIES_CSV_PATH
from settings import MOVIES_DB_PATH
class ApplicationModule(catalogs.DeclarativeCatalog):
"""Catalog of application component providers."""
class ApplicationModule(containers.DeclarativeContainer):
"""IoC container of application component providers."""
database = providers.Singleton(sqlite3.connect, MOVIES_DB_PATH)
@catalogs.copy(MoviesModule)
@containers.copy(MoviesModule)
class DbMoviesModule(MoviesModule):
"""Customized catalog of movies module component providers."""
"""IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(finders.SqliteMovieFinder,
*MoviesModule.movie_finder.injections,
database=ApplicationModule.database)
database=ApplicationModule.database,
**MoviesModule.movie_finder.kwargs)
@catalogs.copy(MoviesModule)
@containers.copy(MoviesModule)
class CsvMoviesModule(MoviesModule):
"""Customized catalog of movies module component providers."""
"""IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(finders.CsvMovieFinder,
*MoviesModule.movie_finder.injections,
csv_file=MOVIES_CSV_PATH,
delimeter=',')
delimeter=',',
**MoviesModule.movie_finder.kwargs)
@injections.inject(db_movie_lister=DbMoviesModule.movie_lister)

View File

@ -1,9 +1,9 @@
"""Movies package.
Top-level package of movies library. This package contains catalog of movies
module component providers - ``MoviesModule``. It is recommended to use movies
library functionality by fetching required instances from ``MoviesModule``
providers.
Top-level package of movies library. This package contains IoC container of
movies module component providers - ``MoviesModule``. It is recommended to use
movies library functionality by fetching required instances from
``MoviesModule`` providers.
``MoviesModule.movie_finder`` is a factory that provides abstract component
``finders.MovieFinder``. This provider should be overridden by provider of
@ -12,7 +12,7 @@ concrete finder implementation in terms of library configuration.
Each of ``MoviesModule`` providers could be overridden.
"""
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
from . import finders
@ -20,8 +20,8 @@ from . import listers
from . import models
class MoviesModule(catalogs.DeclarativeCatalog):
"""Catalog of movies module component providers."""
class MoviesModule(containers.DeclarativeContainer):
"""IoC container of movies module component providers."""
movie_model = providers.DelegatedFactory(models.Movie)

View File

@ -4,12 +4,12 @@ import sqlite3
import boto.s3.connection
import example.services
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
class Platform(catalogs.DeclarativeCatalog):
"""Catalog of platform service providers."""
class Platform(containers.DeclarativeContainer):
"""IoC container of platform service providers."""
database = providers.Singleton(sqlite3.connect, ':memory:')
@ -18,8 +18,8 @@ class Platform(catalogs.DeclarativeCatalog):
aws_secret_access_key='SECRET')
class Services(catalogs.DeclarativeCatalog):
"""Catalog of business service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users,
db=Platform.database)

View File

@ -7,12 +7,12 @@ import sqlite3
import boto.s3.connection
import example.services
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
class Platform(catalogs.DeclarativeCatalog):
"""Catalog of platform service providers."""
class Platform(containers.DeclarativeContainer):
"""IoC container of platform service providers."""
database = providers.Singleton(sqlite3.connect) \
.add_args(':memory:')
@ -22,8 +22,8 @@ class Platform(catalogs.DeclarativeCatalog):
aws_secret_access_key='SECRET')
class Services(catalogs.DeclarativeCatalog):
"""Catalog of business service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users) \
.add_kwargs(db=Platform.database)

View File

@ -7,12 +7,12 @@ import sqlite3
import boto.s3.connection
import example.services
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
class Platform(catalogs.DeclarativeCatalog):
"""Catalog of platform service providers."""
class Platform(containers.DeclarativeContainer):
"""IoC container of platform service providers."""
database = providers.Singleton(sqlite3.connect)
database.add_args(':memory:')
@ -22,8 +22,8 @@ class Platform(catalogs.DeclarativeCatalog):
aws_secret_access_key='SECRET')
class Services(catalogs.DeclarativeCatalog):
"""Catalog of business service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users)
users.add_kwargs(db=Platform.database)

View File

@ -2,7 +2,7 @@
from dependency_injector.injections import inject
from catalogs import Services
from containers import Services
@inject(users_service=Services.users)

View File

@ -1,8 +1,8 @@
"""Pythonic way for Dependency Injection - Providing Callbacks Catalog."""
"""Pythonic way for Dependency Injection - callback-based IoC container."""
import sqlite3
from dependency_injector import catalogs
from dependency_injector import containers
from dependency_injector import providers
from dependency_injector import injections
@ -24,14 +24,14 @@ class AuthService(object):
self.users_service = users_service
class Services(catalogs.DeclarativeCatalog):
"""Catalog of service providers."""
class Services(containers.DeclarativeContainer):
"""IoC container of service providers."""
@providers.Singleton
def database():
"""Provide database connection.
:rtype: providers.Provider -> sqlite3.Connection
:rtype: sqlite3.Connection
"""
return sqlite3.connect(':memory:')
@ -40,7 +40,7 @@ class Services(catalogs.DeclarativeCatalog):
def users(**kwargs):
"""Provide users service.
:rtype: providers.Provider -> UsersService
:rtype: UsersService
"""
return UsersService(**kwargs)
@ -50,12 +50,12 @@ class Services(catalogs.DeclarativeCatalog):
def auth(**kwargs):
"""Provide users service.
:rtype: providers.Provider -> AuthService
:rtype: AuthService
"""
return AuthService(**kwargs)
# Retrieving catalog providers:
# Retrieving services:
users_service = Services.users()
auth_service = Services.auth()

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)

437
tests/test_containers.py Normal file
View File

@ -0,0 +1,437 @@
"""Dependency injector container unit tests."""
import unittest2 as unittest
from dependency_injector import (
containers,
providers,
errors,
)
class ContainerA(containers.DeclarativeContainer):
"""Declarative IoC container A."""
p11 = providers.Provider()
p12 = providers.Provider()
class ContainerB(ContainerA):
"""Declarative IoC container B.
Extends container A.
"""
p21 = providers.Provider()
p22 = providers.Provider()
class DeclarativeContainerTests(unittest.TestCase):
"""Declarative container tests."""
def test_providers_attribute(self):
"""Test providers attribute."""
self.assertEqual(ContainerA.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
self.assertEqual(ContainerB.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12,
p21=ContainerB.p21,
p22=ContainerB.p22))
def test_cls_providers_attribute(self):
"""Test cls_providers attribute."""
self.assertEqual(ContainerA.cls_providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
self.assertEqual(ContainerB.cls_providers, dict(p21=ContainerB.p21,
p22=ContainerB.p22))
def test_inherited_providers_attribute(self):
"""Test inherited_providers attribute."""
self.assertEqual(ContainerA.inherited_providers, dict())
self.assertEqual(ContainerB.inherited_providers,
dict(p11=ContainerA.p11,
p12=ContainerA.p12))
def test_set_get_del_providers(self):
"""Test set/get/del provider attributes."""
a_p13 = providers.Provider()
b_p23 = providers.Provider()
ContainerA.p13 = a_p13
ContainerB.p23 = b_p23
self.assertEqual(ContainerA.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12,
p13=a_p13))
self.assertEqual(ContainerB.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12,
p21=ContainerB.p21,
p22=ContainerB.p22,
p23=b_p23))
self.assertEqual(ContainerA.cls_providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12,
p13=a_p13))
self.assertEqual(ContainerB.cls_providers, dict(p21=ContainerB.p21,
p22=ContainerB.p22,
p23=b_p23))
del ContainerA.p13
del ContainerB.p23
self.assertEqual(ContainerA.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
self.assertEqual(ContainerB.providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12,
p21=ContainerB.p21,
p22=ContainerB.p22))
self.assertEqual(ContainerA.cls_providers, dict(p11=ContainerA.p11,
p12=ContainerA.p12))
self.assertEqual(ContainerB.cls_providers, dict(p21=ContainerB.p21,
p22=ContainerB.p22))
def test_declare_with_valid_provider_type(self):
"""Test declaration of container with valid provider type."""
class _Container(containers.DeclarativeContainer):
provider_type = providers.Object
px = providers.Object(object())
self.assertIsInstance(_Container.px, providers.Object)
def test_declare_with_invalid_provider_type(self):
"""Test declaration of container with invalid provider type."""
with self.assertRaises(errors.Error):
class _Container(containers.DeclarativeContainer):
provider_type = providers.Object
px = providers.Provider()
def test_seth_valid_provider_type(self):
"""Test setting of valid provider."""
class _Container(containers.DeclarativeContainer):
provider_type = providers.Object
_Container.px = providers.Object(object())
self.assertIsInstance(_Container.px, providers.Object)
def test_set_invalid_provider_type(self):
"""Test setting of invalid provider."""
class _Container(containers.DeclarativeContainer):
provider_type = providers.Object
with self.assertRaises(errors.Error):
_Container.px = providers.Provider()
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.override(_OverridingContainer1)
_Container.override(_OverridingContainer2)
self.assertEqual(_Container.overridden_by,
(_OverridingContainer1,
_OverridingContainer2))
self.assertEqual(_Container.p11.overridden_by,
(_OverridingContainer1.p11,
_OverridingContainer2.p11))
def test_override_with_itself(self):
"""Test override with itself."""
with self.assertRaises(errors.Error):
ContainerA.override(ContainerA)
def test_override_with_parent(self):
"""Test override with parent."""
with self.assertRaises(errors.Error):
ContainerB.override(ContainerA)
def test_override_decorator(self):
"""Test override decorator."""
class _Container(containers.DeclarativeContainer):
p11 = providers.Provider()
@containers.override(_Container)
class _OverridingContainer1(containers.DeclarativeContainer):
p11 = providers.Provider()
@containers.override(_Container)
class _OverridingContainer2(containers.DeclarativeContainer):
p11 = providers.Provider()
p12 = providers.Provider()
self.assertEqual(_Container.overridden_by,
(_OverridingContainer1,
_OverridingContainer2))
self.assertEqual(_Container.p11.overridden_by,
(_OverridingContainer1.p11,
_OverridingContainer2.p11))
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.override(_OverridingContainer1)
_Container.override(_OverridingContainer2)
_Container.reset_last_overriding()
self.assertEqual(_Container.overridden_by,
(_OverridingContainer1,))
self.assertEqual(_Container.p11.overridden_by,
(_OverridingContainer1.p11,))
def test_reset_last_overridding_when_not_overridden(self):
"""Test reset of last overriding."""
with self.assertRaises(errors.Error):
ContainerA.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.override(_OverridingContainer1)
_Container.override(_OverridingContainer2)
_Container.reset_override()
self.assertEqual(_Container.overridden_by, tuple())
self.assertEqual(_Container.p11.overridden_by, tuple())
def test_copy(self):
"""Test copy decorator."""
@containers.copy(ContainerA)
class _Container1(ContainerA):
pass
@containers.copy(ContainerA)
class _Container2(ContainerA):
pass
self.assertIsNot(ContainerA.p11, _Container1.p11)
self.assertIsNot(ContainerA.p12, _Container1.p12)
self.assertIsNot(ContainerA.p11, _Container2.p11)
self.assertIsNot(ContainerA.p12, _Container2.p12)
self.assertIsNot(_Container1.p11, _Container2.p11)
self.assertIsNot(_Container1.p12, _Container2.p12)
def test_copy_with_replacing(self):
"""Test copy decorator with providers replacement."""
class _Container(containers.DeclarativeContainer):
p11 = providers.Object(0)
p12 = providers.Factory(dict, p11=p11)
@containers.copy(_Container)
class _Container1(_Container):
p11 = providers.Object(1)
p13 = providers.Object(11)
@containers.copy(_Container)
class _Container2(_Container):
p11 = providers.Object(2)
p13 = providers.Object(22)
self.assertIsNot(_Container.p11, _Container1.p11)
self.assertIsNot(_Container.p12, _Container1.p12)
self.assertIsNot(_Container.p11, _Container2.p11)
self.assertIsNot(_Container.p12, _Container2.p12)
self.assertIsNot(_Container1.p11, _Container2.p11)
self.assertIsNot(_Container1.p12, _Container2.p12)
self.assertIs(_Container.p12.kwargs['p11'], _Container.p11)
self.assertIs(_Container1.p12.kwargs['p11'], _Container1.p11)
self.assertIs(_Container2.p12.kwargs['p11'], _Container2.p11)
self.assertEqual(_Container.p12(), dict(p11=0))
self.assertEqual(_Container1.p12(), dict(p11=1))
self.assertEqual(_Container2.p12(), dict(p11=2))
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()))