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