mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-06-16 19:43:15 +03:00
Merge remote-tracking branch 'origin/2.0-ioc-containers' into 2.0
This commit is contained in:
commit
5ecb00daba
30
README.rst
30
README.rst
|
@ -52,7 +52,7 @@ Installation
|
||||||
Example
|
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
|
providers for definition of several IoC containers for some microservice
|
||||||
system that consists from several business and platform services:
|
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 boto.s3.connection
|
||||||
import example.services
|
import example.services
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
class Platform(catalogs.DeclarativeCatalog):
|
class Platform(containers.DeclarativeContainer):
|
||||||
"""Catalog of platform service providers."""
|
"""IoC container of platform service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||||
|
|
||||||
|
@ -78,8 +78,8 @@ system that consists from several business and platform services:
|
||||||
aws_secret_access_key='SECRET')
|
aws_secret_access_key='SECRET')
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of business service providers."""
|
"""IoC container of business service providers."""
|
||||||
|
|
||||||
users = providers.Factory(example.services.Users,
|
users = providers.Factory(example.services.Users,
|
||||||
db=Platform.database)
|
db=Platform.database)
|
||||||
|
@ -101,7 +101,7 @@ defined above:
|
||||||
|
|
||||||
from dependency_injector.injections import inject
|
from dependency_injector.injections import inject
|
||||||
|
|
||||||
from catalogs import Services
|
from containers import Services
|
||||||
|
|
||||||
|
|
||||||
@inject(users_service=Services.users)
|
@inject(users_service=Services.users)
|
||||||
|
@ -127,8 +127,8 @@ IoC containers from previous example could look like these:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class Platform(catalogs.DeclarativeCatalog):
|
class Platform(containers.DeclarativeContainer):
|
||||||
"""Catalog of platform service providers."""
|
"""IoC container of platform service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect) \
|
database = providers.Singleton(sqlite3.connect) \
|
||||||
.add_args(':memory:')
|
.add_args(':memory:')
|
||||||
|
@ -138,8 +138,8 @@ IoC containers from previous example could look like these:
|
||||||
aws_secret_access_key='SECRET')
|
aws_secret_access_key='SECRET')
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of business service providers."""
|
"""IoC container of business service providers."""
|
||||||
|
|
||||||
users = providers.Factory(example.services.Users) \
|
users = providers.Factory(example.services.Users) \
|
||||||
.add_kwargs(db=Platform.database)
|
.add_kwargs(db=Platform.database)
|
||||||
|
@ -156,8 +156,8 @@ or like this these:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class Platform(catalogs.DeclarativeCatalog):
|
class Platform(containers.DeclarativeContainer):
|
||||||
"""Catalog of platform service providers."""
|
"""IoC container of platform service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect)
|
database = providers.Singleton(sqlite3.connect)
|
||||||
database.add_args(':memory:')
|
database.add_args(':memory:')
|
||||||
|
@ -167,8 +167,8 @@ or like this these:
|
||||||
aws_secret_access_key='SECRET')
|
aws_secret_access_key='SECRET')
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of business service providers."""
|
"""IoC container of business service providers."""
|
||||||
|
|
||||||
users = providers.Factory(example.services.Users)
|
users = providers.Factory(example.services.Users)
|
||||||
users.add_kwargs(db=Platform.database)
|
users.add_kwargs(db=Platform.database)
|
||||||
|
|
|
@ -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',
|
|
||||||
)
|
|
|
@ -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')
|
|
|
@ -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__
|
|
|
@ -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
|
|
268
dependency_injector/containers.py
Normal file
268
dependency_injector/containers.py
Normal 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))
|
|
@ -64,7 +64,7 @@ class Provider(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initializer."""
|
"""Initializer."""
|
||||||
self.overridden_by = None
|
self.overridden_by = tuple()
|
||||||
super(Provider, self).__init__()
|
super(Provider, self).__init__()
|
||||||
# Enable __call__() / _provide() optimization
|
# Enable __call__() / _provide() optimization
|
||||||
if self.__class__.__OPTIMIZED_CALLS__:
|
if self.__class__.__OPTIMIZED_CALLS__:
|
||||||
|
@ -124,9 +124,6 @@ class Provider(object):
|
||||||
if not is_provider(provider):
|
if not is_provider(provider):
|
||||||
provider = Object(provider)
|
provider = Object(provider)
|
||||||
|
|
||||||
if not self.is_overridden:
|
|
||||||
self.overridden_by = (ensure_is_provider(provider),)
|
|
||||||
else:
|
|
||||||
self.overridden_by += (ensure_is_provider(provider),)
|
self.overridden_by += (ensure_is_provider(provider),)
|
||||||
|
|
||||||
# Disable __call__() / _provide() optimization
|
# Disable __call__() / _provide() optimization
|
||||||
|
@ -145,6 +142,7 @@ class Provider(object):
|
||||||
"""
|
"""
|
||||||
if not self.overridden_by:
|
if not self.overridden_by:
|
||||||
raise Error('Provider {0} is not overridden'.format(str(self)))
|
raise Error('Provider {0} is not overridden'.format(str(self)))
|
||||||
|
|
||||||
self.overridden_by = self.overridden_by[:-1]
|
self.overridden_by = self.overridden_by[:-1]
|
||||||
|
|
||||||
if not self.is_overridden:
|
if not self.is_overridden:
|
||||||
|
@ -157,7 +155,7 @@ class Provider(object):
|
||||||
|
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
self.overridden_by = None
|
self.overridden_by = tuple()
|
||||||
|
|
||||||
# Enable __call__() / _provide() optimization
|
# Enable __call__() / _provide() optimization
|
||||||
if self.__class__.__OPTIMIZED_CALLS__:
|
if self.__class__.__OPTIMIZED_CALLS__:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Utils module."""
|
"""Utils module."""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import copy
|
import copy as _copy
|
||||||
import types
|
import types
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ else: # pragma: no cover
|
||||||
_OBJECT_INIT = None
|
_OBJECT_INIT = None
|
||||||
|
|
||||||
if six.PY2: # pragma: no cover
|
if six.PY2: # pragma: no cover
|
||||||
copy._deepcopy_dispatch[types.MethodType] = \
|
_copy._deepcopy_dispatch[types.MethodType] = \
|
||||||
lambda obj, memo: type(obj)(obj.im_func,
|
lambda obj, memo: type(obj)(obj.im_func,
|
||||||
copy.deepcopy(obj.im_self, memo),
|
_copy.deepcopy(obj.im_self, memo),
|
||||||
obj.im_class)
|
obj.im_class)
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,38 +59,16 @@ def ensure_is_provider(instance):
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
def is_catalog(instance):
|
def is_container(instance):
|
||||||
"""Check if instance is catalog instance.
|
"""Check if instance is container instance.
|
||||||
|
|
||||||
:param instance: Instance to be checked.
|
:param instance: Instance to be checked.
|
||||||
:type instance: object
|
:type instance: object
|
||||||
|
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
return (hasattr(instance, '__IS_CATALOG__') and
|
return (hasattr(instance, '__IS_CONTAINER__') and
|
||||||
getattr(instance, '__IS_CATALOG__', False) is True)
|
getattr(instance, '__IS_CONTAINER__', False) is True)
|
||||||
|
|
||||||
|
|
||||||
def is_dynamic_catalog(instance):
|
|
||||||
"""Check if instance is dynamic catalog instance.
|
|
||||||
|
|
||||||
:param instance: Instance to be checked.
|
|
||||||
:type instance: object
|
|
||||||
|
|
||||||
:rtype: bool
|
|
||||||
"""
|
|
||||||
return (not isinstance(instance, six.class_types) and is_catalog(instance))
|
|
||||||
|
|
||||||
|
|
||||||
def is_declarative_catalog(instance):
|
|
||||||
"""Check if instance is declarative catalog instance.
|
|
||||||
|
|
||||||
:param instance: Instance to be checked.
|
|
||||||
:type instance: object
|
|
||||||
|
|
||||||
:rtype: bool
|
|
||||||
"""
|
|
||||||
return (isinstance(instance, six.class_types) and is_catalog(instance))
|
|
||||||
|
|
||||||
|
|
||||||
def represent_provider(provider, provides):
|
def represent_provider(provider, provides):
|
||||||
|
@ -130,6 +108,6 @@ def fetch_cls_init(cls):
|
||||||
return cls_init
|
return cls_init
|
||||||
|
|
||||||
|
|
||||||
def _copy_providers(providers, memo=None):
|
def deepcopy(instance, memo=None):
|
||||||
"""Make full copy of providers dictionary."""
|
"""Make full copy of instance."""
|
||||||
return copy.deepcopy(providers, memo)
|
return _copy.deepcopy(instance, memo)
|
||||||
|
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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)
|
|
|
@ -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)
|
|
|
@ -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
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
# Defining declarative catalog:
|
# Defining declarative IoC container:
|
||||||
class Catalog(catalogs.DeclarativeCatalog):
|
class Container(containers.DeclarativeContainer):
|
||||||
"""Providers catalog."""
|
"""Example IoC container."""
|
||||||
|
|
||||||
factory1 = providers.Factory(object)
|
factory1 = providers.Factory(object)
|
||||||
|
|
||||||
factory2 = providers.Factory(object)
|
factory2 = providers.Factory(object)
|
||||||
|
|
||||||
# Creating some objects:
|
# Creating some objects:
|
||||||
object1 = Catalog.factory1()
|
object1 = Container.factory1()
|
||||||
object2 = Catalog.factory2()
|
object2 = Container.factory2()
|
||||||
|
|
||||||
# Making some asserts:
|
# Making some asserts:
|
||||||
assert object1 is not object2
|
assert object1 is not object2
|
30
examples/containers/declarative_inheritance.py
Normal file
30
examples/containers/declarative_inheritance.py
Normal 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)
|
|
@ -1,8 +1,8 @@
|
||||||
"""Declarative catalog's provider injections example."""
|
"""Declarative IoC container's provider injections example."""
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ class AuthService(object):
|
||||||
self.users_service = users_service
|
self.users_service = users_service
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of service providers."""
|
"""IoC container of service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class Services(catalogs.DeclarativeCatalog):
|
||||||
users_service=users)
|
users_service=users)
|
||||||
|
|
||||||
|
|
||||||
# Retrieving service providers from catalog:
|
# Retrieving service providers from container:
|
||||||
users_service = Services.users()
|
users_service = Services.users()
|
||||||
auth_service = Services.auth()
|
auth_service = Services.auth()
|
||||||
|
|
17
examples/containers/declarative_provider_type/container.py
Normal file
17
examples/containers/declarative_provider_type/container.py
Normal 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)
|
26
examples/containers/declarative_provider_type/core.py
Normal file
26
examples/containers/declarative_provider_type/core.py
Normal 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
|
42
examples/containers/declarative_provider_type/main.py
Normal file
42
examples/containers/declarative_provider_type/main.py
Normal 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
|
22
examples/containers/declarative_provider_type/services.py
Normal file
22
examples/containers/declarative_provider_type/services.py
Normal 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__()
|
|
@ -1,8 +1,8 @@
|
||||||
"""Declarative catalog overriding example."""
|
"""Declarative IoC container overriding example."""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ Object2 = collections.namedtuple('Object2', ['object1'])
|
||||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||||
|
|
||||||
|
|
||||||
class Catalog(catalogs.DeclarativeCatalog):
|
class Container(containers.DeclarativeContainer):
|
||||||
"""Catalog of some providers."""
|
"""Example IoC container."""
|
||||||
|
|
||||||
object1_factory = providers.Factory(Object1,
|
object1_factory = providers.Factory(Object1,
|
||||||
arg1=1,
|
arg1=1,
|
||||||
|
@ -23,21 +23,21 @@ class Catalog(catalogs.DeclarativeCatalog):
|
||||||
object1=object1_factory)
|
object1=object1_factory)
|
||||||
|
|
||||||
|
|
||||||
class AnotherCatalog(catalogs.DeclarativeCatalog):
|
class OverridingContainer(containers.DeclarativeContainer):
|
||||||
"""Overriding catalog."""
|
"""Overriding IoC container."""
|
||||||
|
|
||||||
object2_factory = providers.Factory(ExtendedObject2)
|
object2_factory = providers.Factory(ExtendedObject2)
|
||||||
|
|
||||||
|
|
||||||
# Overriding `Catalog` with `AnotherCatalog`:
|
# Overriding `Container` with `OverridingContainer`:
|
||||||
Catalog.override(AnotherCatalog)
|
Container.override(OverridingContainer)
|
||||||
|
|
||||||
# Creating some objects using overridden catalog:
|
# Creating some objects using overridden container:
|
||||||
object2_1 = Catalog.object2_factory()
|
object2_1 = Container.object2_factory()
|
||||||
object2_2 = Catalog.object2_factory()
|
object2_2 = Container.object2_factory()
|
||||||
|
|
||||||
# Making some asserts:
|
# Making some asserts:
|
||||||
assert Catalog.is_overridden
|
assert Container.overridden_by == (OverridingContainer,)
|
||||||
|
|
||||||
assert object2_1 is not object2_2
|
assert object2_1 is not object2_2
|
||||||
|
|
41
examples/containers/override_declarative_decorator.py
Normal file
41
examples/containers/override_declarative_decorator.py
Normal 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)
|
|
@ -10,7 +10,7 @@ class Car(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initializer."""
|
"""Initializer."""
|
||||||
self.engine = Engine()
|
self.engine = Engine() # Engine is a "hardcoded" dependency
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Car(object):
|
||||||
|
|
||||||
def __init__(self, engine):
|
def __init__(self, engine):
|
||||||
"""Initializer."""
|
"""Initializer."""
|
||||||
self.engine = engine
|
self.engine = engine # Engine is an "injected" dependency
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
"""Example of inversion of control container for Car & Engine example."""
|
"""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 dependency_injector import providers
|
||||||
|
|
||||||
from car_engine_ioc import Car
|
from car_engine_ioc import Car
|
||||||
from car_engine_ioc import Engine
|
from car_engine_ioc import Engine
|
||||||
|
|
||||||
|
|
||||||
class Components(catalogs.DeclarativeCatalog):
|
class Components(containers.DeclarativeContainer):
|
||||||
"""Catalog of component providers."""
|
"""IoC container of component providers."""
|
||||||
|
|
||||||
engine = providers.Factory(Engine)
|
engine = providers.Factory(Engine)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ This mini application uses ``movies`` library, that is configured to work with
|
||||||
csv file movies database.
|
csv file movies database.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
from dependency_injector import injections
|
from dependency_injector import injections
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ from movies import finders
|
||||||
from settings import MOVIES_CSV_PATH
|
from settings import MOVIES_CSV_PATH
|
||||||
|
|
||||||
|
|
||||||
@catalogs.override(MoviesModule)
|
@containers.override(MoviesModule)
|
||||||
class MyMoviesModule(catalogs.DeclarativeCatalog):
|
class MyMoviesModule(containers.DeclarativeContainer):
|
||||||
"""Customized catalog of movies module component providers."""
|
"""IoC container for overriding movies module component providers."""
|
||||||
|
|
||||||
movie_finder = providers.Factory(finders.CsvMovieFinder,
|
movie_finder = providers.Factory(finders.CsvMovieFinder,
|
||||||
*MoviesModule.movie_finder.injections,
|
|
||||||
csv_file=MOVIES_CSV_PATH,
|
csv_file=MOVIES_CSV_PATH,
|
||||||
delimeter=',')
|
delimeter=',',
|
||||||
|
**MoviesModule.movie_finder.kwargs)
|
||||||
|
|
||||||
|
|
||||||
@injections.inject(MoviesModule.movie_lister)
|
@injections.inject(MoviesModule.movie_lister)
|
||||||
|
|
|
@ -11,7 +11,7 @@ sqlite movies database.
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
from dependency_injector import injections
|
from dependency_injector import injections
|
||||||
|
|
||||||
|
@ -21,19 +21,19 @@ from movies import finders
|
||||||
from settings import MOVIES_DB_PATH
|
from settings import MOVIES_DB_PATH
|
||||||
|
|
||||||
|
|
||||||
class ApplicationModule(catalogs.DeclarativeCatalog):
|
class ApplicationModule(containers.DeclarativeContainer):
|
||||||
"""Catalog of application component providers."""
|
"""IoC container of application component providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, MOVIES_DB_PATH)
|
database = providers.Singleton(sqlite3.connect, MOVIES_DB_PATH)
|
||||||
|
|
||||||
|
|
||||||
@catalogs.override(MoviesModule)
|
@containers.override(MoviesModule)
|
||||||
class MyMoviesModule(catalogs.DeclarativeCatalog):
|
class MyMoviesModule(containers.DeclarativeContainer):
|
||||||
"""Customized catalog of movies module component providers."""
|
"""IoC container for overriding movies module component providers."""
|
||||||
|
|
||||||
movie_finder = providers.Factory(finders.SqliteMovieFinder,
|
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)
|
@injections.inject(MoviesModule.movie_lister)
|
||||||
|
|
|
@ -11,7 +11,7 @@ sqlite movies database and csv file movies database.
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
from dependency_injector import injections
|
from dependency_injector import injections
|
||||||
|
|
||||||
|
@ -22,29 +22,29 @@ from settings import MOVIES_CSV_PATH
|
||||||
from settings import MOVIES_DB_PATH
|
from settings import MOVIES_DB_PATH
|
||||||
|
|
||||||
|
|
||||||
class ApplicationModule(catalogs.DeclarativeCatalog):
|
class ApplicationModule(containers.DeclarativeContainer):
|
||||||
"""Catalog of application component providers."""
|
"""IoC container of application component providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, MOVIES_DB_PATH)
|
database = providers.Singleton(sqlite3.connect, MOVIES_DB_PATH)
|
||||||
|
|
||||||
|
|
||||||
@catalogs.copy(MoviesModule)
|
@containers.copy(MoviesModule)
|
||||||
class DbMoviesModule(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,
|
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):
|
class CsvMoviesModule(MoviesModule):
|
||||||
"""Customized catalog of movies module component providers."""
|
"""IoC container for overriding movies module component providers."""
|
||||||
|
|
||||||
movie_finder = providers.Factory(finders.CsvMovieFinder,
|
movie_finder = providers.Factory(finders.CsvMovieFinder,
|
||||||
*MoviesModule.movie_finder.injections,
|
|
||||||
csv_file=MOVIES_CSV_PATH,
|
csv_file=MOVIES_CSV_PATH,
|
||||||
delimeter=',')
|
delimeter=',',
|
||||||
|
**MoviesModule.movie_finder.kwargs)
|
||||||
|
|
||||||
|
|
||||||
@injections.inject(db_movie_lister=DbMoviesModule.movie_lister)
|
@injections.inject(db_movie_lister=DbMoviesModule.movie_lister)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"""Movies package.
|
"""Movies package.
|
||||||
|
|
||||||
Top-level package of movies library. This package contains catalog of movies
|
Top-level package of movies library. This package contains IoC container of
|
||||||
module component providers - ``MoviesModule``. It is recommended to use movies
|
movies module component providers - ``MoviesModule``. It is recommended to use
|
||||||
library functionality by fetching required instances from ``MoviesModule``
|
movies library functionality by fetching required instances from
|
||||||
providers.
|
``MoviesModule`` providers.
|
||||||
|
|
||||||
``MoviesModule.movie_finder`` is a factory that provides abstract component
|
``MoviesModule.movie_finder`` is a factory that provides abstract component
|
||||||
``finders.MovieFinder``. This provider should be overridden by provider of
|
``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.
|
Each of ``MoviesModule`` providers could be overridden.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
from . import finders
|
from . import finders
|
||||||
|
@ -20,8 +20,8 @@ from . import listers
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
class MoviesModule(catalogs.DeclarativeCatalog):
|
class MoviesModule(containers.DeclarativeContainer):
|
||||||
"""Catalog of movies module component providers."""
|
"""IoC container of movies module component providers."""
|
||||||
|
|
||||||
movie_model = providers.DelegatedFactory(models.Movie)
|
movie_model = providers.DelegatedFactory(models.Movie)
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,12 @@ import sqlite3
|
||||||
import boto.s3.connection
|
import boto.s3.connection
|
||||||
import example.services
|
import example.services
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
class Platform(catalogs.DeclarativeCatalog):
|
class Platform(containers.DeclarativeContainer):
|
||||||
"""Catalog of platform service providers."""
|
"""IoC container of platform service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@ class Platform(catalogs.DeclarativeCatalog):
|
||||||
aws_secret_access_key='SECRET')
|
aws_secret_access_key='SECRET')
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of business service providers."""
|
"""IoC container of business service providers."""
|
||||||
|
|
||||||
users = providers.Factory(example.services.Users,
|
users = providers.Factory(example.services.Users,
|
||||||
db=Platform.database)
|
db=Platform.database)
|
|
@ -7,12 +7,12 @@ import sqlite3
|
||||||
import boto.s3.connection
|
import boto.s3.connection
|
||||||
import example.services
|
import example.services
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
class Platform(catalogs.DeclarativeCatalog):
|
class Platform(containers.DeclarativeContainer):
|
||||||
"""Catalog of platform service providers."""
|
"""IoC container of platform service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect) \
|
database = providers.Singleton(sqlite3.connect) \
|
||||||
.add_args(':memory:')
|
.add_args(':memory:')
|
||||||
|
@ -22,8 +22,8 @@ class Platform(catalogs.DeclarativeCatalog):
|
||||||
aws_secret_access_key='SECRET')
|
aws_secret_access_key='SECRET')
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of business service providers."""
|
"""IoC container of business service providers."""
|
||||||
|
|
||||||
users = providers.Factory(example.services.Users) \
|
users = providers.Factory(example.services.Users) \
|
||||||
.add_kwargs(db=Platform.database)
|
.add_kwargs(db=Platform.database)
|
|
@ -7,12 +7,12 @@ import sqlite3
|
||||||
import boto.s3.connection
|
import boto.s3.connection
|
||||||
import example.services
|
import example.services
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
class Platform(catalogs.DeclarativeCatalog):
|
class Platform(containers.DeclarativeContainer):
|
||||||
"""Catalog of platform service providers."""
|
"""IoC container of platform service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect)
|
database = providers.Singleton(sqlite3.connect)
|
||||||
database.add_args(':memory:')
|
database.add_args(':memory:')
|
||||||
|
@ -22,8 +22,8 @@ class Platform(catalogs.DeclarativeCatalog):
|
||||||
aws_secret_access_key='SECRET')
|
aws_secret_access_key='SECRET')
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of business service providers."""
|
"""IoC container of business service providers."""
|
||||||
|
|
||||||
users = providers.Factory(example.services.Users)
|
users = providers.Factory(example.services.Users)
|
||||||
users.add_kwargs(db=Platform.database)
|
users.add_kwargs(db=Platform.database)
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from dependency_injector.injections import inject
|
from dependency_injector.injections import inject
|
||||||
|
|
||||||
from catalogs import Services
|
from containers import Services
|
||||||
|
|
||||||
|
|
||||||
@inject(users_service=Services.users)
|
@inject(users_service=Services.users)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
"""Pythonic way for Dependency Injection - Providing Callbacks Catalog."""
|
"""Pythonic way for Dependency Injection - callback-based IoC container."""
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
from dependency_injector import injections
|
from dependency_injector import injections
|
||||||
|
|
||||||
|
@ -24,14 +24,14 @@ class AuthService(object):
|
||||||
self.users_service = users_service
|
self.users_service = users_service
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(containers.DeclarativeContainer):
|
||||||
"""Catalog of service providers."""
|
"""IoC container of service providers."""
|
||||||
|
|
||||||
@providers.Singleton
|
@providers.Singleton
|
||||||
def database():
|
def database():
|
||||||
"""Provide database connection.
|
"""Provide database connection.
|
||||||
|
|
||||||
:rtype: providers.Provider -> sqlite3.Connection
|
:rtype: sqlite3.Connection
|
||||||
"""
|
"""
|
||||||
return sqlite3.connect(':memory:')
|
return sqlite3.connect(':memory:')
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class Services(catalogs.DeclarativeCatalog):
|
||||||
def users(**kwargs):
|
def users(**kwargs):
|
||||||
"""Provide users service.
|
"""Provide users service.
|
||||||
|
|
||||||
:rtype: providers.Provider -> UsersService
|
:rtype: UsersService
|
||||||
"""
|
"""
|
||||||
return UsersService(**kwargs)
|
return UsersService(**kwargs)
|
||||||
|
|
||||||
|
@ -50,12 +50,12 @@ class Services(catalogs.DeclarativeCatalog):
|
||||||
def auth(**kwargs):
|
def auth(**kwargs):
|
||||||
"""Provide users service.
|
"""Provide users service.
|
||||||
|
|
||||||
:rtype: providers.Provider -> AuthService
|
:rtype: AuthService
|
||||||
"""
|
"""
|
||||||
return AuthService(**kwargs)
|
return AuthService(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
# Retrieving catalog providers:
|
# Retrieving services:
|
||||||
users_service = Services.users()
|
users_service = Services.users()
|
||||||
auth_service = Services.auth()
|
auth_service = Services.auth()
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -54,7 +54,6 @@ setup(name='dependency_injector',
|
||||||
download_url='https://pypi.python.org/pypi/dependency_injector',
|
download_url='https://pypi.python.org/pypi/dependency_injector',
|
||||||
license='BSD New',
|
license='BSD New',
|
||||||
packages=['dependency_injector',
|
packages=['dependency_injector',
|
||||||
'dependency_injector.catalogs',
|
|
||||||
'dependency_injector.providers'],
|
'dependency_injector.providers'],
|
||||||
platforms=['any'],
|
platforms=['any'],
|
||||||
zip_safe=True,
|
zip_safe=True,
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
"""Dependency injector catalogs unittests."""
|
|
|
@ -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)
|
|
|
@ -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)
|
|
|
@ -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
437
tests/test_containers.py
Normal 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()
|
|
@ -4,7 +4,6 @@ import unittest2 as unittest
|
||||||
|
|
||||||
from dependency_injector import utils
|
from dependency_injector import utils
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
from dependency_injector import catalogs
|
|
||||||
from dependency_injector import errors
|
from dependency_injector import errors
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,56 +68,3 @@ class EnsureIsProviderTests(unittest.TestCase):
|
||||||
def test_with_object(self):
|
def test_with_object(self):
|
||||||
"""Test with object."""
|
"""Test with object."""
|
||||||
self.assertRaises(errors.Error, utils.ensure_is_provider, 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()))
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user