Split `providers` module into smaller modules

This commit is contained in:
Roman Mogilatov 2016-04-03 17:27:53 +03:00
parent 99a3997e08
commit 040d44d55b
19 changed files with 1784 additions and 1646 deletions

View File

@ -1,54 +1,64 @@
"""Dependency injector.""" """Dependency injector."""
from .catalogs import DeclarativeCatalog from dependency_injector.catalogs import (
from .catalogs import AbstractCatalog DeclarativeCatalog,
from .catalogs import DynamicCatalog AbstractCatalog,
from .catalogs import CatalogBundle DynamicCatalog,
from .catalogs import override CatalogBundle,
override,
)
from .providers import Provider from dependency_injector.providers import (
from .providers import Delegate Provider,
from .providers import Callable Delegate,
from .providers import DelegatedCallable Callable,
from .providers import Factory DelegatedCallable,
from .providers import DelegatedFactory Factory,
from .providers import Singleton DelegatedFactory,
from .providers import DelegatedSingleton Singleton,
from .providers import ExternalDependency DelegatedSingleton,
from .providers import StaticProvider ExternalDependency,
from .providers import Class StaticProvider,
from .providers import Object Class,
from .providers import Function Object,
from .providers import Value Function,
from .providers import Config Value,
Config,
)
from .injections import Injection from dependency_injector.injections import (
from .injections import Arg Injection,
from .injections import KwArg Arg,
from .injections import Attribute KwArg,
from .injections import Method Attribute,
from .injections import inject Method,
inject,
)
from .utils import is_provider from dependency_injector.utils import (
from .utils import ensure_is_provider is_provider,
from .utils import is_delegated_provider ensure_is_provider,
from .utils import is_injection is_delegated_provider,
from .utils import ensure_is_injection is_injection,
from .utils import is_arg_injection ensure_is_injection,
from .utils import is_kwarg_injection is_arg_injection,
from .utils import is_attribute_injection is_kwarg_injection,
from .utils import is_method_injection is_attribute_injection,
from .utils import is_catalog is_method_injection,
from .utils import is_dynamic_catalog is_catalog,
from .utils import is_declarative_catalog is_dynamic_catalog,
from .utils import is_catalog_bundle is_declarative_catalog,
from .utils import ensure_is_catalog_bundle is_catalog_bundle,
ensure_is_catalog_bundle,
)
from .errors import Error from dependency_injector.errors import (
from .errors import UndefinedProviderError Error,
UndefinedProviderError,
)
# Backward compatibility for versions < 0.11.* # Backward compatibility for versions < 0.11.*
from . import catalogs from dependency_injector import catalogs
catalog = catalogs catalog = catalogs
VERSION = '1.15.1' VERSION = '1.15.1'

View File

@ -2,14 +2,18 @@
import six import six
from .errors import Error from dependency_injector.errors import (
from .errors import UndefinedProviderError Error,
UndefinedProviderError,
)
from .utils import is_provider from dependency_injector.utils import (
from .utils import is_catalog is_provider,
from .utils import is_declarative_catalog is_catalog,
from .utils import ensure_is_provider is_declarative_catalog,
from .utils import ensure_is_catalog_bundle ensure_is_provider,
ensure_is_catalog_bundle,
)
@six.python_2_unicode_compatible @six.python_2_unicode_compatible

View File

@ -2,14 +2,16 @@
import six import six
from .utils import is_provider from dependency_injector.utils import (
from .utils import is_delegated_provider is_provider,
from .utils import is_injection is_delegated_provider,
from .utils import is_arg_injection is_injection,
from .utils import is_kwarg_injection is_arg_injection,
from .utils import fetch_cls_init is_kwarg_injection,
fetch_cls_init,
)
from .errors import Error from dependency_injector.errors import Error
@six.python_2_unicode_compatible @six.python_2_unicode_compatible

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
"""Dependency injector providers package."""
from dependency_injector.providers.base import (
Provider,
Delegate,
Static,
StaticProvider,
ExternalDependency,
OverridingContext,
override,
)
from dependency_injector.providers.callable import (
Callable,
DelegatedCallable,
)
from dependency_injector.providers.creational import (
Factory,
DelegatedFactory,
Singleton,
DelegatedSingleton,
)
from dependency_injector.providers.static import (
Object,
Value,
Class,
Function,
)
from dependency_injector.providers.config import (
Config,
ChildConfig,
)
__all__ = (
'Provider',
'Delegate',
'Static', 'StaticProvider',
'ExternalDependency',
'Callable',
'DelegatedCallable',
'Factory',
'DelegatedFactory',
'Singleton',
'DelegatedSingleton',
'Object',
'Value',
'Class',
'Function',
'Config',
'ChildConfig',
'OverridingContext',
'override',
)

View File

@ -0,0 +1,422 @@
"""Dependency injector base providers."""
import six
from dependency_injector.errors import Error
from dependency_injector.utils import (
is_provider,
ensure_is_provider,
represent_provider,
)
@six.python_2_unicode_compatible
class Provider(object):
"""Base provider class.
:py:class:`Provider` is callable (implements ``__call__`` method). Every
call to provider object returns provided result, according to the providing
strategy of particular provider. This ``callable`` functionality is a
regular part of providers API and it should be the same for all provider's
subclasses.
Implementation of particular providing strategy should be done in
:py:meth:`Provider._provide` of :py:class:`Provider` subclass. Current
method is called every time when not overridden provider is called.
:py:class:`Provider` implements provider overriding logic that should be
also common for all providers:
.. code-block:: python
provider1 = Factory(SomeClass)
provider2 = Factory(ChildSomeClass)
provider1.override(provider2)
some_instance = provider1()
assert isinstance(some_instance, ChildSomeClass)
Also :py:class:`Provider` implements helper function for creating its
delegates:
.. code-block:: python
provider = Factory(object)
delegate = provider.delegate()
delegated = delegate()
assert provider is delegated
All providers should extend this class.
.. py:attribute:: overridden_by
Tuple of overriding providers, if any.
:type: tuple[:py:class:`Provider`] | None
"""
__IS_PROVIDER__ = True
__OPTIMIZED_CALLS__ = True
__slots__ = ('overridden_by', 'provide', '__call__')
def __init__(self):
"""Initializer."""
self.overridden_by = None
super(Provider, self).__init__()
# Enable __call__() / _provide() optimization
if self.__class__.__OPTIMIZED_CALLS__:
self.__call__ = self.provide = self._provide
def _provide(self, *args, **kwargs):
"""Providing strategy implementation.
Abstract protected method that implements providing strategy of
particular provider. Current method is called every time when not
overridden provider is called. Need to be overridden in subclasses.
"""
raise NotImplementedError()
def _call_last_overriding(self, *args, **kwargs):
"""Call last overriding provider and return result."""
return self.last_overriding(*args, **kwargs)
@property
def is_overridden(self):
"""Read-only property that is set to ``True`` if provider is overridden.
:rtype: bool
"""
return bool(self.overridden_by)
@property
def last_overriding(self):
"""Read-only reference to the last overriding provider, if any.
:type: :py:class:`Provider` | None
"""
return self.overridden_by[-1] if self.overridden_by else None
def override(self, provider):
"""Override provider with another provider.
:param provider: Overriding provider.
:type provider: :py:class:`Provider`
:raise: :py:exc:`dependency_injector.errors.Error`
:return: Overriding provider.
:rtype: :py:class:`Provider`
"""
if provider is self:
raise Error('Provider {0} could not be overridden '
'with itself'.format(self))
if not is_provider(provider):
provider = Static(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
if self.__class__.__OPTIMIZED_CALLS__:
self.__call__ = self.provide = self._call_last_overriding
return OverridingContext(self, provider)
def reset_last_overriding(self):
"""Reset last overriding provider.
:raise: :py:exc:`dependency_injector.errors.Error` if provider is not
overridden.
:rtype: None
"""
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:
# Enable __call__() / _provide() optimization
if self.__class__.__OPTIMIZED_CALLS__:
self.__call__ = self.provide = self._provide
def reset_override(self):
"""Reset all overriding providers.
:rtype: None
"""
self.overridden_by = None
# Enable __call__() / _provide() optimization
if self.__class__.__OPTIMIZED_CALLS__:
self.__call__ = self.provide = self._provide
def delegate(self):
"""Return provider's delegate.
:rtype: :py:class:`Delegate`
"""
return Delegate(self)
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self, provides=None)
__repr__ = __str__
@six.python_2_unicode_compatible
class Delegate(Provider):
""":py:class:`Delegate` provider delegates another provider.
.. code-block:: python
provider = Factory(object)
delegate = Delegate(provider)
delegated = delegate()
assert provider is delegated
.. py:attribute:: delegated
Delegated provider.
:type: :py:class:`Provider`
"""
__slots__ = ('delegated',)
def __init__(self, delegated):
"""Initializer.
:provider delegated: Delegated provider.
:type delegated: :py:class:`Provider`
"""
self.delegated = ensure_is_provider(delegated)
super(Delegate, self).__init__()
def _provide(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:rtype: object
"""
return self.delegated
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self, provides=self.delegated)
__repr__ = __str__
@six.python_2_unicode_compatible
class Static(Provider):
""":py:class:`Static` provider returns provided instance "as is".
:py:class:`Static` provider is base implementation that provides exactly
the same as it got on input.
.. py:attribute:: provides
Value that have to be provided.
:type: object
"""
__slots__ = ('provides',)
def __init__(self, provides):
"""Initializer.
:param provides: Value that have to be provided.
:type provides: object
"""
self.provides = provides
super(Static, self).__init__()
def _provide(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:rtype: object
"""
return self.provides
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self, provides=self.provides)
__repr__ = __str__
StaticProvider = Static
# Backward compatibility for versions < 1.11.1
@six.python_2_unicode_compatible
class ExternalDependency(Provider):
""":py:class:`ExternalDependency` provider describes dependency interface.
This provider is used for description of dependency interface. That might
be useful when dependency could be provided in the client's code only,
but it's interface is known. Such situations could happen when required
dependency has non-determenistic list of dependencies itself.
.. code-block:: python
database_provider = ExternalDependency(sqlite3.dbapi2.Connection)
database_provider.override(Factory(sqlite3.connect, ':memory:'))
database = database_provider()
.. py:attribute:: instance_of
Class of required dependency.
:type: type
"""
__OPTIMIZED_CALLS__ = False
__slots__ = ('instance_of',)
def __init__(self, instance_of):
"""Initializer."""
if not isinstance(instance_of, six.class_types):
raise Error('ExternalDependency provider expects to get class, ' +
'got {0} instead'.format(str(instance_of)))
self.instance_of = instance_of
super(ExternalDependency, self).__init__()
def __call__(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:raise: :py:exc:`dependency_injector.errors.Error`
:rtype: object
"""
if not self.is_overridden:
raise Error('Dependency is not defined')
instance = self.last_overriding(*args, **kwargs)
if not isinstance(instance, self.instance_of):
raise Error('{0} is not an '.format(instance) +
'instance of {0}'.format(self.instance_of))
return instance
def provided_by(self, provider):
"""Set external dependency provider.
:param provider: Provider that provides required dependency.
:type provider: :py:class:`Provider`
:rtype: None
"""
return self.override(provider)
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self, provides=self.instance_of)
__repr__ = __str__
class OverridingContext(object):
"""Provider overriding context.
:py:class:`OverridingContext` is used by :py:meth:`Provider.override` for
implemeting ``with`` contexts. When :py:class:`OverridingContext` is
closed, overriding that was created in this context is dropped also.
.. code-block:: python
with provider.override(another_provider):
assert provider.is_overridden
assert not provider.is_overridden
"""
def __init__(self, overridden, overriding):
"""Initializer.
:param overridden: Overridden provider.
:type overridden: :py:class:`Provider`
:param overriding: Overriding provider.
:type overriding: :py:class:`Provider`
"""
self.overridden = overridden
self.overriding = overriding
def __enter__(self):
"""Do nothing."""
return self.overriding
def __exit__(self, *_):
"""Exit overriding context."""
self.overridden.reset_last_overriding()
def override(overridden):
"""Decorator for overriding providers.
This decorator overrides ``overridden`` provider by decorated one.
.. code-block:: python
@Factory
class SomeClass(object):
pass
@override(SomeClass)
@Factory
class ExtendedSomeClass(SomeClass.cls):
pass
:param overridden: Provider that should be overridden.
:type overridden: :py:class:`Provider`
:return: Overriding provider.
:rtype: :py:class:`Provider`
"""
def decorator(overriding):
overridden.override(overriding)
return overriding
return decorator

View File

@ -0,0 +1,150 @@
"""Dependency injector callable providers."""
import six
from dependency_injector.providers.base import Provider
from dependency_injector.injections import (
_parse_args_injections,
_parse_kwargs_injections,
)
from dependency_injector.utils import represent_provider
from dependency_injector.errors import Error
@six.python_2_unicode_compatible
class Callable(Provider):
""":py:class:`Callable` provider calls wrapped callable on every call.
:py:class:`Callable` provider provides callable that is called on every
provider call with some predefined dependency injections.
:py:class:`Callable` syntax of passing injections is the same like
:py:class:`Factory` one:
.. code-block:: python
# simplified syntax for passing positional and keyword argument
# injections:
some_function = Callable(some_function, 'arg1', 'arg2', arg3=3, arg4=4)
# extended (full) syntax for passing positional and keyword argument
# injections:
some_function = Callable(some_function,
injections.Arg(1),
injections.Arg(2),
injections.KwArg('some_arg', 3),
injections.KwArg('other_arg', 4))
.. py:attribute:: provides
Provided callable.
:type: callable
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
"""
__slots__ = ('provides', 'args', 'kwargs')
def __init__(self, provides, *args, **kwargs):
"""Initializer.
:param provides: Wrapped callable.
:type provides: callable
:param args: Tuple of injections.
:type args: tuple
:param kwargs: Dictionary of injections.
:type kwargs: dict
"""
if not callable(provides):
raise Error('Provider {0} expected to get callable, '
'got {0}'.format('.'.join((self.__class__.__module__,
self.__class__.__name__)),
provides))
self.provides = provides
self.args = _parse_args_injections(args)
self.kwargs = _parse_kwargs_injections(args, kwargs)
super(Callable, self).__init__()
@property
def injections(self):
"""Read-only tuple of all injections.
:rtype: tuple[:py:class:`dependency_injector.injections.Injection`]
"""
return self.args + self.kwargs
def _provide(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:rtype: object
"""
if self.args:
args = tuple(arg.value for arg in self.args) + args
for kwarg in self.kwargs:
if kwarg.name not in kwargs:
kwargs[kwarg.name] = kwarg.value
return self.provides(*args, **kwargs)
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self, provides=self.provides)
__repr__ = __str__
class DelegatedCallable(Callable):
""":py:class:`DelegatedCallable` is a delegated :py:class:`Callable`.
:py:class:`DelegatedCallable` is a :py:class:`Callable`, that is injected
"as is".
.. py:attribute:: provides
Provided callable.
:type: callable
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
"""
__IS_DELEGATED__ = True

View File

@ -0,0 +1,140 @@
"""Dependency injector config providers."""
import six
from dependency_injector.providers.base import Provider
from dependency_injector.errors import Error
from dependency_injector.utils import represent_provider
@six.python_2_unicode_compatible
class Config(Provider):
""":py:class:`Config` provider provide dict values.
:py:class:`Config` provider creates :py:class:`ChildConfig` objects for all
undefined attribute calls. It makes possible to create deferred config
value providers. It might be useful in cases where it is needed to
define / pass some configuration in declarative manner, while
configuration values will be loaded / updated in application's runtime.
"""
__slots__ = ('value',)
def __init__(self, value=None):
"""Initializer.
:param value: Configuration dictionary.
:type value: dict[str, object]
"""
if not value:
value = dict()
self.value = value
super(Config, self).__init__()
def __getattr__(self, item):
"""Return instance of deferred config.
:param item: Name of configuration option or section.
:type item: str
:rtype: :py:class:`ChildConfig`
"""
return ChildConfig(parents=(item,), root_config=self)
def _provide(self, paths=None):
"""Return provided instance.
:param paths: Tuple of pieces of configuration option / section path.
:type args: tuple[str]
:rtype: object
"""
value = self.value
if paths:
for path in paths:
try:
value = value[path]
except KeyError:
raise Error('Config key '
'"{0}" is undefined'.format('.'.join(paths)))
return value
def update_from(self, value):
"""Update current value from another one.
:param value: Configuration dictionary.
:type value: dict[str, object]
:rtype: None
"""
self.value.update(value)
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self, provides=self.value)
__repr__ = __str__
@six.python_2_unicode_compatible
class ChildConfig(Provider):
""":py:class:`ChildConfig` provider provides value from :py:class:`Config`.
:py:class:`ChildConfig` provides value from the root config object
according to the current path in the config tree.
"""
__slots__ = ('parents', 'root_config')
def __init__(self, parents, root_config):
"""Initializer.
:param parents: Tuple of pieces of configuration option / section
parent path.
:type parents: tuple[str]
:param root_config: Root configuration object.
:type root_config: :py:class:`Config`
"""
self.parents = parents
self.root_config = root_config
super(ChildConfig, self).__init__()
def __getattr__(self, item):
"""Return instance of deferred config.
:param item: Name of configuration option or section.
:type item: str
:rtype: :py:class:`ChildConfig`
"""
return ChildConfig(parents=self.parents + (item,),
root_config=self.root_config)
def _provide(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:rtype: object
"""
return self.root_config(self.parents)
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self,
provides='.'.join(self.parents))
__repr__ = __str__

View File

@ -0,0 +1,389 @@
"""Dependency injector creational providers."""
from dependency_injector.providers.callable import Callable
from dependency_injector.utils import (
is_attribute_injection,
is_method_injection,
GLOBAL_LOCK,
)
from dependency_injector.errors import Error
class Factory(Callable):
""":py:class:`Factory` provider creates new instance on every call.
:py:class:`Factory` supports different syntaxes of passing injections:
.. code-block:: python
# simplified syntax for passing positional and keyword argument
# injections only:
factory = Factory(SomeClass, 'arg1', 'arg2', arg3=3, arg4=4)
# extended (full) syntax for passing any type of injections:
factory = Factory(SomeClass,
injections.Arg(1),
injections.Arg(2),
injections.KwArg('some_arg', 3),
injections.KwArg('other_arg', 4),
injections.Attribute('some_attribute', 5))
Retrieving of provided instance can be performed via calling
:py:class:`Factory` object:
.. code-block:: python
factory = Factory(SomeClass,
some_arg1=1,
some_arg2=2)
some_object = factory()
.. py:attribute:: provided_type
If provided type is defined, :py:class:`Factory` checks that
:py:attr:`Factory.provides` is subclass of
:py:attr:`Factory.provided_type`.
:type: type | None
.. py:attribute:: provides
Class or other callable that provides object.
:type: type | callable
.. py:attribute:: cls
Class that provides object.
Alias for :py:attr:`provides`.
:type: type
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
.. py:attribute:: attributes
Tuple of attribute injections.
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
.. py:attribute:: methods
Tuple of method injections.
:type: tuple[:py:class:`dependency_injector.injections.Method`]
"""
provided_type = None
__slots__ = ('cls', 'attributes', 'methods')
def __init__(self, provides, *args, **kwargs):
"""Initializer.
:param provides: Class or other callable that provides object
for creation.
:type provides: type | callable
:param args: Tuple of injections.
:type args: tuple
:param kwargs: Dictionary of injections.
:type kwargs: dict
"""
if (self.__class__.provided_type and
not issubclass(provides, self.__class__.provided_type)):
raise Error('{0} can provide only {1} instances'.format(
self.__class__, self.__class__.provided_type))
self.attributes = tuple(injection
for injection in args
if is_attribute_injection(injection))
self.methods = tuple(injection
for injection in args
if is_method_injection(injection))
super(Factory, self).__init__(provides, *args, **kwargs)
self.cls = self.provides
@property
def injections(self):
"""Read-only tuple of all injections.
:rtype: tuple[:py:class:`dependency_injector.injections.Injection`]
"""
return self.args + self.kwargs + self.attributes + self.methods
def _provide(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:rtype: object
"""
if self.args:
args = tuple(arg.value for arg in self.args) + args
for kwarg in self.kwargs:
if kwarg.name not in kwargs:
kwargs[kwarg.name] = kwarg.value
instance = self.provides(*args, **kwargs)
for attribute in self.attributes:
setattr(instance, attribute.name, attribute.value)
for method in self.methods:
getattr(instance, method.name)(method.value)
return instance
class DelegatedFactory(Factory):
""":py:class:`DelegatedFactory` is a delegated :py:class:`Factory`.
:py:class:`DelegatedFactory` is a :py:class:`Factory`, that is injected
"as is".
.. py:attribute:: provided_type
If provided type is defined, :py:class:`Factory` checks that
:py:attr:`Factory.provides` is subclass of
:py:attr:`Factory.provided_type`.
:type: type | None
.. py:attribute:: provides
Class or other callable that provides object.
:type: type | callable
.. py:attribute:: cls
Class that provides object.
Alias for :py:attr:`provides`.
:type: type
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
.. py:attribute:: attributes
Tuple of attribute injections.
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
.. py:attribute:: methods
Tuple of method injections.
:type: tuple[:py:class:`dependency_injector.injections.Method`]
"""
__IS_DELEGATED__ = True
class Singleton(Factory):
""":py:class:`Singleton` provider returns same instance on every call.
:py:class:`Singleton` provider creates instance once and return it on every
call. :py:class:`Singleton` extends :py:class:`Factory`, so, please follow
:py:class:`Factory` documentation to go inside with injections syntax.
:py:class:`Singleton` is thread-safe and could be used in multithreading
environment without any negative impact.
Retrieving of provided instance can be performed via calling
:py:class:`Singleton` object:
.. code-block:: python
singleton = Singleton(SomeClass,
some_arg1=1,
some_arg2=2)
some_object = singleton()
.. py:attribute:: provided_type
If provided type is defined, :py:class:`Factory` checks that
:py:attr:`Factory.provides` is subclass of
:py:attr:`Factory.provided_type`.
:type: type | None
.. py:attribute:: instance
Read-only reference to singleton's instance.
:type: object
.. py:attribute:: provides
Class or other callable that provides object.
:type: type | callable
.. py:attribute:: cls
Class that provides object.
Alias for :py:attr:`provides`.
:type: type
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
.. py:attribute:: attributes
Tuple of attribute injections.
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
.. py:attribute:: methods
Tuple of method injections.
:type: tuple[:py:class:`dependency_injector.injections.Method`]
"""
__slots__ = ('instance',)
def __init__(self, provides, *args, **kwargs):
"""Initializer.
:param provides: Class or other callable that provides object
for creation.
:type provides: type | callable
:param args: Tuple of injections.
:type args: tuple
:param kwargs: Dictionary of injections.
:type kwargs: dict
"""
self.instance = None
super(Singleton, self).__init__(provides, *args, **kwargs)
def reset(self):
"""Reset cached instance, if any.
:rtype: None
"""
self.instance = None
def _provide(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:rtype: object
"""
if self.instance:
return self.instance
with GLOBAL_LOCK:
self.instance = super(Singleton, self)._provide(*args, **kwargs)
return self.instance
class DelegatedSingleton(Singleton):
""":py:class:`DelegatedSingleton` is a delegated :py:class:`Singleton`.
:py:class:`DelegatedSingleton` is a :py:class:`Singleton`, that is injected
"as is".
.. py:attribute:: provided_type
If provided type is defined, :py:class:`Factory` checks that
:py:attr:`Factory.provides` is subclass of
:py:attr:`Factory.provided_type`.
:type: type | None
.. py:attribute:: instance
Read-only reference to singleton's instance.
:type: object
.. py:attribute:: provides
Class or other callable that provides object.
:type: type | callable
.. py:attribute:: cls
Class that provides object.
Alias for :py:attr:`provides`.
:type: type
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
.. py:attribute:: attributes
Tuple of attribute injections.
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
.. py:attribute:: methods
Tuple of method injections.
:type: tuple[:py:class:`dependency_injector.injections.Method`]
"""
__IS_DELEGATED__ = True

View File

@ -0,0 +1,43 @@
"""Dependency injector static providers."""
from dependency_injector.providers.base import Static
class Class(Static):
""":py:class:`Class` returns provided class "as is".
.. code-block:: python
cls_provider = Class(object)
object_cls = cls_provider()
"""
class Object(Static):
""":py:class:`Object` returns provided object "as is".
.. code-block:: python
object_provider = Object(object())
object_instance = object_provider()
"""
class Function(Static):
""":py:class:`Function` returns provided function "as is".
.. code-block:: python
function_provider = Function(len)
len_function = function_provider()
"""
class Value(Static):
""":py:class:`Value` returns provided value "as is".
.. code-block:: python
value_provider = Value(31337)
value = value_provider()
"""

View File

@ -5,7 +5,7 @@ import threading
import six import six
from .errors import Error from dependency_injector.errors import Error
GLOBAL_LOCK = threading.RLock() GLOBAL_LOCK = threading.RLock()

View File

@ -9,7 +9,8 @@ follows `Semantic versioning`_
Development version Development version
------------------- -------------------
- No features. - [Refactoring] split ``providers`` module into smaller modules,
``providers`` become a package.
1.15.1 1.15.1
------ ------

View File

@ -52,7 +52,8 @@ setup(name='dependency_injector',
bugtrack_url='https://github.com/ets-labs/dependency_injector/issues', bugtrack_url='https://github.com/ets-labs/dependency_injector/issues',
download_url='https://pypi.python.org/pypi/dependency_injector', download_url='https://pypi.python.org/pypi/dependency_injector',
license='BSD New', license='BSD New',
packages=['dependency_injector'], packages=['dependency_injector',
'dependency_injector.providers'],
platforms=['any'], platforms=['any'],
zip_safe=True, zip_safe=True,
install_requires=requirements, install_requires=requirements,

View File

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

View File

@ -0,0 +1,185 @@
"""Dependency injector base providers unittests."""
import unittest2 as unittest
from dependency_injector import providers
from dependency_injector import errors
from dependency_injector import utils
class ProviderTests(unittest.TestCase):
"""Provider test cases."""
def setUp(self):
"""Set test cases environment up."""
self.provider = providers.Provider()
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.provider))
def test_call(self):
"""Test call."""
self.assertRaises(NotImplementedError, self.provider.__call__)
def test_delegate(self):
"""Test creating of provider delegation."""
delegate1 = self.provider.delegate()
self.assertIsInstance(delegate1, providers.Delegate)
self.assertIs(delegate1(), self.provider)
delegate2 = self.provider.delegate()
self.assertIsInstance(delegate2, providers.Delegate)
self.assertIs(delegate2(), self.provider)
self.assertIsNot(delegate1, delegate2)
def test_override(self):
"""Test provider overriding."""
overriding_provider = providers.Provider()
self.provider.override(overriding_provider)
self.assertTrue(self.provider.is_overridden)
def test_overriding_context(self):
"""Test provider overriding context."""
overriding_provider = providers.Provider()
with self.provider.override(overriding_provider):
self.assertTrue(self.provider.is_overridden)
self.assertFalse(self.provider.is_overridden)
def test_override_with_itself(self):
"""Test provider overriding with itself."""
self.assertRaises(errors.Error, self.provider.override, self.provider)
def test_override_with_not_provider(self):
"""Test provider overriding with not provider instance."""
obj = object()
self.provider.override(obj)
self.assertIs(self.provider(), obj)
def test_last_overriding(self):
"""Test getting last overriding provider."""
overriding_provider1 = providers.Provider()
overriding_provider2 = providers.Provider()
self.provider.override(overriding_provider1)
self.assertIs(self.provider.last_overriding, overriding_provider1)
self.provider.override(overriding_provider2)
self.assertIs(self.provider.last_overriding, overriding_provider2)
def test_last_overriding_of_not_overridden_provider(self):
"""Test getting last overriding from not overridden provider."""
self.assertIsNone(self.provider.last_overriding)
def test_reset_last_overriding(self):
"""Test reseting of last overriding provider."""
overriding_provider1 = providers.Provider()
overriding_provider2 = providers.Provider()
self.provider.override(overriding_provider1)
self.provider.override(overriding_provider2)
self.assertIs(self.provider.last_overriding, overriding_provider2)
self.provider.reset_last_overriding()
self.assertIs(self.provider.last_overriding, overriding_provider1)
self.provider.reset_last_overriding()
self.assertFalse(self.provider.is_overridden)
def test_reset_last_overriding_of_not_overridden_provider(self):
"""Test resetting of last overriding on not overridden provier."""
self.assertRaises(errors.Error, self.provider.reset_last_overriding)
def test_reset_override(self):
"""Test reset of provider's override."""
overriding_provider = providers.Provider()
self.provider.override(overriding_provider)
self.assertTrue(self.provider.is_overridden)
self.assertIs(self.provider.last_overriding, overriding_provider)
self.provider.reset_override()
self.assertFalse(self.provider.is_overridden)
self.assertIsNone(self.provider.last_overriding)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.provider),
'<dependency_injector.providers.base.'
'Provider() at {0}>'.format(hex(id(self.provider))))
class DelegateTests(unittest.TestCase):
"""Delegate test cases."""
def setUp(self):
"""Set test cases environment up."""
self.delegated = providers.Provider()
self.delegate = providers.Delegate(delegated=self.delegated)
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.delegate))
def test_init_with_not_provider(self):
"""Test that delegate accepts only another provider as delegated."""
self.assertRaises(errors.Error, providers.Delegate, delegated=object())
def test_call(self):
"""Test returning of delegated provider."""
delegated1 = self.delegate()
delegated2 = self.delegate()
self.assertIs(delegated1, self.delegated)
self.assertIs(delegated2, self.delegated)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.delegate),
'<dependency_injector.providers.base.'
'Delegate({0}) at {1}>'.format(
repr(self.delegated),
hex(id(self.delegate))))
class ExternalDependencyTests(unittest.TestCase):
"""ExternalDependency test cases."""
def setUp(self):
"""Set test cases environment up."""
self.provider = providers.ExternalDependency(instance_of=list)
def test_init_with_not_class(self):
"""Test creation with not a class."""
self.assertRaises(errors.Error, providers.ExternalDependency, object())
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.provider))
def test_call_overridden(self):
"""Test call of overridden external dependency."""
self.provider.provided_by(providers.Factory(list))
self.assertIsInstance(self.provider(), list)
def test_call_overridden_but_not_instance_of(self):
"""Test call of overridden external dependency, but not instance of."""
self.provider.provided_by(providers.Factory(dict))
self.assertRaises(errors.Error, self.provider)
def test_call_not_overridden(self):
"""Test call of not satisfied external dependency."""
self.assertRaises(errors.Error, self.provider)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.provider),
'<dependency_injector.providers.base.'
'ExternalDependency({0}) at {1}>'.format(
repr(list),
hex(id(self.provider))))

View File

@ -0,0 +1,138 @@
"""Dependency injector callable providers unittests."""
import unittest2 as unittest
from dependency_injector import providers
from dependency_injector import injections
from dependency_injector import utils
from dependency_injector import errors
class CallableTests(unittest.TestCase):
"""Callable test cases."""
def example(self, arg1, arg2, arg3, arg4):
"""Example callback."""
return arg1, arg2, arg3, arg4
def test_init_with_callable(self):
"""Test creation of provider with a callable."""
self.assertTrue(providers.Callable(self.example))
def test_init_with_not_callable(self):
"""Test creation of provider with not a callable."""
self.assertRaises(errors.Error, providers.Callable, 123)
def test_call(self):
"""Test call."""
provider = providers.Callable(lambda: True)
self.assertTrue(provider())
def test_call_with_positional_args(self):
"""Test call with positional args.
New simplified syntax.
"""
provider = providers.Callable(self.example, 1, 2, 3, 4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_keyword_args(self):
"""Test call with keyword args.
New simplified syntax.
"""
provider = providers.Callable(self.example,
arg1=1,
arg2=2,
arg3=3,
arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args(self):
"""Test call with positional and keyword args.
Simplified syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args_extended_syntax(self):
"""Test call with positional and keyword args.
Extended syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example,
injections.Arg(1),
injections.Arg(2),
injections.KwArg('arg3', 3),
injections.KwArg('arg4', 4))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_context_args(self):
"""Test call with context args."""
provider = providers.Callable(self.example, 1, 2)
self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4))
def test_call_with_context_kwargs(self):
"""Test call with context kwargs."""
provider = providers.Callable(self.example,
injections.KwArg('arg1', 1))
self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_with_context_args_and_kwargs(self):
"""Test call with context args and kwargs."""
provider = providers.Callable(self.example, 1)
self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_overridden(self):
"""Test creation of new instances on overridden provider."""
provider = providers.Callable(self.example)
provider.override(providers.Value((4, 3, 2, 1)))
provider.override(providers.Value((1, 2, 3, 4)))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_injections(self):
"""Test getting a full list of injections using injections property."""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertEquals(len(provider.injections), 4)
def test_repr(self):
"""Test representation of provider."""
provider = providers.Callable(self.example,
injections.KwArg(
'arg1',
providers.Factory(dict)),
injections.KwArg(
'arg2',
providers.Factory(list)),
injections.KwArg(
'arg3',
providers.Factory(set)),
injections.KwArg(
'arg4',
providers.Factory(tuple)))
self.assertEqual(repr(provider),
'<dependency_injector.providers.callable.'
'Callable({0}) at {1}>'.format(
repr(self.example),
hex(id(provider))))
class DelegatedCallableTests(unittest.TestCase):
"""DelegatedCallable test cases."""
def test_inheritance(self):
"""Test inheritance."""
self.assertIsInstance(providers.DelegatedCallable(len),
providers.Callable)
def test_is_provider(self):
"""Test is_provider."""
self.assertTrue(utils.is_provider(providers.DelegatedCallable(len)))
def test_is_delegated_provider(self):
"""Test is_delegated_provider."""
self.assertTrue(utils.is_delegated_provider(
providers.DelegatedCallable(len)))
self.assertFalse(utils.is_delegated_provider(providers.Callable(len)))

View File

@ -0,0 +1,85 @@
"""Dependency injector config providers unittests."""
import unittest2 as unittest
from dependency_injector import providers
from dependency_injector import utils
from dependency_injector import errors
class ConfigTests(unittest.TestCase):
"""Config test cases."""
def setUp(self):
"""Set test cases environment up."""
self.initial_data = dict(key='value',
category=dict(setting='setting_value'))
self.provider = providers.Config(self.initial_data)
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.provider))
def test_init_without_initial_value(self):
"""Test provider's creation with no initial value."""
self.assertEqual(providers.Config()(), dict())
def test_call(self):
"""Test returning of config value."""
self.assertEqual(self.provider(), self.initial_data)
def test_update_from(self):
"""Test update of config value."""
self.assertEqual(self.provider(), self.initial_data)
self.initial_data['key'] = 'other_value'
self.provider.update_from(self.initial_data)
self.assertEqual(self.provider(), self.initial_data)
def test_call_child(self):
"""Test returning of child config values."""
category = self.provider.category
category_setting = self.provider.category.setting
self.assertTrue(utils.is_provider(category))
self.assertTrue(utils.is_provider(category_setting))
self.assertEqual(category(), self.initial_data['category'])
self.assertEqual(category_setting(),
self.initial_data['category']['setting'])
def test_call_deferred_child_and_update_from(self):
"""Test returning of deferred child config values."""
self.provider = providers.Config()
category = self.provider.category
category_setting = self.provider.category.setting
self.assertTrue(utils.is_provider(category))
self.assertTrue(utils.is_provider(category_setting))
self.provider.update_from(self.initial_data)
self.assertEqual(category(), self.initial_data['category'])
self.assertEqual(category_setting(),
self.initial_data['category']['setting'])
def test_call_deferred_child_with_empty_value(self):
"""Test returning of deferred child config values."""
self.provider = providers.Config()
category_setting = self.provider.category.setting
self.assertRaises(errors.Error, category_setting)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.provider),
'<dependency_injector.providers.config.'
'Config({0}) at {1}>'.format(
repr(self.initial_data),
hex(id(self.provider))))
category_setting = self.provider.category.setting
self.assertEqual(repr(category_setting),
'<dependency_injector.providers.config.'
'ChildConfig({0}) at {1}>'.format(
repr('.'.join(('category', 'setting'))),
hex(id(category_setting))))

View File

@ -1,11 +1,11 @@
"""Dependency injector providers unittests.""" """Dependency injector creational providers unittests."""
import unittest2 as unittest import unittest2 as unittest
from dependency_injector import providers from dependency_injector import providers
from dependency_injector import injections from dependency_injector import injections
from dependency_injector import errors
from dependency_injector import utils from dependency_injector import utils
from dependency_injector import errors
class Example(object): class Example(object):
@ -34,276 +34,6 @@ class Example(object):
self.method2_value = value self.method2_value = value
class ProviderTests(unittest.TestCase):
"""Provider test cases."""
def setUp(self):
"""Set test cases environment up."""
self.provider = providers.Provider()
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.provider))
def test_call(self):
"""Test call."""
self.assertRaises(NotImplementedError, self.provider.__call__)
def test_delegate(self):
"""Test creating of provider delegation."""
delegate1 = self.provider.delegate()
self.assertIsInstance(delegate1, providers.Delegate)
self.assertIs(delegate1(), self.provider)
delegate2 = self.provider.delegate()
self.assertIsInstance(delegate2, providers.Delegate)
self.assertIs(delegate2(), self.provider)
self.assertIsNot(delegate1, delegate2)
def test_override(self):
"""Test provider overriding."""
overriding_provider = providers.Provider()
self.provider.override(overriding_provider)
self.assertTrue(self.provider.is_overridden)
def test_overriding_context(self):
"""Test provider overriding context."""
overriding_provider = providers.Provider()
with self.provider.override(overriding_provider):
self.assertTrue(self.provider.is_overridden)
self.assertFalse(self.provider.is_overridden)
def test_override_with_itself(self):
"""Test provider overriding with itself."""
self.assertRaises(errors.Error, self.provider.override, self.provider)
def test_override_with_not_provider(self):
"""Test provider overriding with not provider instance."""
obj = object()
self.provider.override(obj)
self.assertIs(self.provider(), obj)
def test_last_overriding(self):
"""Test getting last overriding provider."""
overriding_provider1 = providers.Provider()
overriding_provider2 = providers.Provider()
self.provider.override(overriding_provider1)
self.assertIs(self.provider.last_overriding, overriding_provider1)
self.provider.override(overriding_provider2)
self.assertIs(self.provider.last_overriding, overriding_provider2)
def test_last_overriding_of_not_overridden_provider(self):
"""Test getting last overriding from not overridden provider."""
self.assertIsNone(self.provider.last_overriding)
def test_reset_last_overriding(self):
"""Test reseting of last overriding provider."""
overriding_provider1 = providers.Provider()
overriding_provider2 = providers.Provider()
self.provider.override(overriding_provider1)
self.provider.override(overriding_provider2)
self.assertIs(self.provider.last_overriding, overriding_provider2)
self.provider.reset_last_overriding()
self.assertIs(self.provider.last_overriding, overriding_provider1)
self.provider.reset_last_overriding()
self.assertFalse(self.provider.is_overridden)
def test_reset_last_overriding_of_not_overridden_provider(self):
"""Test resetting of last overriding on not overridden provier."""
self.assertRaises(errors.Error, self.provider.reset_last_overriding)
def test_reset_override(self):
"""Test reset of provider's override."""
overriding_provider = providers.Provider()
self.provider.override(overriding_provider)
self.assertTrue(self.provider.is_overridden)
self.assertIs(self.provider.last_overriding, overriding_provider)
self.provider.reset_override()
self.assertFalse(self.provider.is_overridden)
self.assertIsNone(self.provider.last_overriding)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.provider),
'<dependency_injector.providers.'
'Provider() at {0}>'.format(hex(id(self.provider))))
class DelegateTests(unittest.TestCase):
"""Delegate test cases."""
def setUp(self):
"""Set test cases environment up."""
self.delegated = providers.Provider()
self.delegate = providers.Delegate(delegated=self.delegated)
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.delegate))
def test_init_with_not_provider(self):
"""Test that delegate accepts only another provider as delegated."""
self.assertRaises(errors.Error, providers.Delegate, delegated=object())
def test_call(self):
"""Test returning of delegated provider."""
delegated1 = self.delegate()
delegated2 = self.delegate()
self.assertIs(delegated1, self.delegated)
self.assertIs(delegated2, self.delegated)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.delegate),
'<dependency_injector.providers.'
'Delegate({0}) at {1}>'.format(
repr(self.delegated),
hex(id(self.delegate))))
class CallableTests(unittest.TestCase):
"""Callable test cases."""
def example(self, arg1, arg2, arg3, arg4):
"""Example callback."""
return arg1, arg2, arg3, arg4
def test_init_with_callable(self):
"""Test creation of provider with a callable."""
self.assertTrue(providers.Callable(self.example))
def test_init_with_not_callable(self):
"""Test creation of provider with not a callable."""
self.assertRaises(errors.Error, providers.Callable, 123)
def test_call(self):
"""Test call."""
provider = providers.Callable(lambda: True)
self.assertTrue(provider())
def test_call_with_positional_args(self):
"""Test call with positional args.
New simplified syntax.
"""
provider = providers.Callable(self.example, 1, 2, 3, 4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_keyword_args(self):
"""Test call with keyword args.
New simplified syntax.
"""
provider = providers.Callable(self.example,
arg1=1,
arg2=2,
arg3=3,
arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args(self):
"""Test call with positional and keyword args.
Simplified syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args_extended_syntax(self):
"""Test call with positional and keyword args.
Extended syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example,
injections.Arg(1),
injections.Arg(2),
injections.KwArg('arg3', 3),
injections.KwArg('arg4', 4))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_context_args(self):
"""Test call with context args."""
provider = providers.Callable(self.example, 1, 2)
self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4))
def test_call_with_context_kwargs(self):
"""Test call with context kwargs."""
provider = providers.Callable(self.example,
injections.KwArg('arg1', 1))
self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_with_context_args_and_kwargs(self):
"""Test call with context args and kwargs."""
provider = providers.Callable(self.example, 1)
self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_overridden(self):
"""Test creation of new instances on overridden provider."""
provider = providers.Callable(self.example)
provider.override(providers.Value((4, 3, 2, 1)))
provider.override(providers.Value((1, 2, 3, 4)))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_injections(self):
"""Test getting a full list of injections using injections property."""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertEquals(len(provider.injections), 4)
def test_repr(self):
"""Test representation of provider."""
provider = providers.Callable(self.example,
injections.KwArg(
'arg1',
providers.Factory(dict)),
injections.KwArg(
'arg2',
providers.Factory(list)),
injections.KwArg(
'arg3',
providers.Factory(set)),
injections.KwArg(
'arg4',
providers.Factory(tuple)))
self.assertEqual(repr(provider),
'<dependency_injector.providers.'
'Callable({0}) at {1}>'.format(
repr(self.example),
hex(id(provider))))
class DelegatedCallableTests(unittest.TestCase):
"""DelegatedCallable test cases."""
def test_inheritance(self):
"""Test inheritance."""
self.assertIsInstance(providers.DelegatedCallable(len),
providers.Callable)
def test_is_provider(self):
"""Test is_provider."""
self.assertTrue(utils.is_provider(providers.DelegatedCallable(len)))
def test_is_delegated_provider(self):
"""Test is_delegated_provider."""
self.assertTrue(utils.is_delegated_provider(
providers.DelegatedCallable(len)))
self.assertFalse(utils.is_delegated_provider(providers.Callable(len)))
class FactoryTests(unittest.TestCase): class FactoryTests(unittest.TestCase):
"""Factory test cases.""" """Factory test cases."""
@ -552,7 +282,7 @@ class FactoryTests(unittest.TestCase):
injections.KwArg('init_arg2', injections.KwArg('init_arg2',
providers.Factory(list))) providers.Factory(list)))
self.assertEqual(repr(provider), self.assertEqual(repr(provider),
'<dependency_injector.providers.' '<dependency_injector.providers.creational.'
'Factory({0}) at {1}>'.format( 'Factory({0}) at {1}>'.format(
repr(Example), repr(Example),
hex(id(provider)))) hex(id(provider))))
@ -872,7 +602,7 @@ class SingletonTests(unittest.TestCase):
'init_arg2', 'init_arg2',
providers.Factory(list))) providers.Factory(list)))
self.assertEqual(repr(provider), self.assertEqual(repr(provider),
'<dependency_injector.providers.' '<dependency_injector.providers.creational.'
'Singleton({0}) at {1}>'.format( 'Singleton({0}) at {1}>'.format(
repr(Example), repr(Example),
hex(id(provider)))) hex(id(provider))))
@ -899,207 +629,6 @@ class DelegatedSingletonTests(unittest.TestCase):
providers.Singleton(object))) providers.Singleton(object)))
class ExternalDependencyTests(unittest.TestCase):
"""ExternalDependency test cases."""
def setUp(self):
"""Set test cases environment up."""
self.provider = providers.ExternalDependency(instance_of=list)
def test_init_with_not_class(self):
"""Test creation with not a class."""
self.assertRaises(errors.Error, providers.ExternalDependency, object())
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.provider))
def test_call_overridden(self):
"""Test call of overridden external dependency."""
self.provider.provided_by(providers.Factory(list))
self.assertIsInstance(self.provider(), list)
def test_call_overridden_but_not_instance_of(self):
"""Test call of overridden external dependency, but not instance of."""
self.provider.provided_by(providers.Factory(dict))
self.assertRaises(errors.Error, self.provider)
def test_call_not_overridden(self):
"""Test call of not satisfied external dependency."""
self.assertRaises(errors.Error, self.provider)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.provider),
'<dependency_injector.providers.'
'ExternalDependency({0}) at {1}>'.format(
repr(list),
hex(id(self.provider))))
class StaticProvidersTests(unittest.TestCase):
"""Static providers test cases."""
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(providers.Class(object)))
self.assertTrue(utils.is_provider(providers.Object(object())))
self.assertTrue(utils.is_provider(providers.Function(map)))
self.assertTrue(utils.is_provider(providers.Value(123)))
def test_call_class_provider(self):
"""Test Class provider call."""
self.assertIs(providers.Class(dict)(), dict)
def test_call_object_provider(self):
"""Test Object provider call."""
obj = object()
self.assertIs(providers.Object(obj)(), obj)
def test_call_function_provider(self):
"""Test Function provider call."""
self.assertIs(providers.Function(map)(), map)
def test_call_value_provider(self):
"""Test Value provider call."""
self.assertEqual(providers.Value(123)(), 123)
def test_call_overridden_class_provider(self):
"""Test overridden Class provider call."""
cls_provider = providers.Class(dict)
cls_provider.override(providers.Object(list))
self.assertIs(cls_provider(), list)
def test_call_overridden_object_provider(self):
"""Test overridden Object provider call."""
obj1 = object()
obj2 = object()
obj_provider = providers.Object(obj1)
obj_provider.override(providers.Object(obj2))
self.assertIs(obj_provider(), obj2)
def test_call_overridden_function_provider(self):
"""Test overridden Function provider call."""
function_provider = providers.Function(len)
function_provider.override(providers.Function(sum))
self.assertIs(function_provider(), sum)
def test_call_overridden_value_provider(self):
"""Test overridden Value provider call."""
value_provider = providers.Value(123)
value_provider.override(providers.Value(321))
self.assertEqual(value_provider(), 321)
def test_repr(self):
"""Test representation of provider."""
class_provider = providers.Class(object)
self.assertEqual(repr(class_provider),
'<dependency_injector.providers.'
'Class({0}) at {1}>'.format(
repr(object),
hex(id(class_provider))))
some_object = object()
object_provider = providers.Object(some_object)
self.assertEqual(repr(object_provider),
'<dependency_injector.providers.'
'Object({0}) at {1}>'.format(
repr(some_object),
hex(id(object_provider))))
function_provider = providers.Function(map)
self.assertEqual(repr(function_provider),
'<dependency_injector.providers.'
'Function({0}) at {1}>'.format(
repr(map),
hex(id(function_provider))))
value_provider = providers.Value(123)
self.assertEqual(repr(value_provider),
'<dependency_injector.providers.'
'Value({0}) at {1}>'.format(
repr(123),
hex(id(value_provider))))
class ConfigTests(unittest.TestCase):
"""Config test cases."""
def setUp(self):
"""Set test cases environment up."""
self.initial_data = dict(key='value',
category=dict(setting='setting_value'))
self.provider = providers.Config(self.initial_data)
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(self.provider))
def test_init_without_initial_value(self):
"""Test provider's creation with no initial value."""
self.assertEqual(providers.Config()(), dict())
def test_call(self):
"""Test returning of config value."""
self.assertEqual(self.provider(), self.initial_data)
def test_update_from(self):
"""Test update of config value."""
self.assertEqual(self.provider(), self.initial_data)
self.initial_data['key'] = 'other_value'
self.provider.update_from(self.initial_data)
self.assertEqual(self.provider(), self.initial_data)
def test_call_child(self):
"""Test returning of child config values."""
category = self.provider.category
category_setting = self.provider.category.setting
self.assertTrue(utils.is_provider(category))
self.assertTrue(utils.is_provider(category_setting))
self.assertEqual(category(), self.initial_data['category'])
self.assertEqual(category_setting(),
self.initial_data['category']['setting'])
def test_call_deferred_child_and_update_from(self):
"""Test returning of deferred child config values."""
self.provider = providers.Config()
category = self.provider.category
category_setting = self.provider.category.setting
self.assertTrue(utils.is_provider(category))
self.assertTrue(utils.is_provider(category_setting))
self.provider.update_from(self.initial_data)
self.assertEqual(category(), self.initial_data['category'])
self.assertEqual(category_setting(),
self.initial_data['category']['setting'])
def test_call_deferred_child_with_empty_value(self):
"""Test returning of deferred child config values."""
self.provider = providers.Config()
category_setting = self.provider.category.setting
self.assertRaises(errors.Error, category_setting)
def test_repr(self):
"""Test representation of provider."""
self.assertEqual(repr(self.provider),
'<dependency_injector.providers.'
'Config({0}) at {1}>'.format(
repr(self.initial_data),
hex(id(self.provider))))
category_setting = self.provider.category.setting
self.assertEqual(repr(category_setting),
'<dependency_injector.providers.'
'ChildConfig({0}) at {1}>'.format(
repr('.'.join(('category', 'setting'))),
hex(id(category_setting))))
class FactoryAsDecoratorTests(unittest.TestCase): class FactoryAsDecoratorTests(unittest.TestCase):
"""Factory as decorator tests.""" """Factory as decorator tests."""

View File

@ -0,0 +1,91 @@
"""Dependency injector static providers unittests."""
import unittest2 as unittest
from dependency_injector import providers
from dependency_injector import utils
class StaticProvidersTests(unittest.TestCase):
"""Static providers test cases."""
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(utils.is_provider(providers.Class(object)))
self.assertTrue(utils.is_provider(providers.Object(object())))
self.assertTrue(utils.is_provider(providers.Function(map)))
self.assertTrue(utils.is_provider(providers.Value(123)))
def test_call_class_provider(self):
"""Test Class provider call."""
self.assertIs(providers.Class(dict)(), dict)
def test_call_object_provider(self):
"""Test Object provider call."""
obj = object()
self.assertIs(providers.Object(obj)(), obj)
def test_call_function_provider(self):
"""Test Function provider call."""
self.assertIs(providers.Function(map)(), map)
def test_call_value_provider(self):
"""Test Value provider call."""
self.assertEqual(providers.Value(123)(), 123)
def test_call_overridden_class_provider(self):
"""Test overridden Class provider call."""
cls_provider = providers.Class(dict)
cls_provider.override(providers.Object(list))
self.assertIs(cls_provider(), list)
def test_call_overridden_object_provider(self):
"""Test overridden Object provider call."""
obj1 = object()
obj2 = object()
obj_provider = providers.Object(obj1)
obj_provider.override(providers.Object(obj2))
self.assertIs(obj_provider(), obj2)
def test_call_overridden_function_provider(self):
"""Test overridden Function provider call."""
function_provider = providers.Function(len)
function_provider.override(providers.Function(sum))
self.assertIs(function_provider(), sum)
def test_call_overridden_value_provider(self):
"""Test overridden Value provider call."""
value_provider = providers.Value(123)
value_provider.override(providers.Value(321))
self.assertEqual(value_provider(), 321)
def test_repr(self):
"""Test representation of provider."""
class_provider = providers.Class(object)
self.assertEqual(repr(class_provider),
'<dependency_injector.providers.static.'
'Class({0}) at {1}>'.format(
repr(object),
hex(id(class_provider))))
some_object = object()
object_provider = providers.Object(some_object)
self.assertEqual(repr(object_provider),
'<dependency_injector.providers.static.'
'Object({0}) at {1}>'.format(
repr(some_object),
hex(id(object_provider))))
function_provider = providers.Function(map)
self.assertEqual(repr(function_provider),
'<dependency_injector.providers.static.'
'Function({0}) at {1}>'.format(
repr(map),
hex(id(function_provider))))
value_provider = providers.Value(123)
self.assertEqual(repr(value_provider),
'<dependency_injector.providers.static.'
'Value({0}) at {1}>'.format(
repr(123),
hex(id(value_provider))))