mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-07 07:00:49 +03:00
Merge pull request #143 from ets-labs/138_cython_providers_v3
Cython providers
This commit is contained in:
commit
8259de6dd7
|
@ -16,6 +16,9 @@ dependency injection pattern in formal, pretty, Pythonic way.
|
||||||
+ Documentation.
|
+ Documentation.
|
||||||
+ Semantic versioning.
|
+ Semantic versioning.
|
||||||
|
|
||||||
|
*Dependency Injector* providers are implemented as C extension types using
|
||||||
|
Cython.
|
||||||
|
|
||||||
Status
|
Status
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,4 @@ API Documentation
|
||||||
top_level
|
top_level
|
||||||
providers
|
providers
|
||||||
containers
|
containers
|
||||||
utils
|
|
||||||
errors
|
errors
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
``dependency_injector.providers``
|
``dependency_injector.providers``
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
.. image:: /images/providers/providers_class_diagram.png
|
|
||||||
:width: 100%
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
.. automodule:: dependency_injector.providers
|
.. automodule:: dependency_injector.providers
|
||||||
:members:
|
:members:
|
||||||
:inherited-members:
|
:inherited-members:
|
||||||
|
|
|
@ -17,7 +17,7 @@ Also, for both of these and some other cases, it might be useful to attach
|
||||||
some init / shutdown functionality or something else, that deals with group
|
some init / shutdown functionality or something else, that deals with group
|
||||||
of providers.
|
of providers.
|
||||||
|
|
||||||
Containers module API docs - :py:mod:`dependency_injector.containers`.
|
Containers package API docs - :py:mod:`dependency_injector.containers`.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 139 KiB |
|
@ -8,22 +8,33 @@ Dependency Injector --- Dependency injection microframework for Python
|
||||||
:description: Dependency Injector is a dependency injection microframework
|
:description: Dependency Injector is a dependency injection microframework
|
||||||
for Python. It was designed to be unified, developer-friendly
|
for Python. It was designed to be unified, developer-friendly
|
||||||
tool that helps to implement dependency injection pattern in
|
tool that helps to implement dependency injection pattern in
|
||||||
formal, pretty, Pythonic way.
|
formal, pretty, Pythonic way. Dependency Injector framework
|
||||||
|
key features are: Easy, smart, pythonic style; Obvious, clear
|
||||||
|
structure; Extensibility and flexibility; High performance;
|
||||||
|
Memory efficiency; Thread safety; Documentation; Semantic
|
||||||
|
versioning; Dependency Injector providers are implemented as
|
||||||
|
C extension types using Cython.
|
||||||
|
|
||||||
|
.. _index:
|
||||||
|
|
||||||
*Dependency Injector* is a dependency injection microframework for Python.
|
*Dependency Injector* is a dependency injection microframework for Python.
|
||||||
It was designed to be unified, developer-friendly tool that helps to implement
|
It was designed to be unified, developer-friendly tool that helps to implement
|
||||||
dependency injection pattern in formal, pretty, Pythonic way.
|
dependency injection pattern in formal, pretty, Pythonic way.
|
||||||
|
|
||||||
*Dependency Injector* framework key features are:
|
*Dependency Injector* framework key features are:
|
||||||
|
|
||||||
+ Easy, smart, pythonic style.
|
+ Easy, smart, pythonic style.
|
||||||
+ Obvious, clear structure.
|
+ Obvious, clear structure.
|
||||||
+ Extensibility and flexibility.
|
+ Extensibility and flexibility.
|
||||||
|
+ High performance.
|
||||||
+ Memory efficiency.
|
+ Memory efficiency.
|
||||||
+ Thread safety.
|
+ Thread safety.
|
||||||
+ Documentation.
|
+ Documentation.
|
||||||
+ Semantic versioning.
|
+ Semantic versioning.
|
||||||
|
|
||||||
|
*Dependency Injector* providers are implemented as C extension types using
|
||||||
|
Cython.
|
||||||
|
|
||||||
Status
|
Status
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ code for specification of dependencies. Nevertheless, this disadvantage could
|
||||||
be easily avoided by creating inversion of control container (IoC container).
|
be easily avoided by creating inversion of control container (IoC container).
|
||||||
|
|
||||||
Example of creation of several inversion of control containers (IoC containers)
|
Example of creation of several inversion of control containers (IoC containers)
|
||||||
using *Dependency Injector*:
|
using :doc:`Dependency Injector <../index>`:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/engines_cars/example_ioc_containers.py
|
.. literalinclude:: ../../examples/miniapps/engines_cars/example_ioc_containers.py
|
||||||
:language: python
|
:language: python
|
||||||
|
|
|
@ -9,16 +9,40 @@ follows `Semantic versioning`_
|
||||||
|
|
||||||
Development version
|
Development version
|
||||||
-------------------
|
-------------------
|
||||||
- Add ``dependency_injector.injections`` module (C extension).
|
- **Providers**
|
||||||
- Transfer ``dependency_injector.utils`` module to Cython (C extension).
|
|
||||||
- Transfer ``dependency_injector.errors`` module to Cython (C extension).
|
|
||||||
- Remove ``@inject`` decorator.
|
|
||||||
- Add makefile (``clean``, ``test``, ``build``, ``install``, ``uninstall``
|
|
||||||
& ``publish`` commands).
|
|
||||||
- Update repository structure:
|
|
||||||
|
|
||||||
- Sources are moved under ``src``.
|
1. All providers from ``dependency_injector.providers`` package are
|
||||||
- Tests are moved under ``tests/unit``.
|
implemented as C extension types using Cython.
|
||||||
|
2. Add ``BaseSingleton`` super class for all singleton providers.
|
||||||
|
3. Make ``Singleton`` provider not thread-safe. It makes performance of
|
||||||
|
``Singleton`` provider 10x times faster.
|
||||||
|
4. Add ``ThreadSafeSingleton`` provider - thread-safe version of
|
||||||
|
``Singleton`` provider.
|
||||||
|
5. Add ``ThreadLocalSingleton`` provider - ``Singleton`` provider that uses
|
||||||
|
thread-local storage.
|
||||||
|
6. Remove ``provides`` attribute from ``Factory`` and ``Singleton``
|
||||||
|
providers.
|
||||||
|
7. Add ``set_args()`` and ``clear_args()`` methods for ``Callable``,
|
||||||
|
``Factory`` and ``Singleton`` providers.
|
||||||
|
|
||||||
|
- **Containers**
|
||||||
|
|
||||||
|
1. Module ``dependency_injector.containers`` was splitted into submodules
|
||||||
|
without any functional changes.
|
||||||
|
|
||||||
|
- **Utils**
|
||||||
|
|
||||||
|
1. Module ``dependency_injector.utils`` is splitted into
|
||||||
|
``dependency_injector.containers`` and ``dependency_injector.providers``.
|
||||||
|
|
||||||
|
- **Miscellaneous**
|
||||||
|
|
||||||
|
1. Remove ``@inject`` decorator.
|
||||||
|
2. Add makefile (``clean``, ``test``, ``build``, ``install``, ``uninstall``
|
||||||
|
& ``publish`` commands).
|
||||||
|
3. Update repository structure:
|
||||||
|
1. Sources are moved under ``src/`` folder.
|
||||||
|
2. Tests are moved under ``tests/unit/`` folder.
|
||||||
|
|
||||||
.. - No features.
|
.. - No features.
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,13 @@ framework can be installed from PyPi_:
|
||||||
pip install dependency_injector
|
pip install dependency_injector
|
||||||
|
|
||||||
# Installing particular version:
|
# Installing particular version:
|
||||||
pip install dependency_injector==2.0.0
|
pip install dependency-injector==3.0.0
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Some components of *Dependency Injector* are implemented as C extension types.
|
||||||
|
*Dependency Injector* is distributed as an archive with a source code, so
|
||||||
|
C compiler and Python header files are required for the installation.
|
||||||
|
|
||||||
Sources can be cloned from GitHub_:
|
Sources can be cloned from GitHub_:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
@ -30,7 +35,7 @@ Verification of currently installed version could be done using
|
||||||
|
|
||||||
>>> from dependency_injector import VERSION
|
>>> from dependency_injector import VERSION
|
||||||
>>> VERSION
|
>>> VERSION
|
||||||
'2.0.0'
|
'3.0.0'
|
||||||
|
|
||||||
.. _PyPi: https://pypi.python.org/pypi/dependency_injector
|
.. _PyPi: https://pypi.python.org/pypi/dependency_injector
|
||||||
.. _GitHub: https://github.com/ets-labs/python-dependency-injector
|
.. _GitHub: https://github.com/ets-labs/python-dependency-injector
|
||||||
|
|
|
@ -12,16 +12,7 @@ Current documentation section consists from description of standard providers
|
||||||
library and some useful information like overriding of providers and writing
|
library and some useful information like overriding of providers and writing
|
||||||
of custom providers.
|
of custom providers.
|
||||||
|
|
||||||
All providers are validated in multithreading environment and considered to
|
Providers package API docs - :py:mod:`dependency_injector.providers`
|
||||||
be thread safe.
|
|
||||||
|
|
||||||
+ Base providers class is: :py:class:`dependency_injector.providers.Provider`
|
|
||||||
+ Providers module API docs: :py:mod:`dependency_injector.providers`
|
|
||||||
+ Providers class diagram:
|
|
||||||
|
|
||||||
.. image:: /images/providers/providers_class_diagram.png
|
|
||||||
:width: 100%
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
|
@ -21,7 +21,7 @@ Singleton providers resetting
|
||||||
|
|
||||||
Created and memorized by :py:class:`Singleton` instance can be reset. Reset of
|
Created and memorized by :py:class:`Singleton` instance can be reset. Reset of
|
||||||
:py:class:`Singleton`'s memorized instance is done by clearing reference to
|
:py:class:`Singleton`'s memorized instance is done by clearing reference to
|
||||||
it. Further lifecycle of memorized instance is out of :py:class:`Singleton`
|
it. Further lifecycle of memorized instance is out of :py:class:`Singleton`
|
||||||
provider's control and dependes on garbage collection strategy.
|
provider's control and dependes on garbage collection strategy.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -33,15 +33,15 @@ Example:
|
||||||
Singleton providers and injections
|
Singleton providers and injections
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
:py:class:`Singleton` provider extends :py:class:`Factory` provider, so, all
|
:py:class:`Singleton` provider has same interface as :py:class:`Factory`
|
||||||
of the rules about injections are the same, as for :py:class:`Factory`
|
provider, so, all of the rules about injections are the same, as for
|
||||||
provider.
|
:py:class:`Factory` provider.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Due that :py:class:`Singleton` provider creates specified class instance
|
Due that :py:class:`Singleton` provider creates specified class instance
|
||||||
only on the first call, all injections are done once, during the first
|
only on the first call, all injections are done once, during the first
|
||||||
call, also. Every next call, while instance has been already created
|
call. Every next call, while instance has been already created
|
||||||
and memorized, no injections are done, :py:class:`Singleton` provider just
|
and memorized, no injections are done, :py:class:`Singleton` provider just
|
||||||
returns memorized earlier instance.
|
returns memorized earlier instance.
|
||||||
|
|
||||||
|
@ -81,10 +81,12 @@ Specialization of :py:class:`Singleton` providers is the same as
|
||||||
Singleton providers and multi-threading
|
Singleton providers and multi-threading
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
:py:class:`Singleton` provider is thread-safe and could be used in
|
:py:class:`Singleton` provider is NOT thread-safe and should be used in
|
||||||
multi-threading applications without any negative impact. Race condition on
|
multi-threading applications with manually controlled locking.
|
||||||
singleton's initialization is escaped by using a global reentrant mutex -
|
|
||||||
:py:obj:`dependency_injector.utils.GLOBAL_LOCK`.
|
:py:class:`ThreadSafeSingleton` is a thread-safe version of
|
||||||
|
:py:class:`Singleton` and could be used in multi-threading applications
|
||||||
|
without any additional locking.
|
||||||
|
|
||||||
Also there could be a need to use thread-scoped singletons and there is a
|
Also there could be a need to use thread-scoped singletons and there is a
|
||||||
special provider for such case - :py:class:`ThreadLocalSingleton`.
|
special provider for such case - :py:class:`ThreadLocalSingleton`.
|
||||||
|
|
16
setup.py
16
setup.py
|
@ -47,6 +47,22 @@ 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.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,46 +2,51 @@
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
Provider,
|
Provider,
|
||||||
Delegate,
|
|
||||||
Object,
|
Object,
|
||||||
|
Delegate,
|
||||||
ExternalDependency,
|
ExternalDependency,
|
||||||
OverridingContext,
|
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 (
|
|
||||||
GLOBAL_LOCK,
|
|
||||||
is_provider,
|
|
||||||
ensure_is_provider,
|
|
||||||
is_delegated,
|
|
||||||
represent_provider,
|
|
||||||
)
|
|
||||||
from .injections import (
|
from .injections import (
|
||||||
Injection,
|
Injection,
|
||||||
PositionalInjection,
|
PositionalInjection,
|
||||||
NamedInjection,
|
NamedInjection,
|
||||||
)
|
)
|
||||||
|
from .utils import (
|
||||||
|
is_provider,
|
||||||
|
ensure_is_provider,
|
||||||
|
is_delegated,
|
||||||
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Provider',
|
'Provider',
|
||||||
'Delegate',
|
|
||||||
'Object',
|
'Object',
|
||||||
|
'Delegate',
|
||||||
'ExternalDependency',
|
'ExternalDependency',
|
||||||
|
|
||||||
'OverridingContext',
|
'OverridingContext',
|
||||||
'override',
|
|
||||||
|
|
||||||
'Callable',
|
'Callable',
|
||||||
'DelegatedCallable',
|
'DelegatedCallable',
|
||||||
|
@ -49,19 +54,24 @@ __all__ = (
|
||||||
'Factory',
|
'Factory',
|
||||||
'DelegatedFactory',
|
'DelegatedFactory',
|
||||||
|
|
||||||
|
'BaseSingleton',
|
||||||
|
|
||||||
'Singleton',
|
'Singleton',
|
||||||
'DelegatedSingleton',
|
'DelegatedSingleton',
|
||||||
|
|
||||||
|
'ThreadSafeSingleton',
|
||||||
|
'DelegatedThreadSafeSingleton',
|
||||||
|
|
||||||
'ThreadLocalSingleton',
|
'ThreadLocalSingleton',
|
||||||
'DelegatedThreadLocalSingleton',
|
'DelegatedThreadLocalSingleton',
|
||||||
|
|
||||||
'GLOBAL_LOCK',
|
'Injection',
|
||||||
|
'PositionalInjection',
|
||||||
|
'NamedInjection',
|
||||||
|
|
||||||
'is_provider',
|
'is_provider',
|
||||||
'ensure_is_provider',
|
'ensure_is_provider',
|
||||||
'is_delegated',
|
'is_delegated',
|
||||||
'represent_provider',
|
'represent_provider',
|
||||||
|
'deepcopy',
|
||||||
'Injection',
|
|
||||||
'PositionalInjection',
|
|
||||||
'NamedInjection',
|
|
||||||
)
|
)
|
||||||
|
|
31
src/dependency_injector/providers/base.pxd
Normal file
31
src/dependency_injector/providers/base.pxd
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
"""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)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
|
@ -1,17 +1,22 @@
|
||||||
"""Dependency injector base providers."""
|
"""Dependency injector base providers.
|
||||||
|
|
||||||
import six
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
cimport cython
|
||||||
|
|
||||||
from dependency_injector.errors import Error
|
from dependency_injector.errors import Error
|
||||||
from .utils import (
|
|
||||||
|
from .utils cimport (
|
||||||
|
CLASS_TYPES,
|
||||||
is_provider,
|
is_provider,
|
||||||
ensure_is_provider,
|
ensure_is_provider,
|
||||||
represent_provider,
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@six.python_2_unicode_compatible
|
cdef class Provider(object):
|
||||||
class Provider(object):
|
|
||||||
"""Base provider class.
|
"""Base provider class.
|
||||||
|
|
||||||
:py:class:`Provider` is callable (implements ``__call__`` method). Every
|
:py:class:`Provider` is callable (implements ``__call__`` method). Every
|
||||||
|
@ -59,38 +64,53 @@ class Provider(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__IS_PROVIDER__ = True
|
__IS_PROVIDER__ = True
|
||||||
__OPTIMIZED_CALLS__ = True
|
|
||||||
__slots__ = ('overridden', 'provide', '__call__')
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initializer."""
|
"""Initializer."""
|
||||||
self.overridden = tuple()
|
self.__overridden = tuple()
|
||||||
|
self.__overridden_len = 0
|
||||||
super(Provider, self).__init__()
|
super(Provider, self).__init__()
|
||||||
# Enable __call__() / _provide() optimization
|
|
||||||
if self.__class__.__OPTIMIZED_CALLS__:
|
|
||||||
self.__call__ = self.provide = self._provide
|
|
||||||
|
|
||||||
def _provide(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
"""Providing strategy implementation.
|
"""Return provided object.
|
||||||
|
|
||||||
Abstract protected method that implements providing strategy of
|
Callable interface implementation.
|
||||||
particular provider. Current method is called every time when not
|
|
||||||
overridden provider is called. Need to be overridden in subclasses.
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
if self.__overridden_len != 0:
|
||||||
|
return self._call_last_overriding(args, kwargs)
|
||||||
|
return self._provide(args, kwargs)
|
||||||
|
|
||||||
def _call_last_overriding(self, *args, **kwargs):
|
def __deepcopy__(self, memo):
|
||||||
"""Call last overriding provider and return result."""
|
"""Create and return full copy of provider."""
|
||||||
return (self.overridden[-1](*args, **kwargs)
|
copied = memo.get(id(self))
|
||||||
if self.overridden
|
if copied is not None:
|
||||||
else None)
|
return copied
|
||||||
|
|
||||||
def provide_injection(self):
|
copied = self.__class__()
|
||||||
"""Injection strategy implementation.
|
|
||||||
|
|
||||||
:rtype: object
|
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 self.provide()
|
return represent_provider(provider=self, provides=None)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def overridden(self):
|
||||||
|
"""Return tuple of overriding providers."""
|
||||||
|
return self.__overridden
|
||||||
|
|
||||||
def override(self, provider):
|
def override(self, provider):
|
||||||
"""Override provider with another provider.
|
"""Override provider with another provider.
|
||||||
|
@ -100,8 +120,8 @@ class Provider(object):
|
||||||
|
|
||||||
:raise: :py:exc:`dependency_injector.errors.Error`
|
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||||
|
|
||||||
:return: Overriding provider.
|
:return: Overriding context.
|
||||||
:rtype: :py:class:`Provider`
|
:rtype: :py:class:`OverridingContext`
|
||||||
"""
|
"""
|
||||||
if provider is self:
|
if provider is self:
|
||||||
raise Error('Provider {0} could not be overridden '
|
raise Error('Provider {0} could not be overridden '
|
||||||
|
@ -110,14 +130,13 @@ class Provider(object):
|
||||||
if not is_provider(provider):
|
if not is_provider(provider):
|
||||||
provider = Object(provider)
|
provider = Object(provider)
|
||||||
|
|
||||||
self.overridden += (ensure_is_provider(provider),)
|
self.__overridden += (provider,)
|
||||||
|
self.__overridden_len += 1
|
||||||
# Disable __call__() / _provide() optimization
|
|
||||||
if self.__class__.__OPTIMIZED_CALLS__:
|
|
||||||
self.__call__ = self.provide = self._call_last_overriding
|
|
||||||
|
|
||||||
return OverridingContext(self, provider)
|
return OverridingContext(self, provider)
|
||||||
|
|
||||||
|
@cython.boundscheck(False)
|
||||||
|
@cython.wraparound(False)
|
||||||
def reset_last_overriding(self):
|
def reset_last_overriding(self):
|
||||||
"""Reset last overriding provider.
|
"""Reset last overriding provider.
|
||||||
|
|
||||||
|
@ -126,26 +145,19 @@ class Provider(object):
|
||||||
|
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
if not self.overridden:
|
if self.__overridden_len == 0:
|
||||||
raise Error('Provider {0} is not overridden'.format(str(self)))
|
raise Error('Provider {0} is not overridden'.format(str(self)))
|
||||||
|
|
||||||
self.overridden = self.overridden[:-1]
|
self.__overridden = self.__overridden[:self.__overridden_len - 1]
|
||||||
|
self.__overridden_len -= 1
|
||||||
if not self.overridden:
|
|
||||||
# Enable __call__() / _provide() optimization
|
|
||||||
if self.__class__.__OPTIMIZED_CALLS__:
|
|
||||||
self.__call__ = self.provide = self._provide
|
|
||||||
|
|
||||||
def reset_override(self):
|
def reset_override(self):
|
||||||
"""Reset all overriding providers.
|
"""Reset all overriding providers.
|
||||||
|
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
self.overridden = tuple()
|
self.__overridden = tuple()
|
||||||
|
self.__overridden_len = 0
|
||||||
# Enable __call__() / _provide() optimization
|
|
||||||
if self.__class__.__OPTIMIZED_CALLS__:
|
|
||||||
self.__call__ = self.provide = self._provide
|
|
||||||
|
|
||||||
def delegate(self):
|
def delegate(self):
|
||||||
"""Return provider's delegate.
|
"""Return provider's delegate.
|
||||||
|
@ -154,73 +166,25 @@ class Provider(object):
|
||||||
"""
|
"""
|
||||||
return Delegate(self)
|
return Delegate(self)
|
||||||
|
|
||||||
def __str__(self):
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
"""Return string representation of provider.
|
"""Providing strategy implementation.
|
||||||
|
|
||||||
:rtype: str
|
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.
|
||||||
"""
|
"""
|
||||||
return represent_provider(provider=self, provides=None)
|
raise NotImplementedError()
|
||||||
|
|
||||||
__repr__ = __str__
|
@cython.boundscheck(False)
|
||||||
|
@cython.wraparound(False)
|
||||||
|
cpdef object _call_last_overriding(self, tuple args, dict kwargs):
|
||||||
|
"""Call last overriding provider and return result."""
|
||||||
|
return <object>self.__overridden[self.__overridden_len - 1](*args,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@six.python_2_unicode_compatible
|
cdef class Object(Provider):
|
||||||
class Delegate(Provider):
|
"""Object provider returns provided instance "as is".
|
||||||
""":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
|
.. py:attribute:: provides
|
||||||
|
|
||||||
|
@ -229,18 +193,43 @@ class Object(Provider):
|
||||||
:type: object
|
:type: object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ('provides',)
|
|
||||||
|
|
||||||
def __init__(self, provides):
|
def __init__(self, provides):
|
||||||
"""Initializer.
|
"""Initializer.
|
||||||
|
|
||||||
:param provides: Value that have to be provided.
|
:param provides: Value that have to be provided.
|
||||||
:type provides: object
|
:type provides: object
|
||||||
"""
|
"""
|
||||||
self.provides = provides
|
self.__provides = provides
|
||||||
super(Object, self).__init__()
|
super(Object, self).__init__()
|
||||||
|
|
||||||
def _provide(self, *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__(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.
|
"""Return provided instance.
|
||||||
|
|
||||||
:param args: Tuple of context positional arguments.
|
:param args: Tuple of context positional arguments.
|
||||||
|
@ -251,20 +240,29 @@ class Object(Provider):
|
||||||
|
|
||||||
:rtype: object
|
:rtype: object
|
||||||
"""
|
"""
|
||||||
return self.provides
|
return self.__provides
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return string representation of provider.
|
|
||||||
|
|
||||||
:rtype: str
|
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
|
||||||
"""
|
"""
|
||||||
return represent_provider(provider=self, provides=self.provides)
|
super(Delegate, self).__init__(ensure_is_provider(provides))
|
||||||
|
|
||||||
__repr__ = __str__
|
|
||||||
|
|
||||||
|
|
||||||
@six.python_2_unicode_compatible
|
cdef class ExternalDependency(Provider):
|
||||||
class ExternalDependency(Provider):
|
|
||||||
""":py:class:`ExternalDependency` provider describes dependency interface.
|
""":py:class:`ExternalDependency` provider describes dependency interface.
|
||||||
|
|
||||||
This provider is used for description of dependency interface. That might
|
This provider is used for description of dependency interface. That might
|
||||||
|
@ -286,18 +284,24 @@ class ExternalDependency(Provider):
|
||||||
:type: type
|
:type: type
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__OPTIMIZED_CALLS__ = False
|
def __init__(self, type instance_of):
|
||||||
__slots__ = ('instance_of',)
|
|
||||||
|
|
||||||
def __init__(self, instance_of):
|
|
||||||
"""Initializer."""
|
"""Initializer."""
|
||||||
if not isinstance(instance_of, six.class_types):
|
self.__instance_of = instance_of
|
||||||
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__()
|
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):
|
def __call__(self, *args, **kwargs):
|
||||||
"""Return provided instance.
|
"""Return provided instance.
|
||||||
|
|
||||||
|
@ -311,10 +315,12 @@ class ExternalDependency(Provider):
|
||||||
|
|
||||||
:rtype: object
|
:rtype: object
|
||||||
"""
|
"""
|
||||||
if not self.overridden:
|
cdef object instance
|
||||||
|
|
||||||
|
if self.__overridden_len == 0:
|
||||||
raise Error('Dependency is not defined')
|
raise Error('Dependency is not defined')
|
||||||
|
|
||||||
instance = self._call_last_overriding(*args, **kwargs)
|
instance = self._call_last_overriding(args, kwargs)
|
||||||
|
|
||||||
if not isinstance(instance, self.instance_of):
|
if not isinstance(instance, self.instance_of):
|
||||||
raise Error('{0} is not an '.format(instance) +
|
raise Error('{0} is not an '.format(instance) +
|
||||||
|
@ -322,6 +328,25 @@ class ExternalDependency(Provider):
|
||||||
|
|
||||||
return instance
|
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):
|
def provided_by(self, provider):
|
||||||
"""Set external dependency provider.
|
"""Set external dependency provider.
|
||||||
|
|
||||||
|
@ -332,17 +357,8 @@ class ExternalDependency(Provider):
|
||||||
"""
|
"""
|
||||||
return self.override(provider)
|
return self.override(provider)
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return string representation of provider.
|
|
||||||
|
|
||||||
:rtype: str
|
cdef class OverridingContext(object):
|
||||||
"""
|
|
||||||
return represent_provider(provider=self, provides=self.instance_of)
|
|
||||||
|
|
||||||
__repr__ = __str__
|
|
||||||
|
|
||||||
|
|
||||||
class OverridingContext(object):
|
|
||||||
"""Provider overriding context.
|
"""Provider overriding context.
|
||||||
|
|
||||||
:py:class:`OverridingContext` is used by :py:meth:`Provider.override` for
|
:py:class:`OverridingContext` is used by :py:meth:`Provider.override` for
|
||||||
|
@ -356,7 +372,7 @@ class OverridingContext(object):
|
||||||
assert not provider.overridden
|
assert not provider.overridden
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, overridden, overriding):
|
def __init__(self, Provider overridden, Provider overriding):
|
||||||
"""Initializer.
|
"""Initializer.
|
||||||
|
|
||||||
:param overridden: Overridden provider.
|
:param overridden: Overridden provider.
|
||||||
|
@ -365,52 +381,14 @@ class OverridingContext(object):
|
||||||
:param overriding: Overriding provider.
|
:param overriding: Overriding provider.
|
||||||
:type overriding: :py:class:`Provider`
|
:type overriding: :py:class:`Provider`
|
||||||
"""
|
"""
|
||||||
self.overridden = overridden
|
self.__overridden = overridden
|
||||||
self.overriding = overriding
|
self.__overriding = overriding
|
||||||
|
super(OverridingContext, self).__init__()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
"""Do nothing."""
|
"""Do nothing."""
|
||||||
return self.overriding
|
return self.__overriding
|
||||||
|
|
||||||
def __exit__(self, *_):
|
def __exit__(self, *_):
|
||||||
"""Exit overriding context."""
|
"""Exit overriding context."""
|
||||||
self.overridden.reset_last_overriding()
|
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))
|
|
|
@ -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
|
|
42
src/dependency_injector/providers/callables.pxd
Normal file
42
src/dependency_injector/providers/callables.pxd
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
"""Dependency injector callable providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
from .injections cimport (
|
||||||
|
PositionalInjection,
|
||||||
|
NamedInjection,
|
||||||
|
__provide_positional_args,
|
||||||
|
__provide_keyword_args,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Callable(Provider):
|
||||||
|
cdef object __provides
|
||||||
|
|
||||||
|
cdef tuple __args
|
||||||
|
cdef int __args_len
|
||||||
|
|
||||||
|
cdef tuple __kwargs
|
||||||
|
cdef int __kwargs_len
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
cdef inline object __provide(self, tuple args, dict kwargs):
|
||||||
|
cdef tuple positional_args
|
||||||
|
cdef dict keyword_args
|
||||||
|
|
||||||
|
positional_args = __provide_positional_args(args,
|
||||||
|
self.__args,
|
||||||
|
self.__args_len)
|
||||||
|
keyword_args = __provide_keyword_args(kwargs,
|
||||||
|
self.__kwargs,
|
||||||
|
self.__kwargs_len)
|
||||||
|
|
||||||
|
return self.__provides(*positional_args, **keyword_args)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedCallable(Callable):
|
||||||
|
pass
|
208
src/dependency_injector/providers/callables.pyx
Normal file
208
src/dependency_injector/providers/callables.pyx
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
"""Dependency injector callable providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
from .injections cimport (
|
||||||
|
PositionalInjection,
|
||||||
|
NamedInjection,
|
||||||
|
parse_positional_injections,
|
||||||
|
parse_named_injections,
|
||||||
|
)
|
||||||
|
from .utils cimport (
|
||||||
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Callable(Provider):
|
||||||
|
r"""Callable provider calls wrapped callable on every call.
|
||||||
|
|
||||||
|
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)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, provides, *args, **kwargs):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Wrapped callable.
|
||||||
|
:type provides: callable
|
||||||
|
|
||||||
|
:param args: Tuple of positional argument injections.
|
||||||
|
:type args: tuple[object]
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of context keyword argument injections.
|
||||||
|
:type kwargs: dict[str, object]
|
||||||
|
"""
|
||||||
|
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.__args_len = 0
|
||||||
|
self.set_args(*args)
|
||||||
|
|
||||||
|
self.__kwargs = tuple()
|
||||||
|
self.__kwargs_len = 0
|
||||||
|
self.set_kwargs(**kwargs)
|
||||||
|
|
||||||
|
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.provides,
|
||||||
|
*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):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return represent_provider(provider=self, provides=self.__provides)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provides(self):
|
||||||
|
"""Return wrapped callable."""
|
||||||
|
return self.__provides
|
||||||
|
|
||||||
|
@property
|
||||||
|
def args(self):
|
||||||
|
"""Return positional argument injections."""
|
||||||
|
cdef int index
|
||||||
|
cdef PositionalInjection arg
|
||||||
|
cdef list args
|
||||||
|
|
||||||
|
args = list()
|
||||||
|
for index in range(self.__args_len):
|
||||||
|
arg = self.__args[index]
|
||||||
|
args.append(arg.__value)
|
||||||
|
return tuple(args)
|
||||||
|
|
||||||
|
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)
|
||||||
|
self.__args_len = len(self.__args)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_args(self, *args):
|
||||||
|
"""Set postional argument injections.
|
||||||
|
|
||||||
|
Existing positional argument injections are dropped.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__args = parse_positional_injections(args)
|
||||||
|
self.__args_len = len(self.__args)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_args(self):
|
||||||
|
"""Drop postional argument injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__args = tuple()
|
||||||
|
self.__args_len = len(self.__args)
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kwargs(self):
|
||||||
|
"""Return keyword argument injections."""
|
||||||
|
cdef int index
|
||||||
|
cdef NamedInjection kwarg
|
||||||
|
cdef dict kwargs
|
||||||
|
|
||||||
|
kwargs = dict()
|
||||||
|
for index in range(self.__kwargs_len):
|
||||||
|
kwarg = self.__kwargs[index]
|
||||||
|
kwargs[kwarg.__name] = kwarg.__value
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def add_kwargs(self, **kwargs):
|
||||||
|
"""Add keyword argument injections.
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of injections.
|
||||||
|
:type kwargs: dict
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__kwargs += parse_named_injections(kwargs)
|
||||||
|
self.__kwargs_len = len(self.__kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_kwargs(self, **kwargs):
|
||||||
|
"""Set keyword argument injections.
|
||||||
|
|
||||||
|
Existing keyword argument injections are dropped.
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of injections.
|
||||||
|
:type kwargs: dict
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__kwargs = parse_named_injections(kwargs)
|
||||||
|
self.__kwargs_len = len(self.__kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_kwargs(self):
|
||||||
|
"""Drop keyword argument injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__kwargs = tuple()
|
||||||
|
self.__kwargs_len = len(self.__kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
"""Return result of provided callable's call."""
|
||||||
|
return self.__provide(args, kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedCallable(Callable):
|
||||||
|
"""Callable that is injected "as is".
|
||||||
|
|
||||||
|
DelegatedCallable is a :py:class:`Callable`, that is injected "as is".
|
||||||
|
"""
|
||||||
|
|
||||||
|
__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
|
|
33
src/dependency_injector/providers/factories.pxd
Normal file
33
src/dependency_injector/providers/factories.pxd
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
"""Dependency injector factory providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
from .callables cimport Callable
|
||||||
|
from .injections cimport __inject_attributes
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Factory(Provider):
|
||||||
|
cdef Callable __instantiator
|
||||||
|
|
||||||
|
cdef tuple __attributes
|
||||||
|
cdef int __attributes_len
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
cdef inline object __provide(self, tuple args, dict kwargs):
|
||||||
|
cdef object instance
|
||||||
|
|
||||||
|
instance = self.__instantiator.__provide(args, kwargs)
|
||||||
|
|
||||||
|
if self.__attributes_len > 0:
|
||||||
|
__inject_attributes(instance,
|
||||||
|
self.__attributes,
|
||||||
|
self.__attributes_len)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedFactory(Factory):
|
||||||
|
pass
|
270
src/dependency_injector/providers/factories.pyx
Normal file
270
src/dependency_injector/providers/factories.pyx
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
"""Dependency injector factory providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
from .callables cimport Callable
|
||||||
|
from .injections cimport (
|
||||||
|
NamedInjection,
|
||||||
|
parse_named_injections,
|
||||||
|
)
|
||||||
|
from .utils cimport (
|
||||||
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Factory(Provider):
|
||||||
|
r"""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
|
||||||
|
"""
|
||||||
|
|
||||||
|
provided_type = None
|
||||||
|
|
||||||
|
def __init__(self, provides, *args, **kwargs):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Provided type.
|
||||||
|
:type provides: type
|
||||||
|
|
||||||
|
:param args: Tuple of positional argument injections.
|
||||||
|
:type args: tuple[object]
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of context keyword argument injections.
|
||||||
|
:type kwargs: dict[str, object]
|
||||||
|
"""
|
||||||
|
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.__instantiator = Callable(provides, *args, **kwargs)
|
||||||
|
|
||||||
|
self.__attributes = tuple()
|
||||||
|
self.__attributes_len = 0
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return represent_provider(provider=self,
|
||||||
|
provides=self.__instantiator.provides)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cls(self):
|
||||||
|
"""Return provided type."""
|
||||||
|
return self.__instantiator.provides
|
||||||
|
|
||||||
|
@property
|
||||||
|
def args(self):
|
||||||
|
"""Return positional argument injections."""
|
||||||
|
return self.__instantiator.args
|
||||||
|
|
||||||
|
def add_args(self, *args):
|
||||||
|
"""Add __init__ postional argument injections.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.add_args(*args)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_args(self, *args):
|
||||||
|
"""Set __init__ postional argument injections.
|
||||||
|
|
||||||
|
Existing __init__ positional argument injections are dropped.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.set_args(*args)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_args(self):
|
||||||
|
"""Drop __init__ postional argument injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.clear_args()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kwargs(self):
|
||||||
|
"""Return keyword argument injections."""
|
||||||
|
return self.__instantiator.kwargs
|
||||||
|
|
||||||
|
def add_kwargs(self, **kwargs):
|
||||||
|
"""Add __init__ keyword argument injections.
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of injections.
|
||||||
|
:type kwargs: dict
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.add_kwargs(**kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_kwargs(self, **kwargs):
|
||||||
|
"""Set __init__ keyword argument injections.
|
||||||
|
|
||||||
|
Existing __init__ keyword argument injections are dropped.
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of injections.
|
||||||
|
:type kwargs: dict
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.set_kwargs(**kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_kwargs(self):
|
||||||
|
"""Drop __init__ keyword argument injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.clear_kwargs()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def attributes(self):
|
||||||
|
"""Return attribute injections."""
|
||||||
|
cdef int index
|
||||||
|
cdef NamedInjection attribute
|
||||||
|
cdef dict attributes
|
||||||
|
|
||||||
|
attributes = dict()
|
||||||
|
for index in range(self.__attributes_len):
|
||||||
|
attribute = self.__attributes[index]
|
||||||
|
attributes[attribute.__name] = attribute.__value
|
||||||
|
return attributes
|
||||||
|
|
||||||
|
def add_attributes(self, **kwargs):
|
||||||
|
"""Add attribute injections.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__attributes += parse_named_injections(kwargs)
|
||||||
|
self.__attributes_len = len(self.__attributes)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_attributes(self, **kwargs):
|
||||||
|
"""Set attribute injections.
|
||||||
|
|
||||||
|
Existing attribute injections are dropped.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__attributes = parse_named_injections(kwargs)
|
||||||
|
self.__attributes_len = len(self.__attributes)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_attributes(self):
|
||||||
|
"""Drop attribute injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__attributes = tuple()
|
||||||
|
self.__attributes_len = len(self.__attributes)
|
||||||
|
return self
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
"""Return new instance."""
|
||||||
|
return self.__provide(args, kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedFactory(Factory):
|
||||||
|
"""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
|
||||||
|
"""
|
||||||
|
|
||||||
|
__IS_DELEGATED__ = True
|
|
@ -6,7 +6,7 @@ Powered by Cython.
|
||||||
cimport cython
|
cimport cython
|
||||||
|
|
||||||
|
|
||||||
cdef class Injection:
|
cdef class Injection(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@ cdef class NamedInjection(Injection):
|
||||||
|
|
||||||
@cython.boundscheck(False)
|
@cython.boundscheck(False)
|
||||||
@cython.wraparound(False)
|
@cython.wraparound(False)
|
||||||
cdef inline tuple __provide_positional_args(tuple inj_args,
|
cdef inline tuple __provide_positional_args(tuple args,
|
||||||
int inj_args_len,
|
tuple inj_args,
|
||||||
tuple args):
|
int inj_args_len):
|
||||||
cdef int index
|
cdef int index
|
||||||
cdef list positional_args
|
cdef list positional_args
|
||||||
cdef PositionalInjection injection
|
cdef PositionalInjection injection
|
||||||
|
@ -53,29 +53,48 @@ cdef inline tuple __provide_positional_args(tuple inj_args,
|
||||||
positional_args = list()
|
positional_args = list()
|
||||||
for index in range(inj_args_len):
|
for index in range(inj_args_len):
|
||||||
injection = <PositionalInjection>inj_args[index]
|
injection = <PositionalInjection>inj_args[index]
|
||||||
positional_args.append(injection.get_value())
|
positional_args.append(injection.__get_value())
|
||||||
positional_args.extend(args)
|
positional_args.extend(args)
|
||||||
|
|
||||||
return positional_args
|
return tuple(positional_args)
|
||||||
|
|
||||||
|
|
||||||
@cython.boundscheck(False)
|
@cython.boundscheck(False)
|
||||||
@cython.wraparound(False)
|
@cython.wraparound(False)
|
||||||
cdef inline dict __provide_keyword_args(tuple inj_kwargs,
|
cdef inline dict __provide_keyword_args(dict kwargs,
|
||||||
int inj_kwargs_len,
|
tuple inj_kwargs,
|
||||||
dict kwargs):
|
int inj_kwargs_len):
|
||||||
cdef int index
|
cdef int index
|
||||||
|
cdef object name
|
||||||
cdef NamedInjection kw_injection
|
cdef NamedInjection kw_injection
|
||||||
|
|
||||||
if inj_kwargs_len == 0:
|
if len(kwargs) == 0:
|
||||||
return kwargs
|
for index in range(inj_kwargs_len):
|
||||||
|
kw_injection = <NamedInjection>inj_kwargs[index]
|
||||||
for index in range(inj_kwargs_len):
|
name = kw_injection.__get_name()
|
||||||
kw_injection = <NamedInjection>inj_kwargs[index]
|
kwargs[name] = kw_injection.__get_value()
|
||||||
kwargs[kw_injection.get_name()] = kw_injection.get_value()
|
else:
|
||||||
|
for index in range(inj_kwargs_len):
|
||||||
|
kw_injection = <NamedInjection>inj_kwargs[index]
|
||||||
|
name = kw_injection.__get_name()
|
||||||
|
if name not in kwargs:
|
||||||
|
kwargs[name] = kw_injection.__get_value()
|
||||||
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
@cython.boundscheck(False)
|
||||||
|
@cython.wraparound(False)
|
||||||
|
cdef inline object __inject_attributes(object instance,
|
||||||
|
tuple attributes,
|
||||||
|
int attributes_len):
|
||||||
|
cdef NamedInjection attr_injection
|
||||||
|
for index in range(attributes_len):
|
||||||
|
attr_injection = <NamedInjection>attributes[index]
|
||||||
|
setattr(instance,
|
||||||
|
attr_injection.__get_name(),
|
||||||
|
attr_injection.__get_value())
|
||||||
|
|
||||||
|
|
||||||
cpdef tuple parse_positional_injections(tuple args)
|
cpdef tuple parse_positional_injections(tuple args)
|
||||||
cpdef tuple parse_named_injections(dict kwargs)
|
cpdef tuple parse_named_injections(dict kwargs)
|
||||||
|
|
|
@ -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."""
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +24,16 @@ cdef class PositionalInjection(Injection):
|
||||||
self.__value = value
|
self.__value = value
|
||||||
self.__is_provider = <int>is_provider(value)
|
self.__is_provider = <int>is_provider(value)
|
||||||
self.__is_delegated = <int>is_delegated(value)
|
self.__is_delegated = <int>is_delegated(value)
|
||||||
self.__call = <int>self.__is_provider == 1 and self.__is_delegated == 0
|
self.__call = <int>(self.__is_provider == 1 and
|
||||||
|
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."""
|
||||||
|
@ -43,7 +53,17 @@ cdef class NamedInjection(Injection):
|
||||||
self.__value = value
|
self.__value = value
|
||||||
self.__is_provider = <int>is_provider(value)
|
self.__is_provider = <int>is_provider(value)
|
||||||
self.__is_delegated = <int>is_delegated(value)
|
self.__is_delegated = <int>is_delegated(value)
|
||||||
self.__call = <int>self.__is_provider == 1 and self.__is_delegated == 0
|
self.__call = <int>(self.__is_provider == 1 and
|
||||||
|
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."""
|
||||||
|
|
64
src/dependency_injector/providers/singletons.pxd
Normal file
64
src/dependency_injector/providers/singletons.pxd
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
"""Dependency injector singleton providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
from .factories cimport Factory
|
||||||
|
|
||||||
|
|
||||||
|
cdef class BaseSingleton(Provider):
|
||||||
|
cdef Factory __instantiator
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Singleton(BaseSingleton):
|
||||||
|
cdef object __storage
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
cdef inline object __provide(self, tuple args, dict kwargs):
|
||||||
|
if self.__storage is None:
|
||||||
|
self.__storage = self.__instantiator.__provide(args, kwargs)
|
||||||
|
return self.__storage
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedSingleton(Singleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadSafeSingleton(BaseSingleton):
|
||||||
|
cdef object __storage
|
||||||
|
cdef object __lock
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
cdef inline object __provide(self, tuple args, dict kwargs):
|
||||||
|
with self.__lock:
|
||||||
|
if self.__storage is None:
|
||||||
|
self.__storage = self.__instantiator.__provide(args, kwargs)
|
||||||
|
return self.__storage
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadLocalSingleton(BaseSingleton):
|
||||||
|
cdef object __storage
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
cdef inline object __provide(self, tuple args, dict kwargs):
|
||||||
|
cdef object instance
|
||||||
|
|
||||||
|
try:
|
||||||
|
instance = self.__storage.instance
|
||||||
|
except AttributeError:
|
||||||
|
instance = self.__instantiator.__provide(args, kwargs)
|
||||||
|
self.__storage.instance = instance
|
||||||
|
finally:
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
|
||||||
|
pass
|
393
src/dependency_injector/providers/singletons.pyx
Normal file
393
src/dependency_injector/providers/singletons.pyx
Normal file
|
@ -0,0 +1,393 @@
|
||||||
|
"""Dependency injector singleton providers.
|
||||||
|
|
||||||
|
Powered by Cython.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from dependency_injector.errors import Error
|
||||||
|
|
||||||
|
from .base cimport Provider
|
||||||
|
from .factories cimport Factory
|
||||||
|
from .utils cimport (
|
||||||
|
represent_provider,
|
||||||
|
deepcopy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
GLOBAL_LOCK = threading.RLock()
|
||||||
|
"""Global reentrant lock.
|
||||||
|
|
||||||
|
:type: :py:class:`threading.RLock`
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
cdef class BaseSingleton(Provider):
|
||||||
|
"""Base class of singleton providers."""
|
||||||
|
|
||||||
|
provided_type = None
|
||||||
|
|
||||||
|
def __init__(self, provides, *args, **kwargs):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Provided type.
|
||||||
|
:type provides: type
|
||||||
|
|
||||||
|
:param args: Tuple of positional argument injections.
|
||||||
|
:type args: tuple[object]
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of context keyword argument injections.
|
||||||
|
:type kwargs: dict[str, object]
|
||||||
|
"""
|
||||||
|
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.__instantiator = Factory(provides, *args, **kwargs)
|
||||||
|
|
||||||
|
super(BaseSingleton, self).__init__()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Return string representation of provider.
|
||||||
|
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return represent_provider(provider=self,
|
||||||
|
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
|
||||||
|
def cls(self):
|
||||||
|
"""Return provided type."""
|
||||||
|
return self.__instantiator.cls
|
||||||
|
|
||||||
|
@property
|
||||||
|
def args(self):
|
||||||
|
"""Return positional argument injections."""
|
||||||
|
return self.__instantiator.args
|
||||||
|
|
||||||
|
def add_args(self, *args):
|
||||||
|
"""Add __init__ postional argument injections.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.add_args(*args)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_args(self, *args):
|
||||||
|
"""Set __init__ postional argument injections.
|
||||||
|
|
||||||
|
Existing __init__ positional argument injections are dropped.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.set_args(*args)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_args(self):
|
||||||
|
"""Drop __init__ postional argument injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.clear_args()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kwargs(self):
|
||||||
|
"""Return keyword argument injections."""
|
||||||
|
return self.__instantiator.kwargs
|
||||||
|
|
||||||
|
def add_kwargs(self, **kwargs):
|
||||||
|
"""Add __init__ keyword argument injections.
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of injections.
|
||||||
|
:type kwargs: dict
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.add_kwargs(**kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_kwargs(self, **kwargs):
|
||||||
|
"""Set __init__ keyword argument injections.
|
||||||
|
|
||||||
|
Existing __init__ keyword argument injections are dropped.
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of injections.
|
||||||
|
:type kwargs: dict
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.set_kwargs(**kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_kwargs(self):
|
||||||
|
"""Drop __init__ keyword argument injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.clear_kwargs()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def attributes(self):
|
||||||
|
"""Return attribute injections."""
|
||||||
|
return self.__instantiator.attributes
|
||||||
|
|
||||||
|
def add_attributes(self, **kwargs):
|
||||||
|
"""Add attribute injections.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.add_attributes(**kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_attributes(self, **kwargs):
|
||||||
|
"""Set attribute injections.
|
||||||
|
|
||||||
|
Existing attribute injections are dropped.
|
||||||
|
|
||||||
|
:param args: Tuple of injections.
|
||||||
|
:type args: tuple
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.set_attributes(**kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clear_attributes(self):
|
||||||
|
"""Drop attribute injections.
|
||||||
|
|
||||||
|
:return: Reference ``self``
|
||||||
|
"""
|
||||||
|
self.__instantiator.clear_attributes()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Reset cached instance, if any.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Singleton(BaseSingleton):
|
||||||
|
"""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):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Provided type.
|
||||||
|
:type provides: type
|
||||||
|
|
||||||
|
:param args: Tuple of positional argument injections.
|
||||||
|
:type args: tuple[object]
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of context keyword argument injections.
|
||||||
|
:type kwargs: dict[str, object]
|
||||||
|
"""
|
||||||
|
self.__storage = None
|
||||||
|
super(Singleton, self).__init__(provides, *args, **kwargs)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Reset cached instance, if any.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
self.__storage = None
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
"""Return single instance."""
|
||||||
|
return self.__provide(args, kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadSafeSingleton(BaseSingleton):
|
||||||
|
"""Thread-safe singleton provider."""
|
||||||
|
|
||||||
|
def __init__(self, provides, *args, **kwargs):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Provided type.
|
||||||
|
:type provides: type
|
||||||
|
|
||||||
|
:param args: Tuple of positional argument injections.
|
||||||
|
:type args: tuple[object]
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of context keyword argument injections.
|
||||||
|
:type kwargs: dict[str, object]
|
||||||
|
"""
|
||||||
|
self.__storage = None
|
||||||
|
self.__lock = GLOBAL_LOCK
|
||||||
|
super(ThreadSafeSingleton, self).__init__(provides, *args, **kwargs)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Reset cached instance, if any.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
self.__storage = None
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
"""Return single instance."""
|
||||||
|
return self.__provide(args, kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ThreadLocalSingleton(BaseSingleton):
|
||||||
|
"""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):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param provides: Provided type.
|
||||||
|
:type provides: type
|
||||||
|
|
||||||
|
:param args: Tuple of positional argument injections.
|
||||||
|
:type args: tuple[object]
|
||||||
|
|
||||||
|
:param kwargs: Dictionary of context keyword argument injections.
|
||||||
|
:type kwargs: dict[str, object]
|
||||||
|
"""
|
||||||
|
self.__storage = threading.local()
|
||||||
|
super(ThreadLocalSingleton, self).__init__(provides, *args, **kwargs)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Reset cached instance, if any.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
self.__storage.instance = None
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
"""Return single instance."""
|
||||||
|
return self.__provide(args, kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
31
src/dependency_injector/providers/utils.h
Normal file
31
src/dependency_injector/providers/utils.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* Generated by Cython 0.25.1 */
|
||||||
|
|
||||||
|
#ifndef __PYX_HAVE__dependency_injector__providers__utils
|
||||||
|
#define __PYX_HAVE__dependency_injector__providers__utils
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __PYX_HAVE_API__dependency_injector__providers__utils
|
||||||
|
|
||||||
|
#ifndef __PYX_EXTERN_C
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define __PYX_EXTERN_C extern "C"
|
||||||
|
#else
|
||||||
|
#define __PYX_EXTERN_C extern
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DL_IMPORT
|
||||||
|
#define DL_IMPORT(_T) _T
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__PYX_EXTERN_C DL_IMPORT(PyObject) *__pyx_v_19dependency_injector_9providers_5utils_CLASS_TYPES;
|
||||||
|
|
||||||
|
#endif /* !__PYX_HAVE_API__dependency_injector__providers__utils */
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
PyMODINIT_FUNC initutils(void);
|
||||||
|
#else
|
||||||
|
PyMODINIT_FUNC PyInit_utils(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !__PYX_HAVE__dependency_injector__providers__utils */
|
|
@ -3,7 +3,11 @@
|
||||||
Powered by Cython.
|
Powered by Cython.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
cdef public object CLASS_TYPES
|
||||||
|
|
||||||
|
|
||||||
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,23 +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
|
||||||
|
|
||||||
GLOBAL_LOCK = threading.RLock()
|
|
||||||
"""Global reentrant lock.
|
|
||||||
|
|
||||||
:type: :py:class:`threading.RLock`
|
|
||||||
"""
|
|
||||||
|
|
||||||
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] = \
|
||||||
|
lambda obj, memo: type(obj)(obj.im_func,
|
||||||
|
copy.deepcopy(obj.im_self, memo),
|
||||||
|
obj.im_class)
|
||||||
|
|
||||||
|
|
||||||
cpdef bint is_provider(object instance):
|
cpdef bint is_provider(object instance):
|
||||||
|
@ -30,7 +30,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 +59,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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,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)
|
||||||
|
|
177
tests/performance/test.py
Normal file
177
tests/performance/test.py
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
"""Test providers performance."""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import gc
|
||||||
|
|
||||||
|
import dependency_injector.providers
|
||||||
|
|
||||||
|
|
||||||
|
class Tester(object):
|
||||||
|
"""Performance tester for provider module implementations."""
|
||||||
|
|
||||||
|
def __init__(self, provider_modules, duration_factor):
|
||||||
|
"""Initializer."""
|
||||||
|
self.provider_modules = provider_modules
|
||||||
|
self.tests = [getattr(self, name)
|
||||||
|
for name in dir(self)
|
||||||
|
if name.startswith('test')]
|
||||||
|
self.total_time = 0
|
||||||
|
self.duration_factor = duration_factor
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Run all tests for all provider modules."""
|
||||||
|
for module in self.provider_modules:
|
||||||
|
print('\n')
|
||||||
|
print('Running tests for module - "{module}":'
|
||||||
|
.format(module=module.__name__))
|
||||||
|
|
||||||
|
gc.disable()
|
||||||
|
for test in self.tests:
|
||||||
|
start_time = time.time()
|
||||||
|
test(module)
|
||||||
|
self.total_time = time.time() - start_time
|
||||||
|
print('Test "{test}" took - {time}'
|
||||||
|
.format(test=test.__name__,
|
||||||
|
time=self.total_time))
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
gc.enable()
|
||||||
|
print('\n')
|
||||||
|
|
||||||
|
# def test_simple_object(self, providers):
|
||||||
|
# """Test simple object's creation."""
|
||||||
|
# class Test(object):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
# Test()
|
||||||
|
#
|
||||||
|
# def test_simple_object_factory(self, providers):
|
||||||
|
# """Test simple object's factory."""
|
||||||
|
# class Test(object):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# test_factory = providers.Factory(Test)
|
||||||
|
# for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
# test_factory()
|
||||||
|
#
|
||||||
|
# def test_3_ctx_positional_injections(self, providers):
|
||||||
|
# """Test factory with 3 context positional injections."""
|
||||||
|
# class Test(object):
|
||||||
|
# def __init__(self, a, b, c):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
# Test(1, 2, 3)
|
||||||
|
#
|
||||||
|
# def test_factory_3_ctx_positional_injections(self, providers):
|
||||||
|
# """Test factory with 3 context positional injections."""
|
||||||
|
# class Test(object):
|
||||||
|
# def __init__(self, a, b, c):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# test_factory = providers.Factory(Test)
|
||||||
|
# for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
# test_factory(1, 2, 3)
|
||||||
|
|
||||||
|
def test_3_kw_injections(self, providers):
|
||||||
|
"""Test 3 keyword argument injections."""
|
||||||
|
class A(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class B(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class C(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test(object):
|
||||||
|
def __init__(self, a, b, c):
|
||||||
|
pass
|
||||||
|
|
||||||
|
for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
Test(a=A(), b=B(), c=C())
|
||||||
|
|
||||||
|
def test_factory_3_factory_kw_injections(self, providers):
|
||||||
|
"""Test factory with 3 keyword argument injections via factories."""
|
||||||
|
class A(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class B(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class C(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test(object):
|
||||||
|
def __init__(self, a, b, c):
|
||||||
|
pass
|
||||||
|
|
||||||
|
a_factory = providers.Factory(A)
|
||||||
|
b_factory = providers.Factory(B)
|
||||||
|
c_factory = providers.Factory(C)
|
||||||
|
test_factory = providers.Factory(Test,
|
||||||
|
a=a_factory,
|
||||||
|
b=b_factory,
|
||||||
|
c=c_factory)
|
||||||
|
for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
test_factory()
|
||||||
|
|
||||||
|
def test_factory_subcls_3_factory_subcls_kw_injections(self, providers):
|
||||||
|
"""Test factory with 3 keyword argument injections via factories."""
|
||||||
|
class MyFactory(providers.Factory):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class A(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class B(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class C(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test(object):
|
||||||
|
def __init__(self, a, b, c):
|
||||||
|
pass
|
||||||
|
|
||||||
|
a_factory = MyFactory(A)
|
||||||
|
b_factory = MyFactory(B)
|
||||||
|
c_factory = MyFactory(C)
|
||||||
|
test_factory = MyFactory(Test,
|
||||||
|
a=a_factory,
|
||||||
|
b=b_factory,
|
||||||
|
c=c_factory)
|
||||||
|
for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
test_factory()
|
||||||
|
|
||||||
|
# def test_singleton(self, providers):
|
||||||
|
# """Test factory with 3 keyword argument injections via factories."""
|
||||||
|
# class Test(object):
|
||||||
|
# def __init__(self):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# test_factory = providers.Singleton(Test)
|
||||||
|
# for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
# test_factory()
|
||||||
|
#
|
||||||
|
# def test_singleton_subcls(self, providers):
|
||||||
|
# """Test factory with 3 keyword argument injections via factories."""
|
||||||
|
# class MySingleton(providers.Singleton):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# class Test(object):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# test_factory = MySingleton(Test)
|
||||||
|
# for x in xrange(int(5000000 * self.duration_factor)):
|
||||||
|
# test_factory()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
tester = Tester(
|
||||||
|
provider_modules=[
|
||||||
|
dependency_injector.providers,
|
||||||
|
],
|
||||||
|
duration_factor=1)
|
||||||
|
tester.run()
|
|
@ -80,23 +80,113 @@ class ProviderTests(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEqual(self.provider.overridden, tuple())
|
self.assertEqual(self.provider.overridden, tuple())
|
||||||
|
|
||||||
|
def test_deepcopy(self):
|
||||||
|
provider = providers.Provider()
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIsInstance(provider, providers.Provider)
|
||||||
|
|
||||||
|
def test_deepcopy_from_memo(self):
|
||||||
|
provider = providers.Provider()
|
||||||
|
provider_copy_memo = providers.Provider()
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(
|
||||||
|
provider, memo={id(provider): provider_copy_memo})
|
||||||
|
|
||||||
|
self.assertIs(provider_copy, provider_copy_memo)
|
||||||
|
|
||||||
|
def test_deepcopy_overridden(self):
|
||||||
|
provider = providers.Provider()
|
||||||
|
overriding_provider = providers.Provider()
|
||||||
|
|
||||||
|
provider.override(overriding_provider)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
overriding_provider_copy = provider_copy.overridden[0]
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIsInstance(provider, providers.Provider)
|
||||||
|
|
||||||
|
self.assertIsNot(overriding_provider, overriding_provider_copy)
|
||||||
|
self.assertIsInstance(overriding_provider_copy, providers.Provider)
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
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_deepcopy(self):
|
||||||
|
provider = providers.Object(1)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIsInstance(provider, providers.Object)
|
||||||
|
|
||||||
|
def test_deepcopy_from_memo(self):
|
||||||
|
provider = providers.Object(1)
|
||||||
|
provider_copy_memo = providers.Provider()
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(
|
||||||
|
provider, memo={id(provider): provider_copy_memo})
|
||||||
|
|
||||||
|
self.assertIs(provider_copy, provider_copy_memo)
|
||||||
|
|
||||||
|
def test_deepcopy_overridden(self):
|
||||||
|
provider = providers.Object(1)
|
||||||
|
overriding_provider = providers.Provider()
|
||||||
|
|
||||||
|
provider.override(overriding_provider)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
overriding_provider_copy = provider_copy.overridden[0]
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIsInstance(provider, providers.Object)
|
||||||
|
|
||||||
|
self.assertIsNot(overriding_provider, overriding_provider_copy)
|
||||||
|
self.assertIsInstance(overriding_provider_copy, providers.Provider)
|
||||||
|
|
||||||
|
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):
|
class DelegateTests(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.delegated = providers.Provider()
|
self.delegated = providers.Provider()
|
||||||
self.delegate = providers.Delegate(delegated=self.delegated)
|
self.delegate = providers.Delegate(self.delegated)
|
||||||
|
|
||||||
def test_is_provider(self):
|
def test_is_provider(self):
|
||||||
self.assertTrue(providers.is_provider(self.delegate))
|
self.assertTrue(providers.is_provider(self.delegate))
|
||||||
|
|
||||||
def test_init_with_not_provider(self):
|
def test_init_with_not_provider(self):
|
||||||
self.assertRaises(errors.Error, providers.Delegate, delegated=object())
|
self.assertRaises(errors.Error, providers.Delegate, object())
|
||||||
|
|
||||||
def test_call(self):
|
def test_call(self):
|
||||||
delegated1 = self.delegate()
|
delegated1 = self.delegate()
|
||||||
|
@ -119,7 +209,7 @@ class ExternalDependencyTests(unittest.TestCase):
|
||||||
self.provider = providers.ExternalDependency(instance_of=list)
|
self.provider = providers.ExternalDependency(instance_of=list)
|
||||||
|
|
||||||
def test_init_with_not_class(self):
|
def test_init_with_not_class(self):
|
||||||
self.assertRaises(errors.Error, providers.ExternalDependency, object())
|
self.assertRaises(TypeError, providers.ExternalDependency, object())
|
||||||
|
|
||||||
def test_is_provider(self):
|
def test_is_provider(self):
|
||||||
self.assertTrue(providers.is_provider(self.provider))
|
self.assertTrue(providers.is_provider(self.provider))
|
||||||
|
@ -135,6 +225,38 @@ class ExternalDependencyTests(unittest.TestCase):
|
||||||
def test_call_not_overridden(self):
|
def test_call_not_overridden(self):
|
||||||
self.assertRaises(errors.Error, self.provider)
|
self.assertRaises(errors.Error, self.provider)
|
||||||
|
|
||||||
|
def test_deepcopy(self):
|
||||||
|
provider = providers.ExternalDependency(int)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIsInstance(provider, providers.ExternalDependency)
|
||||||
|
|
||||||
|
def test_deepcopy_from_memo(self):
|
||||||
|
provider = providers.ExternalDependency(int)
|
||||||
|
provider_copy_memo = providers.Provider()
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(
|
||||||
|
provider, memo={id(provider): provider_copy_memo})
|
||||||
|
|
||||||
|
self.assertIs(provider_copy, provider_copy_memo)
|
||||||
|
|
||||||
|
def test_deepcopy_overridden(self):
|
||||||
|
provider = providers.ExternalDependency(int)
|
||||||
|
overriding_provider = providers.Provider()
|
||||||
|
|
||||||
|
provider.override(overriding_provider)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
overriding_provider_copy = provider_copy.overridden[0]
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIsInstance(provider, providers.ExternalDependency)
|
||||||
|
|
||||||
|
self.assertIsNot(overriding_provider, overriding_provider_copy)
|
||||||
|
self.assertIsInstance(overriding_provider_copy, providers.Provider)
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
self.assertEqual(repr(self.provider),
|
self.assertEqual(repr(self.provider),
|
||||||
'<dependency_injector.providers.base.'
|
'<dependency_injector.providers.base.'
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
"""Dependency injector callable providers unit tests."""
|
|
||||||
|
|
||||||
import unittest2 as unittest
|
|
||||||
|
|
||||||
from dependency_injector import (
|
|
||||||
providers,
|
|
||||||
errors,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class CallableTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def example(self, arg1, arg2, arg3, arg4):
|
|
||||||
return arg1, arg2, arg3, arg4
|
|
||||||
|
|
||||||
def test_init_with_callable(self):
|
|
||||||
self.assertTrue(providers.Callable(self.example))
|
|
||||||
|
|
||||||
def test_init_with_not_callable(self):
|
|
||||||
self.assertRaises(errors.Error, providers.Callable, 123)
|
|
||||||
|
|
||||||
def test_call(self):
|
|
||||||
provider = providers.Callable(lambda: True)
|
|
||||||
self.assertTrue(provider())
|
|
||||||
|
|
||||||
def test_call_with_positional_args(self):
|
|
||||||
provider = providers.Callable(self.example,
|
|
||||||
1, 2, 3, 4)
|
|
||||||
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_call_with_keyword_args(self):
|
|
||||||
provider = providers.Callable(self.example,
|
|
||||||
arg1=1, arg2=2, arg3=3, arg4=4)
|
|
||||||
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_call_with_positional_and_keyword_args(self):
|
|
||||||
provider = providers.Callable(self.example,
|
|
||||||
1, 2,
|
|
||||||
arg3=3, arg4=4)
|
|
||||||
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_call_with_context_args(self):
|
|
||||||
provider = providers.Callable(self.example, 1, 2)
|
|
||||||
self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_call_with_context_kwargs(self):
|
|
||||||
provider = providers.Callable(self.example, arg1=1)
|
|
||||||
self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_call_with_context_args_and_kwargs(self):
|
|
||||||
provider = providers.Callable(self.example, 1)
|
|
||||||
self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_fluent_interface(self):
|
|
||||||
provider = providers.Singleton(self.example) \
|
|
||||||
.add_args(1, 2) \
|
|
||||||
.add_kwargs(arg3=3, arg4=4)
|
|
||||||
|
|
||||||
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_call_overridden(self):
|
|
||||||
provider = providers.Callable(self.example)
|
|
||||||
|
|
||||||
provider.override(providers.Object((4, 3, 2, 1)))
|
|
||||||
provider.override(providers.Object((1, 2, 3, 4)))
|
|
||||||
|
|
||||||
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
provider = providers.Callable(self.example)
|
|
||||||
|
|
||||||
self.assertEqual(repr(provider),
|
|
||||||
'<dependency_injector.providers.callable.'
|
|
||||||
'Callable({0}) at {1}>'.format(
|
|
||||||
repr(self.example),
|
|
||||||
hex(id(provider))))
|
|
||||||
|
|
||||||
|
|
||||||
class DelegatedCallableTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_inheritance(self):
|
|
||||||
self.assertIsInstance(providers.DelegatedCallable(len),
|
|
||||||
providers.Callable)
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(
|
|
||||||
providers.is_provider(providers.DelegatedCallable(len)))
|
|
||||||
|
|
||||||
def test_is_delegated_provider(self):
|
|
||||||
provider = providers.DelegatedCallable(len)
|
|
||||||
self.assertIs(provider.provide_injection(), provider)
|
|
191
tests/unit/providers/test_callables.py
Normal file
191
tests/unit/providers/test_callables.py
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
"""Dependency injector callable providers unit tests."""
|
||||||
|
|
||||||
|
import unittest2 as unittest
|
||||||
|
|
||||||
|
from dependency_injector import (
|
||||||
|
providers,
|
||||||
|
errors,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CallableTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def example(self, arg1, arg2, arg3, arg4):
|
||||||
|
return arg1, arg2, arg3, arg4
|
||||||
|
|
||||||
|
def test_init_with_callable(self):
|
||||||
|
self.assertTrue(providers.Callable(self.example))
|
||||||
|
|
||||||
|
def test_init_with_not_callable(self):
|
||||||
|
self.assertRaises(errors.Error, providers.Callable, 123)
|
||||||
|
|
||||||
|
def test_call(self):
|
||||||
|
provider = providers.Callable(lambda: True)
|
||||||
|
self.assertTrue(provider())
|
||||||
|
|
||||||
|
def test_call_with_positional_args(self):
|
||||||
|
provider = providers.Callable(self.example,
|
||||||
|
1, 2, 3, 4)
|
||||||
|
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_keyword_args(self):
|
||||||
|
provider = providers.Callable(self.example,
|
||||||
|
arg1=1, arg2=2, arg3=3, arg4=4)
|
||||||
|
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_positional_and_keyword_args(self):
|
||||||
|
provider = providers.Callable(self.example,
|
||||||
|
1, 2,
|
||||||
|
arg3=3, arg4=4)
|
||||||
|
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_context_args(self):
|
||||||
|
provider = providers.Callable(self.example, 1, 2)
|
||||||
|
self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_context_kwargs(self):
|
||||||
|
provider = providers.Callable(self.example, arg1=1)
|
||||||
|
self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_context_args_and_kwargs(self):
|
||||||
|
provider = providers.Callable(self.example, 1)
|
||||||
|
self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_fluent_interface(self):
|
||||||
|
provider = providers.Singleton(self.example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.add_kwargs(arg3=3, arg4=4)
|
||||||
|
|
||||||
|
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_set_args(self):
|
||||||
|
provider = providers.Callable(self.example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.set_args(3, 4)
|
||||||
|
self.assertEqual(provider.args, tuple([3, 4]))
|
||||||
|
|
||||||
|
def test_set_kwargs(self):
|
||||||
|
provider = providers.Callable(self.example) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.set_kwargs(init_arg3=4, init_arg4=5)
|
||||||
|
self.assertEqual(provider.kwargs, dict(init_arg3=4, init_arg4=5))
|
||||||
|
|
||||||
|
def test_clear_args(self):
|
||||||
|
provider = providers.Callable(self.example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.clear_args()
|
||||||
|
self.assertEqual(provider.args, tuple())
|
||||||
|
|
||||||
|
def test_clear_kwargs(self):
|
||||||
|
provider = providers.Callable(self.example) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.clear_kwargs()
|
||||||
|
self.assertEqual(provider.kwargs, dict())
|
||||||
|
|
||||||
|
def test_call_overridden(self):
|
||||||
|
provider = providers.Callable(self.example)
|
||||||
|
|
||||||
|
provider.override(providers.Object((4, 3, 2, 1)))
|
||||||
|
provider.override(providers.Object((1, 2, 3, 4)))
|
||||||
|
|
||||||
|
self.assertTupleEqual(provider(), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_deepcopy(self):
|
||||||
|
provider = providers.Callable(self.example)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIs(provider.provides, provider_copy.provides)
|
||||||
|
self.assertIsInstance(provider, providers.Callable)
|
||||||
|
|
||||||
|
def test_deepcopy_from_memo(self):
|
||||||
|
provider = providers.Callable(self.example)
|
||||||
|
provider_copy_memo = providers.Callable(self.example)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(
|
||||||
|
provider, memo={id(provider): provider_copy_memo})
|
||||||
|
|
||||||
|
self.assertIs(provider_copy, provider_copy_memo)
|
||||||
|
|
||||||
|
def test_deepcopy_args(self):
|
||||||
|
provider = providers.Callable(self.example)
|
||||||
|
dependent_provider1 = providers.Callable(list)
|
||||||
|
dependent_provider2 = providers.Callable(dict)
|
||||||
|
|
||||||
|
provider.add_args(dependent_provider1, dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.args[0]
|
||||||
|
dependent_provider_copy2 = provider_copy.args[1]
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.args, provider_copy.args)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.provides,
|
||||||
|
dependent_provider_copy1.provides)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.provides,
|
||||||
|
dependent_provider_copy2.provides)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_kwargs(self):
|
||||||
|
provider = providers.Callable(self.example)
|
||||||
|
dependent_provider1 = providers.Callable(list)
|
||||||
|
dependent_provider2 = providers.Callable(dict)
|
||||||
|
|
||||||
|
provider.add_kwargs(a1=dependent_provider1, a2=dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.kwargs['a1']
|
||||||
|
dependent_provider_copy2 = provider_copy.kwargs['a2']
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.kwargs, provider_copy.kwargs)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.provides,
|
||||||
|
dependent_provider_copy1.provides)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.provides,
|
||||||
|
dependent_provider_copy2.provides)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_overridden(self):
|
||||||
|
provider = providers.Callable(self.example)
|
||||||
|
object_provider = providers.Object(object())
|
||||||
|
|
||||||
|
provider.override(object_provider)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
object_provider_copy = provider_copy.overridden[0]
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIs(provider.provides, provider_copy.provides)
|
||||||
|
self.assertIsInstance(provider, providers.Callable)
|
||||||
|
|
||||||
|
self.assertIsNot(object_provider, object_provider_copy)
|
||||||
|
self.assertIsInstance(object_provider_copy, providers.Object)
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = providers.Callable(self.example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.callables.'
|
||||||
|
'Callable({0}) at {1}>'.format(
|
||||||
|
repr(self.example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegatedCallableTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_inheritance(self):
|
||||||
|
self.assertIsInstance(providers.DelegatedCallable(len),
|
||||||
|
providers.Callable)
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(
|
||||||
|
providers.is_provider(providers.DelegatedCallable(len)))
|
||||||
|
|
||||||
|
def test_is_delegated_provider(self):
|
||||||
|
provider = providers.DelegatedCallable(len)
|
||||||
|
self.assertTrue(providers.is_delegated(provider))
|
|
@ -1,662 +0,0 @@
|
||||||
"""Dependency injector creational providers unit tests."""
|
|
||||||
|
|
||||||
import unittest2 as unittest
|
|
||||||
|
|
||||||
from dependency_injector import (
|
|
||||||
providers,
|
|
||||||
errors,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Example(object):
|
|
||||||
|
|
||||||
def __init__(self, init_arg1=None, init_arg2=None, init_arg3=None,
|
|
||||||
init_arg4=None):
|
|
||||||
self.init_arg1 = init_arg1
|
|
||||||
self.init_arg2 = init_arg2
|
|
||||||
self.init_arg3 = init_arg3
|
|
||||||
self.init_arg4 = init_arg4
|
|
||||||
|
|
||||||
self.attribute1 = None
|
|
||||||
self.attribute2 = None
|
|
||||||
|
|
||||||
|
|
||||||
class FactoryTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(providers.is_provider(providers.Factory(Example)))
|
|
||||||
|
|
||||||
def test_init_with_callable(self):
|
|
||||||
self.assertTrue(providers.Factory(credits))
|
|
||||||
|
|
||||||
def test_init_with_not_callable(self):
|
|
||||||
self.assertRaises(errors.Error, providers.Factory, 123)
|
|
||||||
|
|
||||||
def test_init_with_valid_provided_type(self):
|
|
||||||
class ExampleProvider(providers.Factory):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
example_provider = ExampleProvider(Example, 1, 2)
|
|
||||||
|
|
||||||
self.assertIsInstance(example_provider(), Example)
|
|
||||||
|
|
||||||
def test_init_with_valid_provided_subtype(self):
|
|
||||||
class ExampleProvider(providers.Factory):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
class NewExampe(Example):
|
|
||||||
pass
|
|
||||||
|
|
||||||
example_provider = ExampleProvider(NewExampe, 1, 2)
|
|
||||||
|
|
||||||
self.assertIsInstance(example_provider(), NewExampe)
|
|
||||||
|
|
||||||
def test_init_with_invalid_provided_type(self):
|
|
||||||
class ExampleProvider(providers.Factory):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
with self.assertRaises(errors.Error):
|
|
||||||
ExampleProvider(list)
|
|
||||||
|
|
||||||
def test_call(self):
|
|
||||||
provider = providers.Factory(Example)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_positional_args(self):
|
|
||||||
provider = providers.Factory(Example, 'i1', 'i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_keyword_args(self):
|
|
||||||
provider = providers.Factory(Example, init_arg1='i1', init_arg2='i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_positional_and_keyword_args(self):
|
|
||||||
provider = providers.Factory(Example, 'i1', init_arg2='i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_attributes(self):
|
|
||||||
provider = providers.Factory(Example)
|
|
||||||
provider.add_attributes(attribute1='a1', attribute2='a2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.attribute1, 'a1')
|
|
||||||
self.assertEqual(instance1.attribute2, 'a2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.attribute1, 'a1')
|
|
||||||
self.assertEqual(instance2.attribute2, 'a2')
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_context_args(self):
|
|
||||||
provider = providers.Factory(Example, 11, 22)
|
|
||||||
|
|
||||||
instance = provider(33, 44)
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 11)
|
|
||||||
self.assertEqual(instance.init_arg2, 22)
|
|
||||||
self.assertEqual(instance.init_arg3, 33)
|
|
||||||
self.assertEqual(instance.init_arg4, 44)
|
|
||||||
|
|
||||||
def test_call_with_context_kwargs(self):
|
|
||||||
provider = providers.Factory(Example, init_arg1=1)
|
|
||||||
|
|
||||||
instance1 = provider(init_arg2=22)
|
|
||||||
self.assertEqual(instance1.init_arg1, 1)
|
|
||||||
self.assertEqual(instance1.init_arg2, 22)
|
|
||||||
|
|
||||||
instance2 = provider(init_arg1=11, init_arg2=22)
|
|
||||||
self.assertEqual(instance2.init_arg1, 11)
|
|
||||||
self.assertEqual(instance2.init_arg2, 22)
|
|
||||||
|
|
||||||
def test_call_with_context_args_and_kwargs(self):
|
|
||||||
provider = providers.Factory(Example, 11)
|
|
||||||
|
|
||||||
instance = provider(22, init_arg3=33, init_arg4=44)
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 11)
|
|
||||||
self.assertEqual(instance.init_arg2, 22)
|
|
||||||
self.assertEqual(instance.init_arg3, 33)
|
|
||||||
self.assertEqual(instance.init_arg4, 44)
|
|
||||||
|
|
||||||
def test_fluent_interface(self):
|
|
||||||
provider = providers.Factory(Example) \
|
|
||||||
.add_args(1, 2) \
|
|
||||||
.add_kwargs(init_arg3=3, init_arg4=4) \
|
|
||||||
.add_attributes(attribute1=5, attribute2=6)
|
|
||||||
|
|
||||||
instance = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 1)
|
|
||||||
self.assertEqual(instance.init_arg2, 2)
|
|
||||||
self.assertEqual(instance.init_arg3, 3)
|
|
||||||
self.assertEqual(instance.init_arg4, 4)
|
|
||||||
self.assertEqual(instance.attribute1, 5)
|
|
||||||
self.assertEqual(instance.attribute2, 6)
|
|
||||||
|
|
||||||
def test_call_overridden(self):
|
|
||||||
provider = providers.Factory(Example)
|
|
||||||
overriding_provider1 = providers.Factory(dict)
|
|
||||||
overriding_provider2 = providers.Factory(list)
|
|
||||||
|
|
||||||
provider.override(overriding_provider1)
|
|
||||||
provider.override(overriding_provider2)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, list)
|
|
||||||
self.assertIsInstance(instance2, list)
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
provider = providers.Factory(Example)
|
|
||||||
|
|
||||||
self.assertEqual(repr(provider),
|
|
||||||
'<dependency_injector.providers.creational.'
|
|
||||||
'Factory({0}) at {1}>'.format(
|
|
||||||
repr(Example),
|
|
||||||
hex(id(provider))))
|
|
||||||
|
|
||||||
|
|
||||||
class DelegatedFactoryTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_inheritance(self):
|
|
||||||
self.assertIsInstance(providers.DelegatedFactory(object),
|
|
||||||
providers.Factory)
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(
|
|
||||||
providers.is_provider(providers.DelegatedFactory(object)))
|
|
||||||
|
|
||||||
def test_is_delegated_provider(self):
|
|
||||||
provider = providers.DelegatedFactory(object)
|
|
||||||
self.assertIs(provider.provide_injection(), provider)
|
|
||||||
|
|
||||||
|
|
||||||
class SingletonTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(providers.is_provider(providers.Singleton(Example)))
|
|
||||||
|
|
||||||
def test_init_with_callable(self):
|
|
||||||
self.assertTrue(providers.Singleton(credits))
|
|
||||||
|
|
||||||
def test_init_with_not_callable(self):
|
|
||||||
self.assertRaises(errors.Error, providers.Singleton, 123)
|
|
||||||
|
|
||||||
def test_init_with_valid_provided_type(self):
|
|
||||||
class ExampleProvider(providers.Singleton):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
example_provider = ExampleProvider(Example, 1, 2)
|
|
||||||
|
|
||||||
self.assertIsInstance(example_provider(), Example)
|
|
||||||
|
|
||||||
def test_init_with_valid_provided_subtype(self):
|
|
||||||
class ExampleProvider(providers.Singleton):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
class NewExampe(Example):
|
|
||||||
pass
|
|
||||||
|
|
||||||
example_provider = ExampleProvider(NewExampe, 1, 2)
|
|
||||||
|
|
||||||
self.assertIsInstance(example_provider(), NewExampe)
|
|
||||||
|
|
||||||
def test_init_with_invalid_provided_type(self):
|
|
||||||
class ExampleProvider(providers.Singleton):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
with self.assertRaises(errors.Error):
|
|
||||||
ExampleProvider(list)
|
|
||||||
|
|
||||||
def test_call(self):
|
|
||||||
provider = providers.Singleton(Example)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_positional_args(self):
|
|
||||||
provider = providers.Singleton(Example, 'i1', 'i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_keyword_args(self):
|
|
||||||
provider = providers.Singleton(Example, init_arg1='i1', init_arg2='i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_positional_and_keyword_args(self):
|
|
||||||
provider = providers.Singleton(Example, 'i1', init_arg2='i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_attributes(self):
|
|
||||||
provider = providers.Singleton(Example)
|
|
||||||
provider.add_attributes(attribute1='a1', attribute2='a2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.attribute1, 'a1')
|
|
||||||
self.assertEqual(instance1.attribute2, 'a2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.attribute1, 'a1')
|
|
||||||
self.assertEqual(instance2.attribute2, 'a2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_context_args(self):
|
|
||||||
provider = providers.Singleton(Example)
|
|
||||||
|
|
||||||
instance = provider(11, 22)
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 11)
|
|
||||||
self.assertEqual(instance.init_arg2, 22)
|
|
||||||
|
|
||||||
def test_call_with_context_kwargs(self):
|
|
||||||
provider = providers.Singleton(Example, init_arg1=1)
|
|
||||||
|
|
||||||
instance1 = provider(init_arg2=22)
|
|
||||||
self.assertEqual(instance1.init_arg1, 1)
|
|
||||||
self.assertEqual(instance1.init_arg2, 22)
|
|
||||||
|
|
||||||
# Instance is created earlier
|
|
||||||
instance1 = provider(init_arg1=11, init_arg2=22)
|
|
||||||
self.assertEqual(instance1.init_arg1, 1)
|
|
||||||
self.assertEqual(instance1.init_arg2, 22)
|
|
||||||
|
|
||||||
def test_call_with_context_args_and_kwargs(self):
|
|
||||||
provider = providers.Singleton(Example, 11)
|
|
||||||
|
|
||||||
instance = provider(22, init_arg3=33, init_arg4=44)
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 11)
|
|
||||||
self.assertEqual(instance.init_arg2, 22)
|
|
||||||
self.assertEqual(instance.init_arg3, 33)
|
|
||||||
self.assertEqual(instance.init_arg4, 44)
|
|
||||||
|
|
||||||
def test_fluent_interface(self):
|
|
||||||
provider = providers.Singleton(Example) \
|
|
||||||
.add_args(1, 2) \
|
|
||||||
.add_kwargs(init_arg3=3, init_arg4=4) \
|
|
||||||
.add_attributes(attribute1=5, attribute2=6)
|
|
||||||
|
|
||||||
instance = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 1)
|
|
||||||
self.assertEqual(instance.init_arg2, 2)
|
|
||||||
self.assertEqual(instance.init_arg3, 3)
|
|
||||||
self.assertEqual(instance.init_arg4, 4)
|
|
||||||
self.assertEqual(instance.attribute1, 5)
|
|
||||||
self.assertEqual(instance.attribute2, 6)
|
|
||||||
|
|
||||||
def test_call_overridden(self):
|
|
||||||
provider = providers.Singleton(Example)
|
|
||||||
overriding_provider1 = providers.Singleton(dict)
|
|
||||||
overriding_provider2 = providers.Singleton(object)
|
|
||||||
|
|
||||||
provider.override(overriding_provider1)
|
|
||||||
provider.override(overriding_provider2)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, object)
|
|
||||||
self.assertIsInstance(instance2, object)
|
|
||||||
|
|
||||||
def test_reset(self):
|
|
||||||
provider = providers.Singleton(object)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
self.assertIsInstance(instance1, object)
|
|
||||||
|
|
||||||
provider.reset()
|
|
||||||
|
|
||||||
instance2 = provider()
|
|
||||||
self.assertIsInstance(instance1, object)
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
provider = providers.Singleton(Example)
|
|
||||||
|
|
||||||
self.assertEqual(repr(provider),
|
|
||||||
'<dependency_injector.providers.creational.'
|
|
||||||
'Singleton({0}) at {1}>'.format(
|
|
||||||
repr(Example),
|
|
||||||
hex(id(provider))))
|
|
||||||
|
|
||||||
|
|
||||||
class DelegatedSingletonTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_inheritance(self):
|
|
||||||
self.assertIsInstance(providers.DelegatedSingleton(object),
|
|
||||||
providers.Singleton)
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(
|
|
||||||
providers.is_provider(providers.DelegatedSingleton(object)))
|
|
||||||
|
|
||||||
def test_is_delegated_provider(self):
|
|
||||||
provider = providers.DelegatedSingleton(object)
|
|
||||||
self.assertIs(provider.provide_injection(), provider)
|
|
||||||
|
|
||||||
|
|
||||||
class ThreadLocalSingletonTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(
|
|
||||||
providers.is_provider(providers.ThreadLocalSingleton(Example)))
|
|
||||||
|
|
||||||
def test_init_with_callable(self):
|
|
||||||
self.assertTrue(providers.ThreadLocalSingleton(credits))
|
|
||||||
|
|
||||||
def test_init_with_not_callable(self):
|
|
||||||
self.assertRaises(errors.Error, providers.ThreadLocalSingleton, 123)
|
|
||||||
|
|
||||||
def test_init_with_valid_provided_type(self):
|
|
||||||
class ExampleProvider(providers.ThreadLocalSingleton):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
example_provider = ExampleProvider(Example, 1, 2)
|
|
||||||
|
|
||||||
self.assertIsInstance(example_provider(), Example)
|
|
||||||
|
|
||||||
def test_init_with_valid_provided_subtype(self):
|
|
||||||
class ExampleProvider(providers.ThreadLocalSingleton):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
class NewExampe(Example):
|
|
||||||
pass
|
|
||||||
|
|
||||||
example_provider = ExampleProvider(NewExampe, 1, 2)
|
|
||||||
|
|
||||||
self.assertIsInstance(example_provider(), NewExampe)
|
|
||||||
|
|
||||||
def test_init_with_invalid_provided_type(self):
|
|
||||||
class ExampleProvider(providers.ThreadLocalSingleton):
|
|
||||||
provided_type = Example
|
|
||||||
|
|
||||||
with self.assertRaises(errors.Error):
|
|
||||||
ExampleProvider(list)
|
|
||||||
|
|
||||||
def test_call(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_positional_args(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example, 'i1', 'i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_keyword_args(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example,
|
|
||||||
init_arg1='i1',
|
|
||||||
init_arg2='i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_init_positional_and_keyword_args(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example,
|
|
||||||
'i1',
|
|
||||||
init_arg2='i2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance1.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.init_arg1, 'i1')
|
|
||||||
self.assertEqual(instance2.init_arg2, 'i2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_attributes(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example)
|
|
||||||
provider.add_attributes(attribute1='a1', attribute2='a2')
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance1.attribute1, 'a1')
|
|
||||||
self.assertEqual(instance1.attribute2, 'a2')
|
|
||||||
|
|
||||||
self.assertEqual(instance2.attribute1, 'a1')
|
|
||||||
self.assertEqual(instance2.attribute2, 'a2')
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, Example)
|
|
||||||
self.assertIsInstance(instance2, Example)
|
|
||||||
|
|
||||||
def test_call_with_context_args(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example)
|
|
||||||
|
|
||||||
instance = provider(11, 22)
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 11)
|
|
||||||
self.assertEqual(instance.init_arg2, 22)
|
|
||||||
|
|
||||||
def test_call_with_context_kwargs(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example, init_arg1=1)
|
|
||||||
|
|
||||||
instance1 = provider(init_arg2=22)
|
|
||||||
self.assertEqual(instance1.init_arg1, 1)
|
|
||||||
self.assertEqual(instance1.init_arg2, 22)
|
|
||||||
|
|
||||||
# Instance is created earlier
|
|
||||||
instance1 = provider(init_arg1=11, init_arg2=22)
|
|
||||||
self.assertEqual(instance1.init_arg1, 1)
|
|
||||||
self.assertEqual(instance1.init_arg2, 22)
|
|
||||||
|
|
||||||
def test_call_with_context_args_and_kwargs(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example, 11)
|
|
||||||
|
|
||||||
instance = provider(22, init_arg3=33, init_arg4=44)
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 11)
|
|
||||||
self.assertEqual(instance.init_arg2, 22)
|
|
||||||
self.assertEqual(instance.init_arg3, 33)
|
|
||||||
self.assertEqual(instance.init_arg4, 44)
|
|
||||||
|
|
||||||
def test_fluent_interface(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example) \
|
|
||||||
.add_args(1, 2) \
|
|
||||||
.add_kwargs(init_arg3=3, init_arg4=4) \
|
|
||||||
.add_attributes(attribute1=5, attribute2=6)
|
|
||||||
|
|
||||||
instance = provider()
|
|
||||||
|
|
||||||
self.assertEqual(instance.init_arg1, 1)
|
|
||||||
self.assertEqual(instance.init_arg2, 2)
|
|
||||||
self.assertEqual(instance.init_arg3, 3)
|
|
||||||
self.assertEqual(instance.init_arg4, 4)
|
|
||||||
self.assertEqual(instance.attribute1, 5)
|
|
||||||
self.assertEqual(instance.attribute2, 6)
|
|
||||||
|
|
||||||
def test_call_overridden(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example)
|
|
||||||
overriding_provider1 = providers.ThreadLocalSingleton(dict)
|
|
||||||
overriding_provider2 = providers.ThreadLocalSingleton(object)
|
|
||||||
|
|
||||||
provider.override(overriding_provider1)
|
|
||||||
provider.override(overriding_provider2)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
instance2 = provider()
|
|
||||||
|
|
||||||
self.assertIs(instance1, instance2)
|
|
||||||
self.assertIsInstance(instance1, object)
|
|
||||||
self.assertIsInstance(instance2, object)
|
|
||||||
|
|
||||||
def test_reset(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(object)
|
|
||||||
|
|
||||||
instance1 = provider()
|
|
||||||
self.assertIsInstance(instance1, object)
|
|
||||||
|
|
||||||
provider.reset()
|
|
||||||
|
|
||||||
instance2 = provider()
|
|
||||||
self.assertIsInstance(instance1, object)
|
|
||||||
|
|
||||||
self.assertIsNot(instance1, instance2)
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
provider = providers.ThreadLocalSingleton(Example)
|
|
||||||
|
|
||||||
self.assertEqual(repr(provider),
|
|
||||||
'<dependency_injector.providers.creational.'
|
|
||||||
'ThreadLocalSingleton({0}) at {1}>'.format(
|
|
||||||
repr(Example),
|
|
||||||
hex(id(provider))))
|
|
||||||
|
|
||||||
|
|
||||||
class DelegatedThreadLocalSingletonTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_inheritance(self):
|
|
||||||
self.assertIsInstance(providers.DelegatedThreadLocalSingleton(object),
|
|
||||||
providers.ThreadLocalSingleton)
|
|
||||||
|
|
||||||
def test_is_provider(self):
|
|
||||||
self.assertTrue(
|
|
||||||
providers.is_provider(
|
|
||||||
providers.DelegatedThreadLocalSingleton(object)))
|
|
||||||
|
|
||||||
def test_is_delegated_provider(self):
|
|
||||||
provider = providers.DelegatedThreadLocalSingleton(object)
|
|
||||||
self.assertIs(provider.provide_injection(), provider)
|
|
||||||
|
|
||||||
|
|
||||||
class FactoryAsDecoratorTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_decoration_and_overriding(self):
|
|
||||||
@providers.Factory
|
|
||||||
class AuthService(object):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@providers.override(AuthService)
|
|
||||||
@providers.Factory
|
|
||||||
class ExtAuthService(AuthService.cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
auth_service = AuthService()
|
|
||||||
|
|
||||||
self.assertIsInstance(auth_service, ExtAuthService.cls)
|
|
346
tests/unit/providers/test_factories.py
Normal file
346
tests/unit/providers/test_factories.py
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
"""Dependency injector factory providers unit tests."""
|
||||||
|
|
||||||
|
import unittest2 as unittest
|
||||||
|
|
||||||
|
from dependency_injector import (
|
||||||
|
providers,
|
||||||
|
errors,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Example(object):
|
||||||
|
|
||||||
|
def __init__(self, init_arg1=None, init_arg2=None, init_arg3=None,
|
||||||
|
init_arg4=None):
|
||||||
|
self.init_arg1 = init_arg1
|
||||||
|
self.init_arg2 = init_arg2
|
||||||
|
self.init_arg3 = init_arg3
|
||||||
|
self.init_arg4 = init_arg4
|
||||||
|
|
||||||
|
self.attribute1 = None
|
||||||
|
self.attribute2 = None
|
||||||
|
|
||||||
|
|
||||||
|
class FactoryTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(providers.is_provider(providers.Factory(Example)))
|
||||||
|
|
||||||
|
def test_init_with_callable(self):
|
||||||
|
self.assertTrue(providers.Factory(credits))
|
||||||
|
|
||||||
|
def test_init_with_not_callable(self):
|
||||||
|
self.assertRaises(errors.Error, providers.Factory, 123)
|
||||||
|
|
||||||
|
def test_init_with_valid_provided_type(self):
|
||||||
|
class ExampleProvider(providers.Factory):
|
||||||
|
provided_type = Example
|
||||||
|
|
||||||
|
example_provider = ExampleProvider(Example, 1, 2)
|
||||||
|
|
||||||
|
self.assertIsInstance(example_provider(), Example)
|
||||||
|
|
||||||
|
def test_init_with_valid_provided_subtype(self):
|
||||||
|
class ExampleProvider(providers.Factory):
|
||||||
|
provided_type = Example
|
||||||
|
|
||||||
|
class NewExampe(Example):
|
||||||
|
pass
|
||||||
|
|
||||||
|
example_provider = ExampleProvider(NewExampe, 1, 2)
|
||||||
|
|
||||||
|
self.assertIsInstance(example_provider(), NewExampe)
|
||||||
|
|
||||||
|
def test_init_with_invalid_provided_type(self):
|
||||||
|
class ExampleProvider(providers.Factory):
|
||||||
|
provided_type = Example
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
ExampleProvider(list)
|
||||||
|
|
||||||
|
def test_call(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertIsNot(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_init_positional_args(self):
|
||||||
|
provider = providers.Factory(Example, 'i1', 'i2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance1.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance2.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertIsNot(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_init_keyword_args(self):
|
||||||
|
provider = providers.Factory(Example, init_arg1='i1', init_arg2='i2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance1.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance2.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertIsNot(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_init_positional_and_keyword_args(self):
|
||||||
|
provider = providers.Factory(Example, 'i1', init_arg2='i2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance1.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance2.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertIsNot(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_attributes(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
provider.add_attributes(attribute1='a1', attribute2='a2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.attribute1, 'a1')
|
||||||
|
self.assertEqual(instance1.attribute2, 'a2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.attribute1, 'a1')
|
||||||
|
self.assertEqual(instance2.attribute2, 'a2')
|
||||||
|
|
||||||
|
self.assertIsNot(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_context_args(self):
|
||||||
|
provider = providers.Factory(Example, 11, 22)
|
||||||
|
|
||||||
|
instance = provider(33, 44)
|
||||||
|
|
||||||
|
self.assertEqual(instance.init_arg1, 11)
|
||||||
|
self.assertEqual(instance.init_arg2, 22)
|
||||||
|
self.assertEqual(instance.init_arg3, 33)
|
||||||
|
self.assertEqual(instance.init_arg4, 44)
|
||||||
|
|
||||||
|
def test_call_with_context_kwargs(self):
|
||||||
|
provider = providers.Factory(Example, init_arg1=1)
|
||||||
|
|
||||||
|
instance1 = provider(init_arg2=22)
|
||||||
|
self.assertEqual(instance1.init_arg1, 1)
|
||||||
|
self.assertEqual(instance1.init_arg2, 22)
|
||||||
|
|
||||||
|
instance2 = provider(init_arg1=11, init_arg2=22)
|
||||||
|
self.assertEqual(instance2.init_arg1, 11)
|
||||||
|
self.assertEqual(instance2.init_arg2, 22)
|
||||||
|
|
||||||
|
def test_call_with_context_args_and_kwargs(self):
|
||||||
|
provider = providers.Factory(Example, 11)
|
||||||
|
|
||||||
|
instance = provider(22, init_arg3=33, init_arg4=44)
|
||||||
|
|
||||||
|
self.assertEqual(instance.init_arg1, 11)
|
||||||
|
self.assertEqual(instance.init_arg2, 22)
|
||||||
|
self.assertEqual(instance.init_arg3, 33)
|
||||||
|
self.assertEqual(instance.init_arg4, 44)
|
||||||
|
|
||||||
|
def test_fluent_interface(self):
|
||||||
|
provider = providers.Factory(Example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.add_attributes(attribute1=5, attribute2=6)
|
||||||
|
|
||||||
|
instance = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance.init_arg1, 1)
|
||||||
|
self.assertEqual(instance.init_arg2, 2)
|
||||||
|
self.assertEqual(instance.init_arg3, 3)
|
||||||
|
self.assertEqual(instance.init_arg4, 4)
|
||||||
|
self.assertEqual(instance.attribute1, 5)
|
||||||
|
self.assertEqual(instance.attribute2, 6)
|
||||||
|
|
||||||
|
def test_set_args(self):
|
||||||
|
provider = providers.Factory(Example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.set_args(3, 4)
|
||||||
|
self.assertEqual(provider.args, tuple([3, 4]))
|
||||||
|
|
||||||
|
def test_set_kwargs(self):
|
||||||
|
provider = providers.Factory(Example) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.set_kwargs(init_arg3=4, init_arg4=5)
|
||||||
|
self.assertEqual(provider.kwargs, dict(init_arg3=4, init_arg4=5))
|
||||||
|
|
||||||
|
def test_set_attributes(self):
|
||||||
|
provider = providers.Factory(Example) \
|
||||||
|
.add_attributes(attribute1=5, attribute2=6) \
|
||||||
|
.set_attributes(attribute1=6, attribute2=7)
|
||||||
|
self.assertEqual(provider.attributes, dict(attribute1=6, attribute2=7))
|
||||||
|
|
||||||
|
def test_clear_args(self):
|
||||||
|
provider = providers.Factory(Example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.clear_args()
|
||||||
|
self.assertEqual(provider.args, tuple())
|
||||||
|
|
||||||
|
def test_clear_kwargs(self):
|
||||||
|
provider = providers.Factory(Example) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.clear_kwargs()
|
||||||
|
self.assertEqual(provider.kwargs, dict())
|
||||||
|
|
||||||
|
def test_clear_attributes(self):
|
||||||
|
provider = providers.Factory(Example) \
|
||||||
|
.add_attributes(attribute1=5, attribute2=6) \
|
||||||
|
.clear_attributes()
|
||||||
|
self.assertEqual(provider.attributes, dict())
|
||||||
|
|
||||||
|
def test_call_overridden(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
overriding_provider1 = providers.Factory(dict)
|
||||||
|
overriding_provider2 = providers.Factory(list)
|
||||||
|
|
||||||
|
provider.override(overriding_provider1)
|
||||||
|
provider.override(overriding_provider2)
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertIsNot(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, list)
|
||||||
|
self.assertIsInstance(instance2, list)
|
||||||
|
|
||||||
|
def test_deepcopy(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIs(provider.cls, provider_copy.cls)
|
||||||
|
self.assertIsInstance(provider, providers.Factory)
|
||||||
|
|
||||||
|
def test_deepcopy_from_memo(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
provider_copy_memo = providers.Factory(Example)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(
|
||||||
|
provider, memo={id(provider): provider_copy_memo})
|
||||||
|
|
||||||
|
self.assertIs(provider_copy, provider_copy_memo)
|
||||||
|
|
||||||
|
def test_deepcopy_args(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
dependent_provider1 = providers.Factory(list)
|
||||||
|
dependent_provider2 = providers.Factory(dict)
|
||||||
|
|
||||||
|
provider.add_args(dependent_provider1, dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.args[0]
|
||||||
|
dependent_provider_copy2 = provider_copy.args[1]
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.args, provider_copy.args)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.cls, dependent_provider_copy1.cls)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.cls, dependent_provider_copy2.cls)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_kwargs(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
dependent_provider1 = providers.Factory(list)
|
||||||
|
dependent_provider2 = providers.Factory(dict)
|
||||||
|
|
||||||
|
provider.add_kwargs(a1=dependent_provider1, a2=dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.kwargs['a1']
|
||||||
|
dependent_provider_copy2 = provider_copy.kwargs['a2']
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.kwargs, provider_copy.kwargs)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.cls, dependent_provider_copy1.cls)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.cls, dependent_provider_copy2.cls)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_attributes(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
dependent_provider1 = providers.Factory(list)
|
||||||
|
dependent_provider2 = providers.Factory(dict)
|
||||||
|
|
||||||
|
provider.add_attributes(a1=dependent_provider1, a2=dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.attributes['a1']
|
||||||
|
dependent_provider_copy2 = provider_copy.attributes['a2']
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.attributes, provider_copy.attributes)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.cls, dependent_provider_copy1.cls)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.cls, dependent_provider_copy2.cls)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_overridden(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
object_provider = providers.Object(object())
|
||||||
|
|
||||||
|
provider.override(object_provider)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
object_provider_copy = provider_copy.overridden[0]
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIs(provider.cls, provider_copy.cls)
|
||||||
|
self.assertIsInstance(provider, providers.Factory)
|
||||||
|
|
||||||
|
self.assertIsNot(object_provider, object_provider_copy)
|
||||||
|
self.assertIsInstance(object_provider_copy, providers.Object)
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.factories.'
|
||||||
|
'Factory({0}) at {1}>'.format(
|
||||||
|
repr(Example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegatedFactoryTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_inheritance(self):
|
||||||
|
self.assertIsInstance(providers.DelegatedFactory(object),
|
||||||
|
providers.Factory)
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(
|
||||||
|
providers.is_provider(providers.DelegatedFactory(object)))
|
||||||
|
|
||||||
|
def test_is_delegated_provider(self):
|
||||||
|
self.assertTrue(
|
||||||
|
providers.is_delegated(providers.DelegatedFactory(object)))
|
|
@ -25,6 +25,33 @@ 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)
|
||||||
|
|
||||||
|
def test_deepcopy(self):
|
||||||
|
provider = providers.Factory(object)
|
||||||
|
injection = providers.PositionalInjection(provider)
|
||||||
|
|
||||||
|
injection_copy = providers.deepcopy(injection)
|
||||||
|
|
||||||
|
self.assertIsNot(injection_copy, injection)
|
||||||
|
self.assertIsNot(injection_copy.get_original_value(),
|
||||||
|
injection.get_original_value())
|
||||||
|
|
||||||
|
def test_deepcopy_memo(self):
|
||||||
|
provider = providers.Factory(object)
|
||||||
|
injection = providers.PositionalInjection(provider)
|
||||||
|
injection_copy_orig = providers.PositionalInjection(provider)
|
||||||
|
|
||||||
|
injection_copy = providers.deepcopy(
|
||||||
|
injection, {id(injection): injection_copy_orig})
|
||||||
|
|
||||||
|
self.assertIs(injection_copy, injection_copy_orig)
|
||||||
|
self.assertIs(injection_copy.get_original_value(),
|
||||||
|
injection.get_original_value())
|
||||||
|
|
||||||
|
|
||||||
class NamedInjectionTests(unittest.TestCase):
|
class NamedInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -50,3 +77,30 @@ 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)
|
||||||
|
|
||||||
|
def test_deepcopy(self):
|
||||||
|
provider = providers.Factory(object)
|
||||||
|
injection = providers.NamedInjection('name', provider)
|
||||||
|
|
||||||
|
injection_copy = providers.deepcopy(injection)
|
||||||
|
|
||||||
|
self.assertIsNot(injection_copy, injection)
|
||||||
|
self.assertIsNot(injection_copy.get_original_value(),
|
||||||
|
injection.get_original_value())
|
||||||
|
|
||||||
|
def test_deepcopy_memo(self):
|
||||||
|
provider = providers.Factory(object)
|
||||||
|
injection = providers.NamedInjection('name', provider)
|
||||||
|
injection_copy_orig = providers.NamedInjection('name', provider)
|
||||||
|
|
||||||
|
injection_copy = providers.deepcopy(
|
||||||
|
injection, {id(injection): injection_copy_orig})
|
||||||
|
|
||||||
|
self.assertIs(injection_copy, injection_copy_orig)
|
||||||
|
self.assertIs(injection_copy.get_original_value(),
|
||||||
|
injection.get_original_value())
|
||||||
|
|
434
tests/unit/providers/test_singletons.py
Normal file
434
tests/unit/providers/test_singletons.py
Normal file
|
@ -0,0 +1,434 @@
|
||||||
|
"""Dependency injector singleton providers unit tests."""
|
||||||
|
|
||||||
|
import unittest2 as unittest
|
||||||
|
|
||||||
|
from dependency_injector import (
|
||||||
|
providers,
|
||||||
|
errors,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Example(object):
|
||||||
|
|
||||||
|
def __init__(self, init_arg1=None, init_arg2=None, init_arg3=None,
|
||||||
|
init_arg4=None):
|
||||||
|
self.init_arg1 = init_arg1
|
||||||
|
self.init_arg2 = init_arg2
|
||||||
|
self.init_arg3 = init_arg3
|
||||||
|
self.init_arg4 = init_arg4
|
||||||
|
|
||||||
|
self.attribute1 = None
|
||||||
|
self.attribute2 = None
|
||||||
|
|
||||||
|
|
||||||
|
class _BaseSingletonTestCase(object):
|
||||||
|
|
||||||
|
singleton_cls = None
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(providers.is_provider(self.singleton_cls(Example)))
|
||||||
|
|
||||||
|
def test_init_with_callable(self):
|
||||||
|
self.assertTrue(self.singleton_cls(credits))
|
||||||
|
|
||||||
|
def test_init_with_not_callable(self):
|
||||||
|
self.assertRaises(errors.Error, self.singleton_cls, 123)
|
||||||
|
|
||||||
|
def test_init_with_valid_provided_type(self):
|
||||||
|
class ExampleProvider(self.singleton_cls):
|
||||||
|
provided_type = Example
|
||||||
|
|
||||||
|
example_provider = ExampleProvider(Example, 1, 2)
|
||||||
|
|
||||||
|
self.assertIsInstance(example_provider(), Example)
|
||||||
|
|
||||||
|
def test_init_with_valid_provided_subtype(self):
|
||||||
|
class ExampleProvider(self.singleton_cls):
|
||||||
|
provided_type = Example
|
||||||
|
|
||||||
|
class NewExampe(Example):
|
||||||
|
pass
|
||||||
|
|
||||||
|
example_provider = ExampleProvider(NewExampe, 1, 2)
|
||||||
|
|
||||||
|
self.assertIsInstance(example_provider(), NewExampe)
|
||||||
|
|
||||||
|
def test_init_with_invalid_provided_type(self):
|
||||||
|
class ExampleProvider(self.singleton_cls):
|
||||||
|
provided_type = Example
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
ExampleProvider(list)
|
||||||
|
|
||||||
|
def test_call(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertIs(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_init_positional_args(self):
|
||||||
|
provider = self.singleton_cls(Example, 'i1', 'i2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance1.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance2.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertIs(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_init_keyword_args(self):
|
||||||
|
provider = self.singleton_cls(Example, init_arg1='i1', init_arg2='i2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance1.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance2.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertIs(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_init_positional_and_keyword_args(self):
|
||||||
|
provider = self.singleton_cls(Example, 'i1', init_arg2='i2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance1.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.init_arg1, 'i1')
|
||||||
|
self.assertEqual(instance2.init_arg2, 'i2')
|
||||||
|
|
||||||
|
self.assertIs(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_attributes(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
provider.add_attributes(attribute1='a1', attribute2='a2')
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance1.attribute1, 'a1')
|
||||||
|
self.assertEqual(instance1.attribute2, 'a2')
|
||||||
|
|
||||||
|
self.assertEqual(instance2.attribute1, 'a1')
|
||||||
|
self.assertEqual(instance2.attribute2, 'a2')
|
||||||
|
|
||||||
|
self.assertIs(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, Example)
|
||||||
|
self.assertIsInstance(instance2, Example)
|
||||||
|
|
||||||
|
def test_call_with_context_args(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
instance = provider(11, 22)
|
||||||
|
|
||||||
|
self.assertEqual(instance.init_arg1, 11)
|
||||||
|
self.assertEqual(instance.init_arg2, 22)
|
||||||
|
|
||||||
|
def test_call_with_context_kwargs(self):
|
||||||
|
provider = self.singleton_cls(Example, init_arg1=1)
|
||||||
|
|
||||||
|
instance1 = provider(init_arg2=22)
|
||||||
|
self.assertEqual(instance1.init_arg1, 1)
|
||||||
|
self.assertEqual(instance1.init_arg2, 22)
|
||||||
|
|
||||||
|
# Instance is created earlier
|
||||||
|
instance1 = provider(init_arg1=11, init_arg2=22)
|
||||||
|
self.assertEqual(instance1.init_arg1, 1)
|
||||||
|
self.assertEqual(instance1.init_arg2, 22)
|
||||||
|
|
||||||
|
def test_call_with_context_args_and_kwargs(self):
|
||||||
|
provider = self.singleton_cls(Example, 11)
|
||||||
|
|
||||||
|
instance = provider(22, init_arg3=33, init_arg4=44)
|
||||||
|
|
||||||
|
self.assertEqual(instance.init_arg1, 11)
|
||||||
|
self.assertEqual(instance.init_arg2, 22)
|
||||||
|
self.assertEqual(instance.init_arg3, 33)
|
||||||
|
self.assertEqual(instance.init_arg4, 44)
|
||||||
|
|
||||||
|
def test_fluent_interface(self):
|
||||||
|
provider = self.singleton_cls(Example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.add_attributes(attribute1=5, attribute2=6)
|
||||||
|
|
||||||
|
instance = provider()
|
||||||
|
|
||||||
|
self.assertEqual(instance.init_arg1, 1)
|
||||||
|
self.assertEqual(instance.init_arg2, 2)
|
||||||
|
self.assertEqual(instance.init_arg3, 3)
|
||||||
|
self.assertEqual(instance.init_arg4, 4)
|
||||||
|
self.assertEqual(instance.attribute1, 5)
|
||||||
|
self.assertEqual(instance.attribute2, 6)
|
||||||
|
|
||||||
|
def test_set_args(self):
|
||||||
|
provider = self.singleton_cls(Example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.set_args(3, 4)
|
||||||
|
self.assertEqual(provider.args, tuple([3, 4]))
|
||||||
|
|
||||||
|
def test_set_kwargs(self):
|
||||||
|
provider = self.singleton_cls(Example) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.set_kwargs(init_arg3=4, init_arg4=5)
|
||||||
|
self.assertEqual(provider.kwargs, dict(init_arg3=4, init_arg4=5))
|
||||||
|
|
||||||
|
def test_set_attributes(self):
|
||||||
|
provider = self.singleton_cls(Example) \
|
||||||
|
.add_attributes(attribute1=5, attribute2=6) \
|
||||||
|
.set_attributes(attribute1=6, attribute2=7)
|
||||||
|
self.assertEqual(provider.attributes, dict(attribute1=6, attribute2=7))
|
||||||
|
|
||||||
|
def test_clear_args(self):
|
||||||
|
provider = self.singleton_cls(Example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.clear_args()
|
||||||
|
self.assertEqual(provider.args, tuple())
|
||||||
|
|
||||||
|
def test_clear_kwargs(self):
|
||||||
|
provider = self.singleton_cls(Example) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.clear_kwargs()
|
||||||
|
self.assertEqual(provider.kwargs, dict())
|
||||||
|
|
||||||
|
def test_clear_attributes(self):
|
||||||
|
provider = self.singleton_cls(Example) \
|
||||||
|
.add_attributes(attribute1=5, attribute2=6) \
|
||||||
|
.clear_attributes()
|
||||||
|
self.assertEqual(provider.attributes, dict())
|
||||||
|
|
||||||
|
def test_call_overridden(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
overriding_provider1 = self.singleton_cls(dict)
|
||||||
|
overriding_provider2 = self.singleton_cls(list)
|
||||||
|
|
||||||
|
provider.override(overriding_provider1)
|
||||||
|
provider.override(overriding_provider2)
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
instance2 = provider()
|
||||||
|
|
||||||
|
self.assertIs(instance1, instance2)
|
||||||
|
self.assertIsInstance(instance1, list)
|
||||||
|
self.assertIsInstance(instance2, list)
|
||||||
|
|
||||||
|
def test_deepcopy(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIs(provider.cls, provider_copy.cls)
|
||||||
|
self.assertIsInstance(provider, self.singleton_cls)
|
||||||
|
|
||||||
|
def test_deepcopy_from_memo(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
provider_copy_memo = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(
|
||||||
|
provider, memo={id(provider): provider_copy_memo})
|
||||||
|
|
||||||
|
self.assertIs(provider_copy, provider_copy_memo)
|
||||||
|
|
||||||
|
def test_deepcopy_args(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
dependent_provider1 = self.singleton_cls(list)
|
||||||
|
dependent_provider2 = self.singleton_cls(dict)
|
||||||
|
|
||||||
|
provider.add_args(dependent_provider1, dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.args[0]
|
||||||
|
dependent_provider_copy2 = provider_copy.args[1]
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.args, provider_copy.args)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.cls, dependent_provider_copy1.cls)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.cls, dependent_provider_copy2.cls)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_kwargs(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
dependent_provider1 = self.singleton_cls(list)
|
||||||
|
dependent_provider2 = self.singleton_cls(dict)
|
||||||
|
|
||||||
|
provider.add_kwargs(a1=dependent_provider1, a2=dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.kwargs['a1']
|
||||||
|
dependent_provider_copy2 = provider_copy.kwargs['a2']
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.kwargs, provider_copy.kwargs)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.cls, dependent_provider_copy1.cls)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.cls, dependent_provider_copy2.cls)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_attributes(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
dependent_provider1 = self.singleton_cls(list)
|
||||||
|
dependent_provider2 = self.singleton_cls(dict)
|
||||||
|
|
||||||
|
provider.add_attributes(a1=dependent_provider1, a2=dependent_provider2)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
dependent_provider_copy1 = provider_copy.attributes['a1']
|
||||||
|
dependent_provider_copy2 = provider_copy.attributes['a2']
|
||||||
|
|
||||||
|
self.assertNotEqual(provider.attributes, provider_copy.attributes)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider1.cls, dependent_provider_copy1.cls)
|
||||||
|
self.assertIsNot(dependent_provider1, dependent_provider_copy1)
|
||||||
|
|
||||||
|
self.assertIs(dependent_provider2.cls, dependent_provider_copy2.cls)
|
||||||
|
self.assertIsNot(dependent_provider2, dependent_provider_copy2)
|
||||||
|
|
||||||
|
def test_deepcopy_overridden(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
object_provider = providers.Object(object())
|
||||||
|
|
||||||
|
provider.override(object_provider)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
object_provider_copy = provider_copy.overridden[0]
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIs(provider.cls, provider_copy.cls)
|
||||||
|
self.assertIsInstance(provider, self.singleton_cls)
|
||||||
|
|
||||||
|
self.assertIsNot(object_provider, object_provider_copy)
|
||||||
|
self.assertIsInstance(object_provider_copy, providers.Object)
|
||||||
|
|
||||||
|
def test_reset(self):
|
||||||
|
provider = self.singleton_cls(object)
|
||||||
|
|
||||||
|
instance1 = provider()
|
||||||
|
self.assertIsInstance(instance1, object)
|
||||||
|
|
||||||
|
provider.reset()
|
||||||
|
|
||||||
|
instance2 = provider()
|
||||||
|
self.assertIsInstance(instance1, object)
|
||||||
|
|
||||||
|
self.assertIsNot(instance1, instance2)
|
||||||
|
|
||||||
|
|
||||||
|
class SingletonTests(_BaseSingletonTestCase, unittest.TestCase):
|
||||||
|
|
||||||
|
singleton_cls = providers.Singleton
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.singletons.'
|
||||||
|
'Singleton({0}) at {1}>'.format(
|
||||||
|
repr(Example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegatedSingletonTests(_BaseSingletonTestCase, unittest.TestCase):
|
||||||
|
|
||||||
|
singleton_cls = providers.DelegatedSingleton
|
||||||
|
|
||||||
|
def test_is_delegated_provider(self):
|
||||||
|
provider = self.singleton_cls(object)
|
||||||
|
self.assertTrue(providers.is_delegated(provider))
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.singletons.'
|
||||||
|
'DelegatedSingleton({0}) at {1}>'.format(
|
||||||
|
repr(Example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadLocalSingletonTests(_BaseSingletonTestCase, unittest.TestCase):
|
||||||
|
|
||||||
|
singleton_cls = providers.ThreadLocalSingleton
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = providers.ThreadLocalSingleton(Example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.singletons.'
|
||||||
|
'ThreadLocalSingleton({0}) at {1}>'.format(
|
||||||
|
repr(Example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegatedThreadLocalSingletonTests(_BaseSingletonTestCase,
|
||||||
|
unittest.TestCase):
|
||||||
|
|
||||||
|
singleton_cls = providers.DelegatedThreadLocalSingleton
|
||||||
|
|
||||||
|
def test_is_delegated_provider(self):
|
||||||
|
provider = self.singleton_cls(object)
|
||||||
|
self.assertTrue(providers.is_delegated(provider))
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.singletons.'
|
||||||
|
'DelegatedThreadLocalSingleton({0}) at {1}>'.format(
|
||||||
|
repr(Example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadSafeSingletonTests(_BaseSingletonTestCase, unittest.TestCase):
|
||||||
|
|
||||||
|
singleton_cls = providers.ThreadSafeSingleton
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.singletons.'
|
||||||
|
'ThreadSafeSingleton({0}) at {1}>'.format(
|
||||||
|
repr(Example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegatedThreadSafeSingletonTests(_BaseSingletonTestCase,
|
||||||
|
unittest.TestCase):
|
||||||
|
|
||||||
|
singleton_cls = providers.DelegatedThreadSafeSingleton
|
||||||
|
|
||||||
|
def test_is_delegated_provider(self):
|
||||||
|
provider = self.singleton_cls(object)
|
||||||
|
self.assertTrue(providers.is_delegated(provider))
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.singletons.'
|
||||||
|
'DelegatedThreadSafeSingleton({0}) at {1}>'.format(
|
||||||
|
repr(Example),
|
||||||
|
hex(id(provider))))
|
|
@ -1,31 +0,0 @@
|
||||||
"""Dependency injector static providers unit tests."""
|
|
||||||
|
|
||||||
import unittest2 as unittest
|
|
||||||
|
|
||||||
from dependency_injector import providers
|
|
||||||
|
|
||||||
|
|
||||||
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))))
|
|
Loading…
Reference in New Issue
Block a user