mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 11:04:01 +03:00
Coroutine provider (#206)
* Add coroutine provider examples * Add coroutine provier * Update changelog * Update static analysis travis jobs to python 3.7 * Update coroutine provider implementation for python 3.4 * Update static analysis travis jobs to python 3.6 * Make pycode style happy * Add tests for coroutine providers * Make coroutine tests python 2 syntax friendly * Split tests to python2 and python3 * Refactor coroutine provider tests * Modify pypy tests running command * Update coroutine provider docs
This commit is contained in:
parent
ac0e5eb26a
commit
9a785de4b5
|
@ -7,17 +7,17 @@ language:
|
||||||
- python
|
- python
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- python: 2.7
|
- python: 3.6
|
||||||
env: TOXENV=coveralls DEPENDENCY_INJECTOR_DEBUG_MODE=1
|
env: TOXENV=coveralls DEPENDENCY_INJECTOR_DEBUG_MODE=1
|
||||||
install:
|
install:
|
||||||
- pip install tox
|
- pip install tox
|
||||||
- pip install cython
|
- pip install cython
|
||||||
- make cythonize
|
- make cythonize
|
||||||
- python: 2.7
|
- python: 3.6
|
||||||
env: TOXENV=pylint
|
env: TOXENV=pylint
|
||||||
- python: 2.7
|
- python: 3.6
|
||||||
env: TOXENV=flake8
|
env: TOXENV=flake8
|
||||||
- python: 2.7
|
- python: 3.6
|
||||||
env: TOXENV=pydocstyle
|
env: TOXENV=pydocstyle
|
||||||
- python: 2.7
|
- python: 2.7
|
||||||
env: TOXENV=py27
|
env: TOXENV=py27
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -42,10 +42,17 @@ install: uninstall clean cythonize
|
||||||
uninstall:
|
uninstall:
|
||||||
- pip uninstall -y -q dependency-injector 2> /dev/null
|
- pip uninstall -y -q dependency-injector 2> /dev/null
|
||||||
|
|
||||||
test: build
|
test-py2: build
|
||||||
# Unit tests with coverage report
|
# Unit tests with coverage report
|
||||||
coverage erase
|
coverage erase
|
||||||
coverage run --rcfile=./.coveragerc -m unittest2 discover tests/unit
|
coverage run --rcfile=./.coveragerc -m unittest2 discover -s tests/unit/ -p test_*_py2_py3.py
|
||||||
|
coverage report --rcfile=./.coveragerc
|
||||||
|
coverage html --rcfile=./.coveragerc
|
||||||
|
|
||||||
|
test-py3: build
|
||||||
|
# Unit tests with coverage report
|
||||||
|
coverage erase
|
||||||
|
coverage run --rcfile=./.coveragerc -m unittest2 discover -s tests/unit/ -p test_*py3.py
|
||||||
coverage report --rcfile=./.coveragerc
|
coverage report --rcfile=./.coveragerc
|
||||||
coverage html --rcfile=./.coveragerc
|
coverage html --rcfile=./.coveragerc
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@ follows `Semantic versioning`_
|
||||||
|
|
||||||
Development version
|
Development version
|
||||||
-------------------
|
-------------------
|
||||||
|
- Add ``Coroutine`` provider.
|
||||||
|
- Add ``DelegatedCoroutine`` provider.
|
||||||
|
- Add ``AbstractCoroutine`` provider.
|
||||||
|
- Add ``CoroutineDelegate`` provider.
|
||||||
- Regenerate C sources using Cython 0.28.5.
|
- Regenerate C sources using Cython 0.28.5.
|
||||||
|
|
||||||
3.13.2
|
3.13.2
|
||||||
|
|
|
@ -11,7 +11,7 @@ Callable providers and injections
|
||||||
:py:class:`Callable` provider takes a various number of positional and keyword
|
:py:class:`Callable` provider takes a various number of positional and keyword
|
||||||
arguments that are used as wrapped callable injections. Every time, when
|
arguments that are used as wrapped callable injections. Every time, when
|
||||||
:py:class:`Callable` provider is called, positional and keyword argument
|
:py:class:`Callable` provider is called, positional and keyword argument
|
||||||
injections would be passed as an callable arguments.
|
injections would be passed as callable arguments.
|
||||||
|
|
||||||
Injections are done according to the next rules:
|
Injections are done according to the next rules:
|
||||||
|
|
||||||
|
|
73
docs/providers/coroutine.rst
Normal file
73
docs/providers/coroutine.rst
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
Coroutine providers
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
|
:py:class:`Coroutine` provider create wrapped coroutine on every call.
|
||||||
|
|
||||||
|
:py:class:`Coroutine` provider is designed for making better integration with
|
||||||
|
``asyncio`` coroutines. In particular, :py:class:`Coroutine` provider returns
|
||||||
|
``True`` for ``asyncio.iscoroutinefunction()`` checks.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
:py:class:`Coroutine` provider works only for Python 3.4+.
|
||||||
|
|
||||||
|
Example of usage :py:class:`Coroutine` provider with ``async / await``-based
|
||||||
|
coroutine:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/providers/coroutine_async_await.py
|
||||||
|
:language: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
Coroutine providers and injections
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
:py:class:`Coroutine` provider takes a various number of positional and keyword
|
||||||
|
arguments that are used as wrapped coroutine injections. Every time, when
|
||||||
|
:py:class:`Coroutine` provider is called, positional and keyword argument
|
||||||
|
injections would be passed as coroutine arguments.
|
||||||
|
|
||||||
|
Injections are done according to the next rules:
|
||||||
|
|
||||||
|
+ All providers (instances of :py:class:`Provider`) are called every time
|
||||||
|
when injection needs to be done.
|
||||||
|
+ Providers could be injected "as is" (delegated), if it is defined obviously.
|
||||||
|
Check out :ref:`coroutine_providers_delegation`.
|
||||||
|
+ All other injectable values are provided *"as is"*.
|
||||||
|
+ Positional context arguments will be appended after :py:class:`Coroutine`
|
||||||
|
positional injections.
|
||||||
|
+ Keyword context arguments have priority on :py:class:`Coroutine` keyword
|
||||||
|
injections and will be merged over them.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Examples of making injections could be found in API docs -
|
||||||
|
:py:class:`Coroutine`.
|
||||||
|
|
||||||
|
.. _coroutine_providers_delegation:
|
||||||
|
|
||||||
|
Coroutine providers delegation
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
:py:class:`Coroutine` provider could be delegated to any other provider via
|
||||||
|
any kind of injection.
|
||||||
|
|
||||||
|
Delegation of :py:class:`Coroutine` providers is the same as
|
||||||
|
:py:class:`Factory` providers delegation, please follow
|
||||||
|
:ref:`factory_providers_delegation` section for examples (with exception
|
||||||
|
of using :py:class:`DelegatedCoroutine` instead of
|
||||||
|
:py:class:`DelegatedFactory`).
|
||||||
|
|
||||||
|
Abstract coroutine providers
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
:py:class:`AbstractCoroutine` provider is a :py:class:`Coroutine` provider that
|
||||||
|
must be explicitly overridden before calling.
|
||||||
|
|
||||||
|
Behaviour of :py:class:`AbstractCoroutine` providers is the same as of
|
||||||
|
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
|
||||||
|
section for examples (with exception of using :py:class:`AbstractCoroutine`
|
||||||
|
provider instead of :py:class:`AbstractFactory`).
|
||||||
|
|
||||||
|
.. disqus::
|
|
@ -22,7 +22,7 @@ Factory providers and __init__ injections
|
||||||
:py:class:`Factory` takes a various number of positional and keyword arguments
|
:py:class:`Factory` takes a various number of positional and keyword arguments
|
||||||
that are used as ``__init__()`` injections. Every time, when
|
that are used as ``__init__()`` injections. Every time, when
|
||||||
:py:class:`Factory` creates new one instance, positional and keyword
|
:py:class:`Factory` creates new one instance, positional and keyword
|
||||||
argument injections would be passed as an instance's arguments.
|
argument injections would be passed as instance arguments.
|
||||||
|
|
||||||
Injections are done according to the next rules:
|
Injections are done according to the next rules:
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ Providers package API docs - :py:mod:`dependency_injector.providers`
|
||||||
factory
|
factory
|
||||||
singleton
|
singleton
|
||||||
callable
|
callable
|
||||||
|
coroutine
|
||||||
object
|
object
|
||||||
dependency
|
dependency
|
||||||
overriding
|
overriding
|
||||||
|
|
26
examples/providers/coroutine.py
Normal file
26
examples/providers/coroutine.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
"""`Coroutine` providers example with @asyncio.coroutine decorator.
|
||||||
|
|
||||||
|
Current example works only fot Python 3.4+.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
import dependency_injector.providers as providers
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def coroutine_function(arg1, arg2):
|
||||||
|
"""Sample coroutine function."""
|
||||||
|
yield from asyncio.sleep(0.1)
|
||||||
|
return arg1, arg2
|
||||||
|
|
||||||
|
|
||||||
|
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
arg1, arg2 = loop.run_until_complete(coroutine_provider())
|
||||||
|
|
||||||
|
assert (arg1, arg2) == (1, 2)
|
||||||
|
assert asyncio.iscoroutinefunction(coroutine_provider)
|
25
examples/providers/coroutine_async_await.py
Normal file
25
examples/providers/coroutine_async_await.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
"""`Coroutine` providers example with async / await syntax.
|
||||||
|
|
||||||
|
Current example works only fot Python 3.5+.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
import dependency_injector.providers as providers
|
||||||
|
|
||||||
|
|
||||||
|
async def coroutine_function(arg1, arg2):
|
||||||
|
"""Sample coroutine function."""
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
return arg1, arg2
|
||||||
|
|
||||||
|
|
||||||
|
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
arg1, arg2 = loop.run_until_complete(coroutine_provider())
|
||||||
|
|
||||||
|
assert (arg1, arg2) == (1, 2)
|
||||||
|
assert asyncio.iscoroutinefunction(coroutine_provider)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -69,6 +69,22 @@ cdef class CallableDelegate(Delegate):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Coroutine providers
|
||||||
|
cdef class Coroutine(Callable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
cdef class DelegatedCoroutine(Coroutine):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
cdef class AbstractCoroutine(Coroutine):
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class CoroutineDelegate(Delegate):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Configuration providers
|
# Configuration providers
|
||||||
cdef class Configuration(Object):
|
cdef class Configuration(Object):
|
||||||
cdef str __name
|
cdef str __name
|
||||||
|
|
|
@ -9,6 +9,19 @@ import sys
|
||||||
import types
|
import types
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
try:
|
||||||
|
import asyncio
|
||||||
|
except ImportError:
|
||||||
|
asyncio = None
|
||||||
|
_is_coroutine_marker = None
|
||||||
|
else:
|
||||||
|
if sys.version_info[0:2] == (3, 4):
|
||||||
|
_is_coroutine_marker = True
|
||||||
|
else:
|
||||||
|
import asyncio.coroutines
|
||||||
|
_is_coroutine_marker = asyncio.coroutines._is_coroutine
|
||||||
|
|
||||||
|
|
||||||
from .errors import (
|
from .errors import (
|
||||||
Error,
|
Error,
|
||||||
NoSuchProviderError,
|
NoSuchProviderError,
|
||||||
|
@ -848,6 +861,128 @@ cdef class CallableDelegate(Delegate):
|
||||||
super(Delegate, self).__init__(callable)
|
super(Delegate, self).__init__(callable)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class Coroutine(Callable):
|
||||||
|
r"""Coroutine provider creates wrapped coroutine on every call.
|
||||||
|
|
||||||
|
Coroutine supports positional and keyword argument injections:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
some_coroutine = Coroutine(some_coroutine,
|
||||||
|
'positional_arg1', 'positional_arg2',
|
||||||
|
keyword_argument1=3, keyword_argument=4)
|
||||||
|
|
||||||
|
# or
|
||||||
|
|
||||||
|
some_coroutine = Coroutine(some_coroutine) \
|
||||||
|
.add_args('positional_arg1', 'positional_arg2') \
|
||||||
|
.add_kwargs(keyword_argument1=3, keyword_argument=4)
|
||||||
|
|
||||||
|
# or
|
||||||
|
|
||||||
|
some_coroutine = Coroutine(some_coroutine)
|
||||||
|
some_coroutine.add_args('positional_arg1', 'positional_arg2')
|
||||||
|
some_coroutine.add_kwargs(keyword_argument1=3, keyword_argument=4)
|
||||||
|
"""
|
||||||
|
|
||||||
|
_is_coroutine = _is_coroutine_marker
|
||||||
|
|
||||||
|
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 asyncio:
|
||||||
|
raise Error('Module asyncio is not available')
|
||||||
|
|
||||||
|
if not asyncio.iscoroutinefunction(provides):
|
||||||
|
raise Error('Provider {0} expected to get coroutine function, '
|
||||||
|
'got {1}'.format('.'.join((self.__class__.__module__,
|
||||||
|
self.__class__.__name__)),
|
||||||
|
provides))
|
||||||
|
|
||||||
|
super(Coroutine, self).__init__(provides, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class DelegatedCoroutine(Coroutine):
|
||||||
|
"""Coroutine provider that is injected "as is".
|
||||||
|
|
||||||
|
DelegatedCoroutine is a :py:class:`Coroutine`, that is injected "as is".
|
||||||
|
"""
|
||||||
|
|
||||||
|
__IS_DELEGATED__ = True
|
||||||
|
|
||||||
|
|
||||||
|
cdef class AbstractCoroutine(Coroutine):
|
||||||
|
"""Abstract coroutine provider.
|
||||||
|
|
||||||
|
:py:class:`AbstractCoroutine` is a :py:class:`Coroutine` provider that must
|
||||||
|
be explicitly overridden before calling.
|
||||||
|
|
||||||
|
Overriding of :py:class:`AbstractCoroutine` is possible only by another
|
||||||
|
:py:class:`Coroutine` provider.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
"""Return provided object.
|
||||||
|
|
||||||
|
Callable interface implementation.
|
||||||
|
"""
|
||||||
|
if self.__last_overriding is None:
|
||||||
|
raise Error('{0} must be overridden before calling'.format(self))
|
||||||
|
return self.__last_overriding(*args, **kwargs)
|
||||||
|
|
||||||
|
def override(self, provider):
|
||||||
|
"""Override provider with another provider.
|
||||||
|
|
||||||
|
:param provider: Overriding provider.
|
||||||
|
:type provider: :py:class:`Provider`
|
||||||
|
|
||||||
|
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||||
|
|
||||||
|
:return: Overriding context.
|
||||||
|
:rtype: :py:class:`OverridingContext`
|
||||||
|
"""
|
||||||
|
if not isinstance(provider, Coroutine):
|
||||||
|
raise Error('{0} must be overridden only by '
|
||||||
|
'{1} providers'.format(self, Coroutine))
|
||||||
|
return super(AbstractCoroutine, self).override(provider)
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
"""Return result of provided callable's call."""
|
||||||
|
raise NotImplementedError('Abstract provider forward providing logic '
|
||||||
|
'to overriding provider')
|
||||||
|
|
||||||
|
|
||||||
|
cdef class CoroutineDelegate(Delegate):
|
||||||
|
"""Coroutine delegate injects delegating coroutine "as is".
|
||||||
|
|
||||||
|
.. py:attribute:: provides
|
||||||
|
|
||||||
|
Value that have to be provided.
|
||||||
|
|
||||||
|
:type: object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, coroutine):
|
||||||
|
"""Initializer.
|
||||||
|
|
||||||
|
:param coroutine: Value that have to be provided.
|
||||||
|
:type coroutine: object
|
||||||
|
"""
|
||||||
|
if isinstance(coroutine, Coroutine) is False:
|
||||||
|
raise Error('{0} can wrap only {1} providers'.format(
|
||||||
|
self.__class__, Callable))
|
||||||
|
super(CoroutineDelegate, self).__init__(coroutine)
|
||||||
|
|
||||||
|
|
||||||
cdef class Configuration(Object):
|
cdef class Configuration(Object):
|
||||||
"""Configuration provider.
|
"""Configuration provider.
|
||||||
|
|
||||||
|
|
282
tests/unit/providers/test_coroutines_py3.py
Normal file
282
tests/unit/providers/test_coroutines_py3.py
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
"""Dependency injector coroutine providers unit tests."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
import unittest2 as unittest
|
||||||
|
|
||||||
|
from dependency_injector import (
|
||||||
|
providers,
|
||||||
|
errors,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _example(arg1, arg2, arg3, arg4):
|
||||||
|
future = asyncio.Future()
|
||||||
|
future.set_result(None)
|
||||||
|
yield from future
|
||||||
|
return arg1, arg2, arg3, arg4
|
||||||
|
|
||||||
|
|
||||||
|
def _run(coro):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
return loop.run_until_complete(coro)
|
||||||
|
|
||||||
|
|
||||||
|
class CoroutineTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_init_with_coroutine(self):
|
||||||
|
self.assertTrue(providers.Coroutine(_example))
|
||||||
|
|
||||||
|
def test_init_with_not_coroutine(self):
|
||||||
|
self.assertRaises(errors.Error, providers.Coroutine, lambda: None)
|
||||||
|
|
||||||
|
def test_call_with_positional_args(self):
|
||||||
|
provider = providers.Coroutine(_example, 1, 2, 3, 4)
|
||||||
|
self.assertTupleEqual(_run(provider()), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_keyword_args(self):
|
||||||
|
provider = providers.Coroutine(_example,
|
||||||
|
arg1=1, arg2=2, arg3=3, arg4=4)
|
||||||
|
self.assertTupleEqual(_run(provider()), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_positional_and_keyword_args(self):
|
||||||
|
provider = providers.Coroutine(_example,
|
||||||
|
1, 2,
|
||||||
|
arg3=3, arg4=4)
|
||||||
|
self.assertTupleEqual(_run(provider()), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_context_args(self):
|
||||||
|
provider = providers.Coroutine(_example, 1, 2)
|
||||||
|
self.assertTupleEqual(_run(provider(3, 4)), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_with_context_kwargs(self):
|
||||||
|
provider = providers.Coroutine(_example, arg1=1)
|
||||||
|
self.assertTupleEqual(
|
||||||
|
_run(provider(arg2=2, arg3=3, arg4=4)),
|
||||||
|
(1, 2, 3, 4),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_call_with_context_args_and_kwargs(self):
|
||||||
|
provider = providers.Coroutine(_example, 1)
|
||||||
|
self.assertTupleEqual(
|
||||||
|
_run(provider(2, arg3=3, arg4=4)),
|
||||||
|
(1, 2, 3, 4),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_fluent_interface(self):
|
||||||
|
provider = providers.Coroutine(_example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.add_kwargs(arg3=3, arg4=4)
|
||||||
|
|
||||||
|
self.assertTupleEqual(_run(provider()), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_set_args(self):
|
||||||
|
provider = providers.Coroutine(_example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.set_args(3, 4)
|
||||||
|
self.assertEqual(provider.args, tuple([3, 4]))
|
||||||
|
|
||||||
|
def test_set_kwargs(self):
|
||||||
|
provider = providers.Coroutine(_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.Coroutine(_example) \
|
||||||
|
.add_args(1, 2) \
|
||||||
|
.clear_args()
|
||||||
|
self.assertEqual(provider.args, tuple())
|
||||||
|
|
||||||
|
def test_clear_kwargs(self):
|
||||||
|
provider = providers.Coroutine(_example) \
|
||||||
|
.add_kwargs(init_arg3=3, init_arg4=4) \
|
||||||
|
.clear_kwargs()
|
||||||
|
self.assertEqual(provider.kwargs, dict())
|
||||||
|
|
||||||
|
def test_call_overridden(self):
|
||||||
|
provider = providers.Coroutine(_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.Coroutine(_example)
|
||||||
|
|
||||||
|
provider_copy = providers.deepcopy(provider)
|
||||||
|
|
||||||
|
self.assertIsNot(provider, provider_copy)
|
||||||
|
self.assertIs(provider.provides, provider_copy.provides)
|
||||||
|
self.assertIsInstance(provider, providers.Coroutine)
|
||||||
|
|
||||||
|
def test_deepcopy_from_memo(self):
|
||||||
|
provider = providers.Coroutine(_example)
|
||||||
|
provider_copy_memo = providers.Coroutine(_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.Coroutine(_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.Coroutine(_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.Coroutine(_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.Coroutine(_example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.'
|
||||||
|
'Coroutine({0}) at {1}>'.format(
|
||||||
|
repr(_example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class DelegatedCoroutineTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_inheritance(self):
|
||||||
|
self.assertIsInstance(providers.DelegatedCoroutine(_example),
|
||||||
|
providers.Coroutine)
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(
|
||||||
|
providers.is_provider(providers.DelegatedCoroutine(_example)))
|
||||||
|
|
||||||
|
def test_is_delegated_provider(self):
|
||||||
|
provider = providers.DelegatedCoroutine(_example)
|
||||||
|
self.assertTrue(providers.is_delegated(provider))
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = providers.DelegatedCoroutine(_example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.'
|
||||||
|
'DelegatedCoroutine({0}) at {1}>'.format(
|
||||||
|
repr(_example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractCoroutineTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_inheritance(self):
|
||||||
|
self.assertIsInstance(providers.AbstractCoroutine(_example),
|
||||||
|
providers.Coroutine)
|
||||||
|
|
||||||
|
def test_call_overridden_by_coroutine(self):
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _abstract_example():
|
||||||
|
raise RuntimeError('Should not be raised')
|
||||||
|
|
||||||
|
provider = providers.AbstractCoroutine(_abstract_example)
|
||||||
|
provider.override(providers.Coroutine(_example))
|
||||||
|
|
||||||
|
self.assertTrue(_run(provider(1, 2, 3, 4)), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_overridden_by_delegated_coroutine(self):
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _abstract_example():
|
||||||
|
raise RuntimeError('Should not be raised')
|
||||||
|
|
||||||
|
provider = providers.AbstractCoroutine(_abstract_example)
|
||||||
|
provider.override(providers.DelegatedCoroutine(_example))
|
||||||
|
|
||||||
|
self.assertTrue(_run(provider(1, 2, 3, 4)), (1, 2, 3, 4))
|
||||||
|
|
||||||
|
def test_call_not_overridden(self):
|
||||||
|
provider = providers.AbstractCoroutine(_example)
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
provider(1, 2, 3, 4)
|
||||||
|
|
||||||
|
def test_override_by_not_coroutine(self):
|
||||||
|
provider = providers.AbstractCoroutine(_example)
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
provider.override(providers.Factory(object))
|
||||||
|
|
||||||
|
def test_provide_not_implemented(self):
|
||||||
|
provider = providers.AbstractCoroutine(_example)
|
||||||
|
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
provider._provide((1, 2, 3, 4), dict())
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
provider = providers.AbstractCoroutine(_example)
|
||||||
|
|
||||||
|
self.assertEqual(repr(provider),
|
||||||
|
'<dependency_injector.providers.'
|
||||||
|
'AbstractCoroutine({0}) at {1}>'.format(
|
||||||
|
repr(_example),
|
||||||
|
hex(id(provider))))
|
||||||
|
|
||||||
|
|
||||||
|
class CoroutineDelegateTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.delegated = providers.Coroutine(_example)
|
||||||
|
self.delegate = providers.CoroutineDelegate(self.delegated)
|
||||||
|
|
||||||
|
def test_is_delegate(self):
|
||||||
|
self.assertIsInstance(self.delegate, providers.Delegate)
|
||||||
|
|
||||||
|
def test_init_with_not_callable(self):
|
||||||
|
self.assertRaises(errors.Error,
|
||||||
|
providers.CoroutineDelegate,
|
||||||
|
providers.Object(object()))
|
18
tox.ini
18
tox.ini
|
@ -6,11 +6,11 @@ envlist=
|
||||||
deps=
|
deps=
|
||||||
unittest2
|
unittest2
|
||||||
commands=
|
commands=
|
||||||
unit2 discover tests/unit
|
unit2 discover -s tests/unit -p test_*_py3.py
|
||||||
|
|
||||||
[testenv:coveralls]
|
[testenv:coveralls]
|
||||||
passenv=TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH DEPENDENCY_INJECTOR_DEBUG_MODE
|
passenv=TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH DEPENDENCY_INJECTOR_DEBUG_MODE
|
||||||
basepython=python2.7
|
basepython=python3.6
|
||||||
usedevelop=True
|
usedevelop=True
|
||||||
deps=
|
deps=
|
||||||
{[testenv]deps}
|
{[testenv]deps}
|
||||||
|
@ -19,10 +19,22 @@ deps=
|
||||||
coveralls
|
coveralls
|
||||||
commands=
|
commands=
|
||||||
coverage erase
|
coverage erase
|
||||||
coverage run --rcfile=./.coveragerc -m unittest2 discover tests/unit
|
coverage run --rcfile=./.coveragerc -m unittest2 discover -s tests/unit/ -p test_*_py3.py
|
||||||
coverage report --rcfile=./.coveragerc
|
coverage report --rcfile=./.coveragerc
|
||||||
coveralls
|
coveralls
|
||||||
|
|
||||||
|
[testenv:py26]
|
||||||
|
commands=
|
||||||
|
unit2 discover -s tests/unit -p test_*_py2_py3.py
|
||||||
|
|
||||||
|
[testenv:py27]
|
||||||
|
commands=
|
||||||
|
unit2 discover -s tests/unit -p test_*_py2_py3.py
|
||||||
|
|
||||||
|
[testenv:pypy]
|
||||||
|
commands=
|
||||||
|
unit2 discover -s tests/unit -p test_*_py2_py3.py
|
||||||
|
|
||||||
[testenv:pylint]
|
[testenv:pylint]
|
||||||
deps=
|
deps=
|
||||||
pylint
|
pylint
|
||||||
|
|
Loading…
Reference in New Issue
Block a user