mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-21 17:16:46 +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
|
||||
matrix:
|
||||
include:
|
||||
- python: 2.7
|
||||
- python: 3.6
|
||||
env: TOXENV=coveralls DEPENDENCY_INJECTOR_DEBUG_MODE=1
|
||||
install:
|
||||
- pip install tox
|
||||
- pip install cython
|
||||
- make cythonize
|
||||
- python: 2.7
|
||||
- python: 3.6
|
||||
env: TOXENV=pylint
|
||||
- python: 2.7
|
||||
- python: 3.6
|
||||
env: TOXENV=flake8
|
||||
- python: 2.7
|
||||
- python: 3.6
|
||||
env: TOXENV=pydocstyle
|
||||
- python: 2.7
|
||||
env: TOXENV=py27
|
||||
|
|
11
Makefile
11
Makefile
|
@ -42,10 +42,17 @@ install: uninstall clean cythonize
|
|||
uninstall:
|
||||
- pip uninstall -y -q dependency-injector 2> /dev/null
|
||||
|
||||
test: build
|
||||
test-py2: build
|
||||
# Unit tests with coverage report
|
||||
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 html --rcfile=./.coveragerc
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@ follows `Semantic versioning`_
|
|||
|
||||
Development version
|
||||
-------------------
|
||||
- Add ``Coroutine`` provider.
|
||||
- Add ``DelegatedCoroutine`` provider.
|
||||
- Add ``AbstractCoroutine`` provider.
|
||||
- Add ``CoroutineDelegate`` provider.
|
||||
- Regenerate C sources using Cython 0.28.5.
|
||||
|
||||
3.13.2
|
||||
|
|
|
@ -11,7 +11,7 @@ Callable providers and injections
|
|||
:py:class:`Callable` provider takes a various number of positional and keyword
|
||||
arguments that are used as wrapped callable injections. Every time, when
|
||||
: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:
|
||||
|
||||
|
|
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
|
||||
that are used as ``__init__()`` injections. Every time, when
|
||||
: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:
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ Providers package API docs - :py:mod:`dependency_injector.providers`
|
|||
factory
|
||||
singleton
|
||||
callable
|
||||
coroutine
|
||||
object
|
||||
dependency
|
||||
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
|
||||
|
||||
|
||||
# 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
|
||||
cdef class Configuration(Object):
|
||||
cdef str __name
|
||||
|
|
|
@ -9,6 +9,19 @@ import sys
|
|||
import types
|
||||
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 (
|
||||
Error,
|
||||
NoSuchProviderError,
|
||||
|
@ -848,6 +861,128 @@ cdef class CallableDelegate(Delegate):
|
|||
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):
|
||||
"""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=
|
||||
unittest2
|
||||
commands=
|
||||
unit2 discover tests/unit
|
||||
unit2 discover -s tests/unit -p test_*_py3.py
|
||||
|
||||
[testenv:coveralls]
|
||||
passenv=TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH DEPENDENCY_INJECTOR_DEBUG_MODE
|
||||
basepython=python2.7
|
||||
basepython=python3.6
|
||||
usedevelop=True
|
||||
deps=
|
||||
{[testenv]deps}
|
||||
|
@ -19,10 +19,22 @@ deps=
|
|||
coveralls
|
||||
commands=
|
||||
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
|
||||
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]
|
||||
deps=
|
||||
pylint
|
||||
|
|
Loading…
Reference in New Issue
Block a user