mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 11:04:01 +03:00
Update providers package structure
This commit is contained in:
parent
e68df7167f
commit
38bdc4f04f
20
setup.py
20
setup.py
|
@ -47,6 +47,26 @@ setup(name='dependency-injector',
|
||||||
'': 'src',
|
'': 'src',
|
||||||
},
|
},
|
||||||
ext_modules=[
|
ext_modules=[
|
||||||
|
Extension('dependency_injector.providers.base',
|
||||||
|
['src/dependency_injector/providers/base.c'],
|
||||||
|
define_macros=defined_macros,
|
||||||
|
extra_compile_args=['-O2']),
|
||||||
|
Extension('dependency_injector.providers.callables',
|
||||||
|
['src/dependency_injector/providers/callables.c'],
|
||||||
|
define_macros=defined_macros,
|
||||||
|
extra_compile_args=['-O2']),
|
||||||
|
Extension('dependency_injector.providers.factories',
|
||||||
|
['src/dependency_injector/providers/factories.c'],
|
||||||
|
define_macros=defined_macros,
|
||||||
|
extra_compile_args=['-O2']),
|
||||||
|
Extension('dependency_injector.providers.singletons',
|
||||||
|
['src/dependency_injector/providers/singletons.c'],
|
||||||
|
define_macros=defined_macros,
|
||||||
|
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,
|
||||||
|
|
|
@ -2,46 +2,49 @@
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
Provider,
|
Provider,
|
||||||
Delegate,
|
|
||||||
Object,
|
|
||||||
ExternalDependency,
|
|
||||||
OverridingContext,
|
|
||||||
override,
|
|
||||||
)
|
)
|
||||||
from .callable import (
|
from .callables import (
|
||||||
Callable,
|
Callable,
|
||||||
DelegatedCallable,
|
DelegatedCallable,
|
||||||
)
|
)
|
||||||
from .creational import (
|
from .factories import (
|
||||||
Factory,
|
Factory,
|
||||||
DelegatedFactory,
|
DelegatedFactory,
|
||||||
|
)
|
||||||
|
from .singletons import (
|
||||||
|
BaseSingleton,
|
||||||
|
|
||||||
Singleton,
|
Singleton,
|
||||||
DelegatedSingleton,
|
DelegatedSingleton,
|
||||||
|
|
||||||
|
ThreadSafeSingleton,
|
||||||
|
DelegatedThreadSafeSingleton,
|
||||||
|
|
||||||
ThreadLocalSingleton,
|
ThreadLocalSingleton,
|
||||||
DelegatedThreadLocalSingleton,
|
DelegatedThreadLocalSingleton,
|
||||||
)
|
)
|
||||||
from .utils import (
|
from .static import (
|
||||||
GLOBAL_LOCK,
|
Object,
|
||||||
is_provider,
|
Delegate,
|
||||||
ensure_is_provider,
|
ExternalDependency,
|
||||||
is_delegated,
|
|
||||||
represent_provider,
|
|
||||||
)
|
)
|
||||||
from .injections import (
|
from .injections import (
|
||||||
Injection,
|
Injection,
|
||||||
PositionalInjection,
|
PositionalInjection,
|
||||||
NamedInjection,
|
NamedInjection,
|
||||||
)
|
)
|
||||||
|
from .utils import (
|
||||||
|
GLOBAL_LOCK,
|
||||||
|
OverridingContext,
|
||||||
|
is_provider,
|
||||||
|
ensure_is_provider,
|
||||||
|
is_delegated,
|
||||||
|
represent_provider,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Provider',
|
'Provider',
|
||||||
'Delegate',
|
|
||||||
'Object',
|
|
||||||
'ExternalDependency',
|
|
||||||
|
|
||||||
'OverridingContext',
|
|
||||||
'override',
|
|
||||||
|
|
||||||
'Callable',
|
'Callable',
|
||||||
'DelegatedCallable',
|
'DelegatedCallable',
|
||||||
|
@ -49,19 +52,29 @@ __all__ = (
|
||||||
'Factory',
|
'Factory',
|
||||||
'DelegatedFactory',
|
'DelegatedFactory',
|
||||||
|
|
||||||
|
'BaseSingleton',
|
||||||
|
|
||||||
'Singleton',
|
'Singleton',
|
||||||
'DelegatedSingleton',
|
'DelegatedSingleton',
|
||||||
|
|
||||||
|
'ThreadSafeSingleton',
|
||||||
|
'DelegatedThreadSafeSingleton',
|
||||||
|
|
||||||
'ThreadLocalSingleton',
|
'ThreadLocalSingleton',
|
||||||
'DelegatedThreadLocalSingleton',
|
'DelegatedThreadLocalSingleton',
|
||||||
|
|
||||||
'GLOBAL_LOCK',
|
'Object',
|
||||||
'is_provider',
|
'Delegate',
|
||||||
'ensure_is_provider',
|
'ExternalDependency',
|
||||||
'is_delegated',
|
|
||||||
'represent_provider',
|
|
||||||
|
|
||||||
'Injection',
|
'Injection',
|
||||||
'PositionalInjection',
|
'PositionalInjection',
|
||||||
'NamedInjection',
|
'NamedInjection',
|
||||||
|
|
||||||
|
'GLOBAL_LOCK',
|
||||||
|
'OverridingContext',
|
||||||
|
'is_provider',
|
||||||
|
'ensure_is_provider',
|
||||||
|
'is_delegated',
|
||||||
|
'represent_provider',
|
||||||
)
|
)
|
||||||
|
|
12
src/dependency_injector/providers/base.pxd
Normal file
12
src/dependency_injector/providers/base.pxd
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
"""Dependency injector base providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Provider(object):
|
||||||
|
cdef tuple __overridden
|
||||||
|
cdef int __overridden_len
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
cpdef object _call_last_overriding(self, tuple args, dict kwargs)
|
|
@ -1,416 +0,0 @@
|
||||||
"""Dependency injector base providers."""
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from dependency_injector.errors import Error
|
|
||||||
from .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
|
|
||||||
|
|
||||||
Tuple of overriding providers, if any.
|
|
||||||
|
|
||||||
:type: tuple[:py:class:`Provider`] | None
|
|
||||||
"""
|
|
||||||
|
|
||||||
__IS_PROVIDER__ = True
|
|
||||||
__OPTIMIZED_CALLS__ = True
|
|
||||||
__slots__ = ('overridden', 'provide', '__call__')
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""Initializer."""
|
|
||||||
self.overridden = tuple()
|
|
||||||
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.overridden[-1](*args, **kwargs)
|
|
||||||
if self.overridden
|
|
||||||
else None)
|
|
||||||
|
|
||||||
def provide_injection(self):
|
|
||||||
"""Injection strategy implementation.
|
|
||||||
|
|
||||||
:rtype: object
|
|
||||||
"""
|
|
||||||
return self.provide()
|
|
||||||
|
|
||||||
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 = Object(provider)
|
|
||||||
|
|
||||||
self.overridden += (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:
|
|
||||||
raise Error('Provider {0} is not overridden'.format(str(self)))
|
|
||||||
|
|
||||||
self.overridden = self.overridden[:-1]
|
|
||||||
|
|
||||||
if not self.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 = tuple()
|
|
||||||
|
|
||||||
# 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 Object(Provider):
|
|
||||||
""":py:class:`Object` provider returns provided instance "as is".
|
|
||||||
|
|
||||||
.. 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(Object, 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__
|
|
||||||
|
|
||||||
|
|
||||||
@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
|
|
||||||
self.provide = self.__call__
|
|
||||||
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.overridden:
|
|
||||||
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 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.overridden
|
|
||||||
assert not provider.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
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_positional_injections(args):
|
|
||||||
return tuple(arg if is_provider(arg) else Object(arg)
|
|
||||||
for arg in args)
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_keyword_injections(kwargs):
|
|
||||||
return dict((name, arg if is_provider(arg) else Object(arg))
|
|
||||||
for name, arg in six.iteritems(kwargs))
|
|
169
src/dependency_injector/providers/base.pyx
Normal file
169
src/dependency_injector/providers/base.pyx
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
"""Dependency injector base providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
cimport cython
|
||||||
|
|
||||||
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
|
from .static cimport (
|
||||||
|
Object,
|
||||||
|
Delegate,
|
||||||
|
)
|
||||||
|
from .utils cimport (
|
||||||
|
is_provider,
|
||||||
|
ensure_is_provider,
|
||||||
|
represent_provider,
|
||||||
|
OverridingContext,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
cdef 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
|
||||||
|
|
||||||
|
Tuple of overriding providers, if any.
|
||||||
|
|
||||||
|
:type: tuple[:py:class:`Provider`] | None
|
||||||
|
"""
|
||||||
|
|
||||||
|
__IS_PROVIDER__ = True
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initializer."""
|
||||||
|
self.__overridden = tuple()
|
||||||
|
self.__overridden_len = 0
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
"""Return provided object.
|
||||||
|
|
||||||
|
Callable interface implementation.
|
||||||
|
"""
|
||||||
|
if self.__overridden_len != 0:
|
||||||
|
return self._call_last_overriding(args, kwargs)
|
||||||
|
return self._provide(args, kwargs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return represent_provider(provider=self, provides=None)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
def override(self, Provider provider):
|
||||||
|
"""Override provider with another provider.
|
||||||
|
|
||||||
|
:param provider: Overriding provider.
|
||||||
|
:type provider: :py:class:`Provider`
|
||||||
|
|
||||||
|
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||||
|
|
||||||
|
:return: Overriding context.
|
||||||
|
:rtype: :py:class:`OverridingContext`
|
||||||
|
"""
|
||||||
|
if provider is self:
|
||||||
|
raise Error('Provider {0} could not be overridden '
|
||||||
|
'with itself'.format(self))
|
||||||
|
|
||||||
|
if not is_provider(provider):
|
||||||
|
provider = Object(provider)
|
||||||
|
|
||||||
|
self.__overridden += tuple(ensure_is_provider(provider),)
|
||||||
|
self.__overridden_len += 1
|
||||||
|
|
||||||
|
return OverridingContext(self, provider)
|
||||||
|
|
||||||
|
@cython.boundscheck(False)
|
||||||
|
@cython.wraparound(False)
|
||||||
|
def reset_last_overriding(self):
|
||||||
|
"""Reset last overriding provider.
|
||||||
|
|
||||||
|
:raise: :py:exc:`dependency_injector.errors.Error` if provider is not
|
||||||
|
overridden.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
if self.__overridden_len == 0:
|
||||||
|
raise Error('Provider {0} is not overridden'.format(str(self)))
|
||||||
|
|
||||||
|
self.__overridden = self.overridden[:self.__overridden_len - 1]
|
||||||
|
self.__overridden_len -= 1
|
||||||
|
|
||||||
|
def reset_override(self):
|
||||||
|
"""Reset all overriding providers.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
self.__overridden = tuple()
|
||||||
|
self.__overridden_len += 0
|
||||||
|
|
||||||
|
def delegate(self):
|
||||||
|
"""Return provider's delegate.
|
||||||
|
|
||||||
|
:rtype: :py:class:`Delegate`
|
||||||
|
"""
|
||||||
|
return Delegate(self)
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict 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()
|
||||||
|
|
||||||
|
@cython.boundscheck(False)
|
||||||
|
@cython.wraparound(False)
|
||||||
|
cpdef object _call_last_overriding(self, tuple args, dict kwargs):
|
||||||
|
"""Call last overriding provider and return result."""
|
||||||
|
if self.__overridden_len == 0:
|
||||||
|
return None
|
||||||
|
return <object>self.__overridden[self.__overridden_len - 1](*args,
|
||||||
|
**kwargs)
|
|
@ -1,127 +0,0 @@
|
||||||
"""Dependency injector callable providers."""
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from dependency_injector.providers.base import (
|
|
||||||
Provider,
|
|
||||||
_parse_positional_injections,
|
|
||||||
_parse_keyword_injections,
|
|
||||||
)
|
|
||||||
from .utils import represent_provider
|
|
||||||
from dependency_injector.errors import Error
|
|
||||||
|
|
||||||
|
|
||||||
@six.python_2_unicode_compatible
|
|
||||||
class Callable(Provider):
|
|
||||||
r""":py:class:`Callable` provider calls wrapped callable on every call.
|
|
||||||
|
|
||||||
:py:class:`Callable` supports positional and keyword argument injections:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
some_function = Callable(some_function,
|
|
||||||
'positional_arg1', 'positional_arg2',
|
|
||||||
keyword_argument1=3, keyword_argument=4)
|
|
||||||
|
|
||||||
# or
|
|
||||||
|
|
||||||
some_function = Callable(some_function) \
|
|
||||||
.add_args('positional_arg1', 'positional_arg2') \
|
|
||||||
.add_kwargs(keyword_argument1=3, keyword_argument=4)
|
|
||||||
|
|
||||||
# or
|
|
||||||
|
|
||||||
some_function = Callable(some_function)
|
|
||||||
some_function.add_args('positional_arg1', 'positional_arg2')
|
|
||||||
some_function.add_kwargs(keyword_argument1=3, keyword_argument=4)
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ('provides', 'args', 'kwargs')
|
|
||||||
|
|
||||||
def __init__(self, provides, *args, **kwargs):
|
|
||||||
"""Initializer.
|
|
||||||
|
|
||||||
:param provides: Wrapped callable.
|
|
||||||
:type provides: callable
|
|
||||||
"""
|
|
||||||
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 = tuple()
|
|
||||||
self.kwargs = dict()
|
|
||||||
|
|
||||||
self.add_args(*args)
|
|
||||||
self.add_kwargs(**kwargs)
|
|
||||||
|
|
||||||
super(Callable, self).__init__()
|
|
||||||
|
|
||||||
def add_args(self, *args):
|
|
||||||
"""Add postional argument injections.
|
|
||||||
|
|
||||||
:param args: Tuple of injections.
|
|
||||||
:type args: tuple
|
|
||||||
|
|
||||||
:return: Reference ``self``
|
|
||||||
"""
|
|
||||||
self.args += _parse_positional_injections(args)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def add_kwargs(self, **kwargs):
|
|
||||||
"""Add keyword argument injections.
|
|
||||||
|
|
||||||
:param kwargs: Dictionary of injections.
|
|
||||||
:type kwargs: dict
|
|
||||||
|
|
||||||
:return: Reference ``self``
|
|
||||||
"""
|
|
||||||
self.kwargs.update(_parse_keyword_injections(kwargs))
|
|
||||||
return self
|
|
||||||
|
|
||||||
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.provide_injection() for arg in self.args) + args
|
|
||||||
|
|
||||||
for name, arg in six.iteritems(self.kwargs):
|
|
||||||
if name not in kwargs:
|
|
||||||
kwargs[name] = arg.provide_injection()
|
|
||||||
|
|
||||||
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".
|
|
||||||
"""
|
|
||||||
|
|
||||||
def provide_injection(self):
|
|
||||||
"""Injection strategy implementation.
|
|
||||||
|
|
||||||
:rtype: object
|
|
||||||
"""
|
|
||||||
return self
|
|
14
src/dependency_injector/providers/callables.pxd
Normal file
14
src/dependency_injector/providers/callables.pxd
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""Dependency injector callable providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Callable(Provider):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedCallable(Callable):
|
||||||
|
pass
|
14
src/dependency_injector/providers/callables.pyx
Normal file
14
src/dependency_injector/providers/callables.pyx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""Dependency injector callable providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Callable(Provider):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedCallable(Callable):
|
||||||
|
__IS_DELEGATED__ = True
|
|
@ -1,342 +0,0 @@
|
||||||
"""Dependency injector creational providers."""
|
|
||||||
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from dependency_injector.providers.callable import Callable
|
|
||||||
from dependency_injector.providers.base import _parse_keyword_injections
|
|
||||||
from .utils import GLOBAL_LOCK
|
|
||||||
from dependency_injector.errors import Error
|
|
||||||
|
|
||||||
|
|
||||||
class Factory(Callable):
|
|
||||||
r""":py:class:`Factory` provider creates new instance on every call.
|
|
||||||
|
|
||||||
:py:class:`Factory` supports positional & keyword argument injections,
|
|
||||||
as well as attribute injections.
|
|
||||||
|
|
||||||
Positional and keyword argument injections could be defined like this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
factory = Factory(SomeClass,
|
|
||||||
'positional_arg1', 'positional_arg2',
|
|
||||||
keyword_argument1=3, keyword_argument=4)
|
|
||||||
|
|
||||||
# or
|
|
||||||
|
|
||||||
factory = Factory(SomeClass) \
|
|
||||||
.add_args('positional_arg1', 'positional_arg2') \
|
|
||||||
.add_kwargs(keyword_argument1=3, keyword_argument=4)
|
|
||||||
|
|
||||||
# or
|
|
||||||
|
|
||||||
factory = Factory(SomeClass)
|
|
||||||
factory.add_args('positional_arg1', 'positional_arg2')
|
|
||||||
factory.add_kwargs(keyword_argument1=3, keyword_argument=4)
|
|
||||||
|
|
||||||
|
|
||||||
Attribute injections are defined by using :py:meth:`Factory.attributes`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
factory = Factory(SomeClass) \
|
|
||||||
.add_attributes(attribute1=1, attribute2=2)
|
|
||||||
|
|
||||||
Retrieving of provided instance can be performed via calling
|
|
||||||
:py:class:`Factory` object:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
factory = Factory(SomeClass)
|
|
||||||
some_object = factory()
|
|
||||||
|
|
||||||
.. 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
|
|
||||||
"""
|
|
||||||
|
|
||||||
provided_type = None
|
|
||||||
|
|
||||||
__slots__ = ('cls', 'attributes')
|
|
||||||
|
|
||||||
def __init__(self, provides, *args, **kwargs):
|
|
||||||
"""Initializer.
|
|
||||||
|
|
||||||
:param provides: Class or other callable that provides object
|
|
||||||
for creation.
|
|
||||||
:type provides: type | callable
|
|
||||||
"""
|
|
||||||
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 = dict()
|
|
||||||
|
|
||||||
super(Factory, self).__init__(provides, *args, **kwargs)
|
|
||||||
|
|
||||||
self.cls = self.provides
|
|
||||||
|
|
||||||
def add_attributes(self, **kwargs):
|
|
||||||
"""Add attribute injections.
|
|
||||||
|
|
||||||
:param kwargs: Dictionary of injections.
|
|
||||||
:type kwargs: dict
|
|
||||||
|
|
||||||
:return: Reference ``self``
|
|
||||||
"""
|
|
||||||
self.attributes.update(_parse_keyword_injections(kwargs))
|
|
||||||
return self
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
instance = super(Factory, self)._provide(*args, **kwargs)
|
|
||||||
|
|
||||||
for name, arg in six.iteritems(self.attributes):
|
|
||||||
setattr(instance, name, arg.provide_injection())
|
|
||||||
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
class DelegatedFactory(Factory):
|
|
||||||
""":py:class:`Factory` that 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
|
|
||||||
"""
|
|
||||||
|
|
||||||
def provide_injection(self):
|
|
||||||
"""Injection strategy implementation.
|
|
||||||
|
|
||||||
:rtype: object
|
|
||||||
"""
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
class Singleton(Factory):
|
|
||||||
""":py:class:`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.
|
|
||||||
|
|
||||||
: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_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
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ('instance',)
|
|
||||||
|
|
||||||
def __init__(self, provides, *args, **kwargs):
|
|
||||||
"""Initializer.
|
|
||||||
|
|
||||||
:param provides: Class or other callable that provides object
|
|
||||||
for creation.
|
|
||||||
:type provides: type | callable
|
|
||||||
"""
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
with GLOBAL_LOCK:
|
|
||||||
if self.instance is None:
|
|
||||||
self.instance = super(Singleton, self)._provide(*args,
|
|
||||||
**kwargs)
|
|
||||||
return self.instance
|
|
||||||
|
|
||||||
|
|
||||||
class DelegatedSingleton(Singleton):
|
|
||||||
""":py:class:`Singleton` that 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
|
|
||||||
"""
|
|
||||||
|
|
||||||
def provide_injection(self):
|
|
||||||
"""Injection strategy implementation.
|
|
||||||
|
|
||||||
:rtype: object
|
|
||||||
"""
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
class ThreadLocalSingleton(Factory):
|
|
||||||
""":py:class:`ThreadLocalSingleton` is singleton based on thread locals.
|
|
||||||
|
|
||||||
:py:class:`ThreadLocalSingleton` provider creates instance once for each
|
|
||||||
thread and returns it on every call. :py:class:`ThreadLocalSingleton`
|
|
||||||
extends :py:class:`Factory`, so, please follow :py:class:`Factory`
|
|
||||||
documentation for getting familiar with injections syntax.
|
|
||||||
|
|
||||||
:py:class:`ThreadLocalSingleton` 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:`ThreadLocalSingleton` object:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
singleton = ThreadLocalSingleton(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
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ('local_storage',)
|
|
||||||
|
|
||||||
def __init__(self, provides, *args, **kwargs):
|
|
||||||
"""Initializer.
|
|
||||||
|
|
||||||
:param provides: Class or other callable that provides object
|
|
||||||
for creation.
|
|
||||||
:type provides: type | callable
|
|
||||||
"""
|
|
||||||
self.local_storage = threading.local()
|
|
||||||
super(ThreadLocalSingleton, self).__init__(provides, *args, **kwargs)
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
"""Reset cached instance, if any.
|
|
||||||
|
|
||||||
:rtype: None
|
|
||||||
"""
|
|
||||||
self.local_storage.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
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
instance = self.local_storage.instance
|
|
||||||
except AttributeError:
|
|
||||||
instance = super(ThreadLocalSingleton, self)._provide(*args,
|
|
||||||
**kwargs)
|
|
||||||
self.local_storage.instance = instance
|
|
||||||
finally:
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
|
|
||||||
""":py:class:`ThreadLocalSingleton` that 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
|
|
||||||
"""
|
|
||||||
|
|
||||||
def provide_injection(self):
|
|
||||||
"""Injection strategy implementation.
|
|
||||||
|
|
||||||
:rtype: object
|
|
||||||
"""
|
|
||||||
return self
|
|
14
src/dependency_injector/providers/factories.pxd
Normal file
14
src/dependency_injector/providers/factories.pxd
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""Dependency injector factory providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Factory(Provider):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedFactory(Factory):
|
||||||
|
pass
|
14
src/dependency_injector/providers/factories.pyx
Normal file
14
src/dependency_injector/providers/factories.pyx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""Dependency injector factory providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Factory(Provider):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedFactory(Factory):
|
||||||
|
__IS_DELEGATED__ = True
|
34
src/dependency_injector/providers/singletons.pxd
Normal file
34
src/dependency_injector/providers/singletons.pxd
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
"""Dependency injector singleton providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
|
cdef class BaseSingleton(Provider):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Singleton(BaseSingleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedSingleton(Singleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadSafeSingleton(Singleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadLocalSingleton(BaseSingleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
|
||||||
|
pass
|
34
src/dependency_injector/providers/singletons.pyx
Normal file
34
src/dependency_injector/providers/singletons.pyx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
"""Dependency injector singleton providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
|
cdef class BaseSingleton(Provider):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Singleton(BaseSingleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedSingleton(Singleton):
|
||||||
|
__IS_DELEGATED__ = True
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadSafeSingleton(Singleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
|
||||||
|
__IS_DELEGATED__ = True
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadLocalSingleton(BaseSingleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
|
||||||
|
__IS_DELEGATED__ = True
|
19
src/dependency_injector/providers/static.pxd
Normal file
19
src/dependency_injector/providers/static.pxd
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
"""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
|
160
src/dependency_injector/providers/static.pyx
Normal file
160
src/dependency_injector/providers/static.pyx
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
"""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__()
|
||||||
|
|
||||||
|
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,6 +3,17 @@
|
||||||
Powered by Cython.
|
Powered by Cython.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
|
cdef tuple 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)
|
||||||
|
|
|
@ -10,16 +10,55 @@ import threading
|
||||||
|
|
||||||
from dependency_injector.errors import Error
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
|
||||||
|
|
||||||
GLOBAL_LOCK = threading.RLock()
|
GLOBAL_LOCK = threading.RLock()
|
||||||
"""Global reentrant lock.
|
"""Global reentrant lock.
|
||||||
|
|
||||||
:type: :py:class:`threading.RLock`
|
:type: :py:class:`threading.RLock`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
cdef tuple CLASS_TYPES
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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):
|
||||||
|
@ -30,7 +69,7 @@ cpdef bint is_provider(object instance):
|
||||||
|
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
return (not isinstance(instance, _CLASS_TYPES) and
|
return (not isinstance(instance, CLASS_TYPES) and
|
||||||
getattr(instance, '__IS_PROVIDER__', False) is True)
|
getattr(instance, '__IS_PROVIDER__', False) is True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,7 +98,7 @@ cpdef bint is_delegated(object instance):
|
||||||
|
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
return (not isinstance(instance, _CLASS_TYPES) and
|
return (not isinstance(instance, CLASS_TYPES) and
|
||||||
getattr(instance, '__IS_DELEGATED__', False) is True)
|
getattr(instance, '__IS_DELEGATED__', False) is True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -84,60 +84,3 @@ 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 DelegateTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.delegated = providers.Provider()
|
|
||||||
self.delegate = providers.Delegate(delegated=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, delegated=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(errors.Error, 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))))
|
|
||||||
|
|
|
@ -25,6 +25,11 @@ class PositionalInjectionTests(unittest.TestCase):
|
||||||
self.assertIs(type(obj2), object)
|
self.assertIs(type(obj2), object)
|
||||||
self.assertIsNot(obj1, obj2)
|
self.assertIsNot(obj1, obj2)
|
||||||
|
|
||||||
|
def test_get_original_value(self):
|
||||||
|
provider = providers.Factory(object)
|
||||||
|
injection = providers.PositionalInjection(provider)
|
||||||
|
self.assertIs(injection.get_original_value(), provider)
|
||||||
|
|
||||||
|
|
||||||
class NamedInjectionTests(unittest.TestCase):
|
class NamedInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -50,3 +55,8 @@ class NamedInjectionTests(unittest.TestCase):
|
||||||
self.assertIs(type(obj1), object)
|
self.assertIs(type(obj1), object)
|
||||||
self.assertIs(type(obj2), object)
|
self.assertIs(type(obj2), object)
|
||||||
self.assertIsNot(obj1, obj2)
|
self.assertIsNot(obj1, obj2)
|
||||||
|
|
||||||
|
def test_get_original_value(self):
|
||||||
|
provider = providers.Factory(object)
|
||||||
|
injection = providers.NamedInjection('name', provider)
|
||||||
|
self.assertIs(injection.get_original_value(), provider)
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
|
|
||||||
from dependency_injector import providers
|
from dependency_injector import (
|
||||||
|
providers,
|
||||||
|
errors,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ObjectProviderTests(unittest.TestCase):
|
class ObjectProviderTests(unittest.TestCase):
|
||||||
|
@ -25,7 +28,64 @@ class ObjectProviderTests(unittest.TestCase):
|
||||||
some_object = object()
|
some_object = object()
|
||||||
provider = providers.Object(some_object)
|
provider = providers.Object(some_object)
|
||||||
self.assertEqual(repr(provider),
|
self.assertEqual(repr(provider),
|
||||||
'<dependency_injector.providers.base.'
|
'<dependency_injector.providers.static.'
|
||||||
'Object({0}) at {1}>'.format(
|
'Object({0}) at {1}>'.format(
|
||||||
repr(some_object),
|
repr(some_object),
|
||||||
hex(id(provider))))
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegateTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.delegated = providers.Provider()
|
||||||
|
self.delegate = providers.Delegate(delegated=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, delegated=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