mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 11:04:01 +03:00
Make providers stable
This commit is contained in:
parent
322ba98f18
commit
7b61464c93
4
setup.py
4
setup.py
|
@ -63,10 +63,6 @@ setup(name='dependency-injector',
|
||||||
['src/dependency_injector/providers/singletons.c'],
|
['src/dependency_injector/providers/singletons.c'],
|
||||||
define_macros=defined_macros,
|
define_macros=defined_macros,
|
||||||
extra_compile_args=['-O2']),
|
extra_compile_args=['-O2']),
|
||||||
Extension('dependency_injector.providers.static',
|
|
||||||
['src/dependency_injector/providers/static.c'],
|
|
||||||
define_macros=defined_macros,
|
|
||||||
extra_compile_args=['-O2']),
|
|
||||||
Extension('dependency_injector.providers.injections',
|
Extension('dependency_injector.providers.injections',
|
||||||
['src/dependency_injector/providers/injections.c'],
|
['src/dependency_injector/providers/injections.c'],
|
||||||
define_macros=defined_macros,
|
define_macros=defined_macros,
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
"""Dependency injector container utils."""
|
"""Dependency injector container utils."""
|
||||||
|
|
||||||
import copy as _copy
|
|
||||||
import types
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from dependency_injector.providers import deepcopy
|
||||||
from dependency_injector.errors import Error
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
|
|
||||||
if six.PY2: # pragma: no cover
|
|
||||||
_copy._deepcopy_dispatch[types.MethodType] = \
|
|
||||||
lambda obj, memo: type(obj)(obj.im_func,
|
|
||||||
_copy.deepcopy(obj.im_self, memo),
|
|
||||||
obj.im_class)
|
|
||||||
|
|
||||||
|
|
||||||
def is_container(instance):
|
def is_container(instance):
|
||||||
"""Check if instance is container instance.
|
"""Check if instance is container instance.
|
||||||
|
|
||||||
|
@ -74,11 +66,6 @@ def copy(container):
|
||||||
return _decorator
|
return _decorator
|
||||||
|
|
||||||
|
|
||||||
def deepcopy(instance, memo=None):
|
|
||||||
"""Make full copy of instance."""
|
|
||||||
return _copy.deepcopy(instance, memo)
|
|
||||||
|
|
||||||
|
|
||||||
def _check_provider_type(cls, provider):
|
def _check_provider_type(cls, provider):
|
||||||
if not isinstance(provider, cls.provider_type):
|
if not isinstance(provider, cls.provider_type):
|
||||||
raise Error('{0} can contain only {1} '
|
raise Error('{0} can contain only {1} '
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
Provider,
|
Provider,
|
||||||
|
Object,
|
||||||
|
Delegate,
|
||||||
|
ExternalDependency,
|
||||||
|
OverridingContext,
|
||||||
)
|
)
|
||||||
from .callables import (
|
from .callables import (
|
||||||
Callable,
|
Callable,
|
||||||
|
@ -23,27 +27,26 @@ from .singletons import (
|
||||||
ThreadLocalSingleton,
|
ThreadLocalSingleton,
|
||||||
DelegatedThreadLocalSingleton,
|
DelegatedThreadLocalSingleton,
|
||||||
)
|
)
|
||||||
from .static import (
|
|
||||||
Object,
|
|
||||||
Delegate,
|
|
||||||
ExternalDependency,
|
|
||||||
)
|
|
||||||
from .injections import (
|
from .injections import (
|
||||||
Injection,
|
Injection,
|
||||||
PositionalInjection,
|
PositionalInjection,
|
||||||
NamedInjection,
|
NamedInjection,
|
||||||
)
|
)
|
||||||
from .utils import (
|
from .utils import (
|
||||||
OverridingContext,
|
|
||||||
is_provider,
|
is_provider,
|
||||||
ensure_is_provider,
|
ensure_is_provider,
|
||||||
is_delegated,
|
is_delegated,
|
||||||
represent_provider,
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Provider',
|
'Provider',
|
||||||
|
'Object',
|
||||||
|
'Delegate',
|
||||||
|
'ExternalDependency',
|
||||||
|
'OverridingContext',
|
||||||
|
|
||||||
'Callable',
|
'Callable',
|
||||||
'DelegatedCallable',
|
'DelegatedCallable',
|
||||||
|
@ -62,17 +65,13 @@ __all__ = (
|
||||||
'ThreadLocalSingleton',
|
'ThreadLocalSingleton',
|
||||||
'DelegatedThreadLocalSingleton',
|
'DelegatedThreadLocalSingleton',
|
||||||
|
|
||||||
'Object',
|
|
||||||
'Delegate',
|
|
||||||
'ExternalDependency',
|
|
||||||
|
|
||||||
'Injection',
|
'Injection',
|
||||||
'PositionalInjection',
|
'PositionalInjection',
|
||||||
'NamedInjection',
|
'NamedInjection',
|
||||||
|
|
||||||
'OverridingContext',
|
|
||||||
'is_provider',
|
'is_provider',
|
||||||
'ensure_is_provider',
|
'ensure_is_provider',
|
||||||
'is_delegated',
|
'is_delegated',
|
||||||
'represent_provider',
|
'represent_provider',
|
||||||
|
'deepcopy',
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,3 +10,22 @@ cdef class Provider(object):
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
cpdef object _call_last_overriding(self, tuple args, dict kwargs)
|
cpdef object _call_last_overriding(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Object(Provider):
|
||||||
|
cdef object __provides
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Delegate(Object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ExternalDependency(Provider):
|
||||||
|
cdef type __instance_of
|
||||||
|
|
||||||
|
|
||||||
|
cdef class OverridingContext(object):
|
||||||
|
cdef Provider __overridden
|
||||||
|
cdef Provider __overriding
|
||||||
|
|
|
@ -7,15 +7,12 @@ cimport cython
|
||||||
|
|
||||||
from dependency_injector.errors import Error
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
from .static cimport (
|
|
||||||
Object,
|
|
||||||
Delegate,
|
|
||||||
)
|
|
||||||
from .utils cimport (
|
from .utils cimport (
|
||||||
|
CLASS_TYPES,
|
||||||
is_provider,
|
is_provider,
|
||||||
ensure_is_provider,
|
ensure_is_provider,
|
||||||
represent_provider,
|
represent_provider,
|
||||||
OverridingContext,
|
deepcopy,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,6 +80,19 @@ cdef class Provider(object):
|
||||||
return self._call_last_overriding(args, kwargs)
|
return self._call_last_overriding(args, kwargs)
|
||||||
return self._provide(args, kwargs)
|
return self._provide(args, kwargs)
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
copied = self.__class__()
|
||||||
|
|
||||||
|
for overriding_provider in self.overridden:
|
||||||
|
copied.override(deepcopy(overriding_provider, memo))
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return string representation of provider.
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
@ -173,3 +183,214 @@ cdef class Provider(object):
|
||||||
return None
|
return None
|
||||||
return <object>self.__overridden[self.__overridden_len - 1](*args,
|
return <object>self.__overridden[self.__overridden_len - 1](*args,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Object(Provider):
|
||||||
|
"""Object provider returns provided instance "as is".
|
||||||
|
|
||||||
|
.. py:attribute:: provides
|
||||||
|
|
||||||
|
Value that have to be provided.
|
||||||
|
|
||||||
|
:type: object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, provides):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Value that have to be provided.
|
||||||
|
:type provides: object
|
||||||
|
"""
|
||||||
|
self.__provides = provides
|
||||||
|
super(Object, self).__init__()
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
copied = self.__class__(deepcopy(self.__provides, memo))
|
||||||
|
|
||||||
|
for overriding_provider in self.overridden:
|
||||||
|
copied.override(deepcopy(overriding_provider, memo))
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return represent_provider(provider=self, provides=self.__provides)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict 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
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Delegate(Object):
|
||||||
|
"""Delegate provider returns provider "as is".
|
||||||
|
|
||||||
|
.. py:attribute:: provides
|
||||||
|
|
||||||
|
Value that have to be provided.
|
||||||
|
|
||||||
|
:type: object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, provides):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Value that have to be provided.
|
||||||
|
:type provides: object
|
||||||
|
"""
|
||||||
|
super(Delegate, self).__init__(ensure_is_provider(provides))
|
||||||
|
|
||||||
|
|
||||||
|
cdef 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
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, type instance_of):
|
||||||
|
"""Initializer."""
|
||||||
|
self.__instance_of = instance_of
|
||||||
|
super(ExternalDependency, self).__init__()
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
copied = self.__class__(self.__instance_of)
|
||||||
|
|
||||||
|
for overriding_provider in self.overridden:
|
||||||
|
copied.override(deepcopy(overriding_provider, memo))
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
cdef object instance
|
||||||
|
|
||||||
|
if self.__overridden_len == 0:
|
||||||
|
raise Error('Dependency is not defined')
|
||||||
|
|
||||||
|
instance = self._call_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 __str__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return represent_provider(provider=self, provides=self.__instance_of)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def instance_of(self):
|
||||||
|
"""Return class of required dependency."""
|
||||||
|
return self.__instance_of
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
cdef 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.overridden
|
||||||
|
assert not provider.overridden
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, Provider overridden, Provider 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
|
||||||
|
super(OverridingContext, self).__init__()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
"""Do nothing."""
|
||||||
|
return self.__overriding
|
||||||
|
|
||||||
|
def __exit__(self, *_):
|
||||||
|
"""Exit overriding context."""
|
||||||
|
self.__overridden.reset_last_overriding()
|
||||||
|
|
|
@ -12,7 +12,10 @@ from .injections cimport (
|
||||||
parse_positional_injections,
|
parse_positional_injections,
|
||||||
parse_named_injections,
|
parse_named_injections,
|
||||||
)
|
)
|
||||||
from .utils cimport represent_provider
|
from .utils cimport (
|
||||||
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
cdef class Callable(Provider):
|
cdef class Callable(Provider):
|
||||||
|
@ -68,6 +71,21 @@ cdef class Callable(Provider):
|
||||||
|
|
||||||
super(Callable, self).__init__()
|
super(Callable, self).__init__()
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
copied = self.__class__(self.__provies,
|
||||||
|
*deepcopy(self.args, memo),
|
||||||
|
**deepcopy(self.kwargs, memo))
|
||||||
|
|
||||||
|
for overriding_provider in self.overridden:
|
||||||
|
copied.override(deepcopy(overriding_provider, memo))
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return string representation of provider.
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
@ -132,13 +150,13 @@ cdef class Callable(Provider):
|
||||||
def kwargs(self):
|
def kwargs(self):
|
||||||
"""Return keyword argument injections."""
|
"""Return keyword argument injections."""
|
||||||
cdef int index
|
cdef int index
|
||||||
cdef NamedInjection arg
|
cdef NamedInjection kwarg
|
||||||
cdef dict kwargs
|
cdef dict kwargs
|
||||||
|
|
||||||
kwargs = dict()
|
kwargs = dict()
|
||||||
for index in range(self.__args_len):
|
for index in range(self.__kwargs_len):
|
||||||
arg = self.__args[index]
|
kwarg = self.__kwargs[index]
|
||||||
kwargs[arg.__name] = arg.__value
|
kwargs[kwarg.__name] = kwarg.__value
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def add_kwargs(self, **kwargs):
|
def add_kwargs(self, **kwargs):
|
||||||
|
|
|
@ -11,7 +11,10 @@ from .injections cimport (
|
||||||
NamedInjection,
|
NamedInjection,
|
||||||
parse_named_injections,
|
parse_named_injections,
|
||||||
)
|
)
|
||||||
from .utils cimport represent_provider
|
from .utils cimport (
|
||||||
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
cdef class Factory(Provider):
|
cdef class Factory(Provider):
|
||||||
|
@ -90,6 +93,22 @@ cdef class Factory(Provider):
|
||||||
|
|
||||||
super(Factory, self).__init__()
|
super(Factory, self).__init__()
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
copied = self.__class__(self.cls,
|
||||||
|
*deepcopy(self.args, memo),
|
||||||
|
**deepcopy(self.kwargs, memo))
|
||||||
|
copied.set_attributes(**deepcopy(self.attributes, memo))
|
||||||
|
|
||||||
|
for overriding_provider in self.overridden:
|
||||||
|
copied.override(deepcopy(overriding_provider, memo))
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return string representation of provider.
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
@ -185,8 +204,8 @@ cdef class Factory(Provider):
|
||||||
cdef dict attributes
|
cdef dict attributes
|
||||||
|
|
||||||
attributes = dict()
|
attributes = dict()
|
||||||
for index in range(self.__args_len):
|
for index in range(self.__attributes_len):
|
||||||
attribute = self.__args[index]
|
attribute = self.__attributes[index]
|
||||||
attributes[attribute.__name] = attribute.__value
|
attributes[attribute.__name] = attribute.__value
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ Powered by Cython.
|
||||||
cimport cython
|
cimport cython
|
||||||
|
|
||||||
|
|
||||||
cdef class Injection:
|
cdef class Injection(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,11 @@ cimport cython
|
||||||
from .utils cimport (
|
from .utils cimport (
|
||||||
is_provider,
|
is_provider,
|
||||||
is_delegated,
|
is_delegated,
|
||||||
|
deepcopy,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
cdef class Injection:
|
cdef class Injection(object):
|
||||||
"""Abstract injection class."""
|
"""Abstract injection class."""
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +26,14 @@ cdef class PositionalInjection(Injection):
|
||||||
self.__is_delegated = <int>is_delegated(value)
|
self.__is_delegated = <int>is_delegated(value)
|
||||||
self.__call = <int>(self.__is_provider == 1 and
|
self.__call = <int>(self.__is_provider == 1 and
|
||||||
self.__is_delegated == 0)
|
self.__is_delegated == 0)
|
||||||
|
super(PositionalInjection, self).__init__()
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
return self.__class__(deepcopy(self.__value, memo))
|
||||||
|
|
||||||
def get_value(self):
|
def get_value(self):
|
||||||
"""Return injection value."""
|
"""Return injection value."""
|
||||||
|
@ -46,6 +55,15 @@ cdef class NamedInjection(Injection):
|
||||||
self.__is_delegated = <int>is_delegated(value)
|
self.__is_delegated = <int>is_delegated(value)
|
||||||
self.__call = <int>(self.__is_provider == 1 and
|
self.__call = <int>(self.__is_provider == 1 and
|
||||||
self.__is_delegated == 0)
|
self.__is_delegated == 0)
|
||||||
|
super(NamedInjection, self).__init__()
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
return self.__class__(deepcopy(self.__name, memo),
|
||||||
|
deepcopy(self.__value, memo))
|
||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
"""Return injection value."""
|
"""Return injection value."""
|
||||||
|
|
|
@ -9,7 +9,10 @@ from dependency_injector.errors import Error
|
||||||
|
|
||||||
from .base cimport Provider
|
from .base cimport Provider
|
||||||
from .factories cimport Factory
|
from .factories cimport Factory
|
||||||
from .utils cimport represent_provider
|
from .utils cimport (
|
||||||
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
GLOBAL_LOCK = threading.RLock()
|
GLOBAL_LOCK = threading.RLock()
|
||||||
|
@ -43,7 +46,7 @@ cdef class BaseSingleton(Provider):
|
||||||
|
|
||||||
self.__instantiator = Factory(provides, *args, **kwargs)
|
self.__instantiator = Factory(provides, *args, **kwargs)
|
||||||
|
|
||||||
super(Provider, self).__init__()
|
super(BaseSingleton, self).__init__()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return string representation of provider.
|
"""Return string representation of provider.
|
||||||
|
@ -53,6 +56,22 @@ cdef class BaseSingleton(Provider):
|
||||||
return represent_provider(provider=self,
|
return represent_provider(provider=self,
|
||||||
provides=self.__instantiator.cls)
|
provides=self.__instantiator.cls)
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
"""Create and return full copy of provider."""
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
copied = self.__class__(self.cls,
|
||||||
|
*deepcopy(self.args, memo),
|
||||||
|
**deepcopy(self.kwargs, memo))
|
||||||
|
copied.set_attributes(**deepcopy(self.attributes, memo))
|
||||||
|
|
||||||
|
for overriding_provider in self.overridden:
|
||||||
|
copied.override(deepcopy(overriding_provider, memo))
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cls(self):
|
def cls(self):
|
||||||
"""Return provided type."""
|
"""Return provided type."""
|
||||||
|
@ -178,7 +197,35 @@ cdef class BaseSingleton(Provider):
|
||||||
|
|
||||||
|
|
||||||
cdef class Singleton(BaseSingleton):
|
cdef class Singleton(BaseSingleton):
|
||||||
"""Singleton provider."""
|
"""Singleton provider returns same instance on every call.
|
||||||
|
|
||||||
|
:py:class:`Singleton` provider creates instance once and returns it on
|
||||||
|
every call. :py:class:`Singleton` extends :py:class:`Factory`, so, please
|
||||||
|
follow :py:class:`Factory` documentation for getting familiar with
|
||||||
|
injections syntax.
|
||||||
|
|
||||||
|
Retrieving of provided instance can be performed via calling
|
||||||
|
:py:class:`Singleton` object:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
singleton = Singleton(SomeClass)
|
||||||
|
some_object = singleton()
|
||||||
|
|
||||||
|
.. py:attribute:: provided_type
|
||||||
|
|
||||||
|
If provided type is defined, provider checks that providing class is
|
||||||
|
its subclass.
|
||||||
|
|
||||||
|
:type: type | None
|
||||||
|
|
||||||
|
.. py:attribute:: cls
|
||||||
|
|
||||||
|
Class that provides object.
|
||||||
|
Alias for :py:attr:`provides`.
|
||||||
|
|
||||||
|
:type: type
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, provides, *args, **kwargs):
|
def __init__(self, provides, *args, **kwargs):
|
||||||
"""Initializer.
|
"""Initializer.
|
||||||
|
@ -208,6 +255,23 @@ cdef class Singleton(BaseSingleton):
|
||||||
|
|
||||||
|
|
||||||
cdef class DelegatedSingleton(Singleton):
|
cdef class DelegatedSingleton(Singleton):
|
||||||
|
"""Delegated singleton is injected "as is".
|
||||||
|
|
||||||
|
.. py:attribute:: provided_type
|
||||||
|
|
||||||
|
If provided type is defined, provider checks that providing class is
|
||||||
|
its subclass.
|
||||||
|
|
||||||
|
:type: type | None
|
||||||
|
|
||||||
|
.. py:attribute:: cls
|
||||||
|
|
||||||
|
Class that provides object.
|
||||||
|
Alias for :py:attr:`provides`.
|
||||||
|
|
||||||
|
:type: type
|
||||||
|
"""
|
||||||
|
|
||||||
__IS_DELEGATED__ = True
|
__IS_DELEGATED__ = True
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,11 +307,43 @@ cdef class ThreadSafeSingleton(BaseSingleton):
|
||||||
|
|
||||||
|
|
||||||
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
|
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
|
||||||
|
"""Delegated thread-safe singleton is injected "as is".
|
||||||
|
|
||||||
|
.. py:attribute:: provided_type
|
||||||
|
|
||||||
|
If provided type is defined, provider checks that providing class is
|
||||||
|
its subclass.
|
||||||
|
|
||||||
|
:type: type | None
|
||||||
|
|
||||||
|
.. py:attribute:: cls
|
||||||
|
|
||||||
|
Class that provides object.
|
||||||
|
Alias for :py:attr:`provides`.
|
||||||
|
|
||||||
|
:type: type
|
||||||
|
"""
|
||||||
|
|
||||||
__IS_DELEGATED__ = True
|
__IS_DELEGATED__ = True
|
||||||
|
|
||||||
|
|
||||||
cdef class ThreadLocalSingleton(BaseSingleton):
|
cdef class ThreadLocalSingleton(BaseSingleton):
|
||||||
"""Thread local singleton provider."""
|
"""Thread-local singleton provides single objects in scope of thread.
|
||||||
|
|
||||||
|
.. py:attribute:: provided_type
|
||||||
|
|
||||||
|
If provided type is defined, provider checks that providing class is
|
||||||
|
its subclass.
|
||||||
|
|
||||||
|
:type: type | None
|
||||||
|
|
||||||
|
.. py:attribute:: cls
|
||||||
|
|
||||||
|
Class that provides object.
|
||||||
|
Alias for :py:attr:`provides`.
|
||||||
|
|
||||||
|
:type: type
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, provides, *args, **kwargs):
|
def __init__(self, provides, *args, **kwargs):
|
||||||
"""Initializer.
|
"""Initializer.
|
||||||
|
@ -277,4 +373,21 @@ cdef class ThreadLocalSingleton(BaseSingleton):
|
||||||
|
|
||||||
|
|
||||||
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
|
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
|
||||||
|
"""Delegated thread-local singleton is injected "as is".
|
||||||
|
|
||||||
|
.. py:attribute:: provided_type
|
||||||
|
|
||||||
|
If provided type is defined, provider checks that providing class is
|
||||||
|
its subclass.
|
||||||
|
|
||||||
|
:type: type | None
|
||||||
|
|
||||||
|
.. py:attribute:: cls
|
||||||
|
|
||||||
|
Class that provides object.
|
||||||
|
Alias for :py:attr:`provides`.
|
||||||
|
|
||||||
|
:type: type
|
||||||
|
"""
|
||||||
|
|
||||||
__IS_DELEGATED__ = True
|
__IS_DELEGATED__ = True
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
"""Dependency injector static providers.
|
|
||||||
|
|
||||||
Powered by Cython.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from .base cimport Provider
|
|
||||||
|
|
||||||
|
|
||||||
cdef class Object(Provider):
|
|
||||||
cdef object __provides
|
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
cdef class Delegate(Object):
|
|
||||||
pass
|
|
||||||
|
|
||||||
cdef class ExternalDependency(Provider):
|
|
||||||
cdef type __instance_of
|
|
|
@ -1,165 +0,0 @@
|
||||||
"""Dependency injector static providers.
|
|
||||||
|
|
||||||
Powered by Cython.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from dependency_injector.errors import Error
|
|
||||||
|
|
||||||
from .base cimport Provider
|
|
||||||
from .utils cimport (
|
|
||||||
ensure_is_provider,
|
|
||||||
represent_provider,
|
|
||||||
CLASS_TYPES,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
cdef class Object(Provider):
|
|
||||||
"""Object provider returns provided instance "as is".
|
|
||||||
|
|
||||||
.. py:attribute:: provides
|
|
||||||
|
|
||||||
Value that have to be provided.
|
|
||||||
|
|
||||||
:type: object
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, provides):
|
|
||||||
"""Initializer.
|
|
||||||
|
|
||||||
:param provides: Value that have to be provided.
|
|
||||||
:type provides: object
|
|
||||||
"""
|
|
||||||
self.__provides = provides
|
|
||||||
super(Object, self).__init__()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return string representation of provider.
|
|
||||||
|
|
||||||
:rtype: str
|
|
||||||
"""
|
|
||||||
return represent_provider(provider=self, provides=self.__provides)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Return string representation of provider.
|
|
||||||
|
|
||||||
:rtype: str
|
|
||||||
"""
|
|
||||||
return self.__str__()
|
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict 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
|
|
||||||
|
|
||||||
|
|
||||||
cdef class Delegate(Object):
|
|
||||||
"""Delegate provider returns provider "as is".
|
|
||||||
|
|
||||||
.. py:attribute:: provides
|
|
||||||
|
|
||||||
Value that have to be provided.
|
|
||||||
|
|
||||||
:type: object
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, provides):
|
|
||||||
"""Initializer.
|
|
||||||
|
|
||||||
:param provides: Value that have to be provided.
|
|
||||||
:type provides: object
|
|
||||||
"""
|
|
||||||
super(Delegate, self).__init__(ensure_is_provider(provides))
|
|
||||||
|
|
||||||
|
|
||||||
cdef 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
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, type instance_of):
|
|
||||||
"""Initializer."""
|
|
||||||
if not isinstance(instance_of, 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
|
|
||||||
"""
|
|
||||||
cdef object instance
|
|
||||||
|
|
||||||
if self.__overridden_len == 0:
|
|
||||||
raise Error('Dependency is not defined')
|
|
||||||
|
|
||||||
instance = self._call_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 __str__(self):
|
|
||||||
"""Return string representation of provider.
|
|
||||||
|
|
||||||
:rtype: str
|
|
||||||
"""
|
|
||||||
return represent_provider(provider=self, provides=self.__instance_of)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Return string representation of provider.
|
|
||||||
|
|
||||||
:rtype: str
|
|
||||||
"""
|
|
||||||
return self.__str__()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def instance_of(self):
|
|
||||||
"""Return class of required dependency."""
|
|
||||||
return self.__instance_of
|
|
||||||
|
|
||||||
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)
|
|
|
@ -3,18 +3,11 @@
|
||||||
Powered by Cython.
|
Powered by Cython.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .base cimport Provider
|
|
||||||
|
|
||||||
|
|
||||||
cdef public object CLASS_TYPES
|
cdef public object CLASS_TYPES
|
||||||
|
|
||||||
|
|
||||||
cdef class OverridingContext(object):
|
|
||||||
cdef Provider __overridden
|
|
||||||
cdef Provider __overriding
|
|
||||||
|
|
||||||
|
|
||||||
cpdef bint is_provider(object instance)
|
cpdef bint is_provider(object instance)
|
||||||
cpdef object ensure_is_provider(object instance)
|
cpdef object ensure_is_provider(object instance)
|
||||||
cpdef bint is_delegated(object instance)
|
cpdef bint is_delegated(object instance)
|
||||||
cpdef str represent_provider(object provider, object provides)
|
cpdef str represent_provider(object provider, object provides)
|
||||||
|
cpdef object deepcopy(object instance, dict memo=*)
|
||||||
|
|
|
@ -3,55 +3,23 @@
|
||||||
Powered by Cython.
|
Powered by Cython.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from dependency_injector.errors import Error
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
from .base cimport Provider
|
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info[0] == 3: # pragma: no cover
|
if sys.version_info[0] == 3: # pragma: no cover
|
||||||
CLASS_TYPES = (type,)
|
CLASS_TYPES = (type,)
|
||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
CLASS_TYPES = (type, types.ClassType)
|
CLASS_TYPES = (type, types.ClassType)
|
||||||
|
|
||||||
|
copy._deepcopy_dispatch[types.MethodType] = \
|
||||||
cdef class OverridingContext(object):
|
lambda obj, memo: type(obj)(obj.im_func,
|
||||||
"""Provider overriding context.
|
copy.deepcopy(obj.im_self, memo),
|
||||||
|
obj.im_class)
|
||||||
: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.overridden
|
|
||||||
assert not provider.overridden
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, Provider overridden, Provider 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()
|
|
||||||
|
|
||||||
|
|
||||||
cpdef bint is_provider(object instance):
|
cpdef bint is_provider(object instance):
|
||||||
|
@ -112,3 +80,7 @@ cpdef str represent_provider(object provider, object provides):
|
||||||
provider.__class__.__name__)),
|
provider.__class__.__name__)),
|
||||||
provides=repr(provides) if provides is not None else '',
|
provides=repr(provides) if provides is not None else '',
|
||||||
address=hex(id(provider)))
|
address=hex(id(provider)))
|
||||||
|
|
||||||
|
cpdef object deepcopy(object instance, dict memo=None):
|
||||||
|
"""Return full copy of provider or container with providers."""
|
||||||
|
return copy.deepcopy(instance, memo)
|
||||||
|
|
|
@ -84,3 +84,86 @@ class ProviderTests(unittest.TestCase):
|
||||||
self.assertEqual(repr(self.provider),
|
self.assertEqual(repr(self.provider),
|
||||||
'<dependency_injector.providers.base.'
|
'<dependency_injector.providers.base.'
|
||||||
'Provider() at {0}>'.format(hex(id(self.provider))))
|
'Provider() at {0}>'.format(hex(id(self.provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectProviderTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(providers.is_provider(providers.Object(object())))
|
||||||
|
|
||||||
|
def test_call_object_provider(self):
|
||||||
|
obj = object()
|
||||||
|
self.assertIs(providers.Object(obj)(), obj)
|
||||||
|
|
||||||
|
def test_call_overridden_object_provider(self):
|
||||||
|
obj1 = object()
|
||||||
|
obj2 = object()
|
||||||
|
provider = providers.Object(obj1)
|
||||||
|
provider.override(providers.Object(obj2))
|
||||||
|
self.assertIs(provider(), obj2)
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
some_object = object()
|
||||||
|
provider = providers.Object(some_object)
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.base.'
|
||||||
|
'Object({0}) at {1}>'.format(
|
||||||
|
repr(some_object),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegateTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.delegated = providers.Provider()
|
||||||
|
self.delegate = providers.Delegate(self.delegated)
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(providers.is_provider(self.delegate))
|
||||||
|
|
||||||
|
def test_init_with_not_provider(self):
|
||||||
|
self.assertRaises(errors.Error, providers.Delegate, object())
|
||||||
|
|
||||||
|
def test_call(self):
|
||||||
|
delegated1 = self.delegate()
|
||||||
|
delegated2 = self.delegate()
|
||||||
|
|
||||||
|
self.assertIs(delegated1, self.delegated)
|
||||||
|
self.assertIs(delegated2, self.delegated)
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
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):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.provider = providers.ExternalDependency(instance_of=list)
|
||||||
|
|
||||||
|
def test_init_with_not_class(self):
|
||||||
|
self.assertRaises(TypeError, providers.ExternalDependency, object())
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(providers.is_provider(self.provider))
|
||||||
|
|
||||||
|
def test_call_overridden(self):
|
||||||
|
self.provider.provided_by(providers.Factory(list))
|
||||||
|
self.assertIsInstance(self.provider(), list)
|
||||||
|
|
||||||
|
def test_call_overridden_but_not_instance_of(self):
|
||||||
|
self.provider.provided_by(providers.Factory(dict))
|
||||||
|
self.assertRaises(errors.Error, self.provider)
|
||||||
|
|
||||||
|
def test_call_not_overridden(self):
|
||||||
|
self.assertRaises(errors.Error, self.provider)
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
self.assertEqual(repr(self.provider),
|
||||||
|
'<dependency_injector.providers.base.'
|
||||||
|
'ExternalDependency({0}) at {1}>'.format(
|
||||||
|
repr(list),
|
||||||
|
hex(id(self.provider))))
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
"""Dependency injector static providers unit tests."""
|
|
||||||
|
|
||||||
import unittest2 as unittest
|
|
||||||
|
|
||||||
from dependency_injector import (
|
|
||||||
providers,
|
|
||||||
errors,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectProviderTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(providers.is_provider(providers.Object(object())))
|
|
||||||
|
|
||||||
def test_call_object_provider(self):
|
|
||||||
obj = object()
|
|
||||||
self.assertIs(providers.Object(obj)(), obj)
|
|
||||||
|
|
||||||
def test_call_overridden_object_provider(self):
|
|
||||||
obj1 = object()
|
|
||||||
obj2 = object()
|
|
||||||
provider = providers.Object(obj1)
|
|
||||||
provider.override(providers.Object(obj2))
|
|
||||||
self.assertIs(provider(), obj2)
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
some_object = object()
|
|
||||||
provider = providers.Object(some_object)
|
|
||||||
self.assertEqual(repr(provider),
|
|
||||||
'<dependency_injector.providers.static.'
|
|
||||||
'Object({0}) at {1}>'.format(
|
|
||||||
repr(some_object),
|
|
||||||
hex(id(provider))))
|
|
||||||
|
|
||||||
|
|
||||||
class DelegateTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.delegated = providers.Provider()
|
|
||||||
self.delegate = providers.Delegate(self.delegated)
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(providers.is_provider(self.delegate))
|
|
||||||
|
|
||||||
def test_init_with_not_provider(self):
|
|
||||||
self.assertRaises(errors.Error, providers.Delegate, object())
|
|
||||||
|
|
||||||
def test_call(self):
|
|
||||||
delegated1 = self.delegate()
|
|
||||||
delegated2 = self.delegate()
|
|
||||||
|
|
||||||
self.assertIs(delegated1, self.delegated)
|
|
||||||
self.assertIs(delegated2, self.delegated)
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
self.assertEqual(repr(self.delegate),
|
|
||||||
'<dependency_injector.providers.static.'
|
|
||||||
'Delegate({0}) at {1}>'.format(
|
|
||||||
repr(self.delegated),
|
|
||||||
hex(id(self.delegate))))
|
|
||||||
|
|
||||||
|
|
||||||
class ExternalDependencyTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.provider = providers.ExternalDependency(instance_of=list)
|
|
||||||
|
|
||||||
def test_init_with_not_class(self):
|
|
||||||
self.assertRaises(TypeError, providers.ExternalDependency, object())
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(providers.is_provider(self.provider))
|
|
||||||
|
|
||||||
def test_call_overridden(self):
|
|
||||||
self.provider.provided_by(providers.Factory(list))
|
|
||||||
self.assertIsInstance(self.provider(), list)
|
|
||||||
|
|
||||||
def test_call_overridden_but_not_instance_of(self):
|
|
||||||
self.provider.provided_by(providers.Factory(dict))
|
|
||||||
self.assertRaises(errors.Error, self.provider)
|
|
||||||
|
|
||||||
def test_call_not_overridden(self):
|
|
||||||
self.assertRaises(errors.Error, self.provider)
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
self.assertEqual(repr(self.provider),
|
|
||||||
'<dependency_injector.providers.static.'
|
|
||||||
'ExternalDependency({0}) at {1}>'.format(
|
|
||||||
repr(list),
|
|
||||||
hex(id(self.provider))))
|
|
Loading…
Reference in New Issue
Block a user