Merge branch 'release/3.14.0' into master

This commit is contained in:
Roman Mogylatov 2018-10-19 13:01:54 +03:00
commit 62b0f914b9
27 changed files with 9985 additions and 3292 deletions

View File

@ -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

View File

@ -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

View File

@ -7,6 +7,16 @@ that were made in every particular version.
From version 0.7.6 *Dependency Injector* framework strictly
follows `Semantic versioning`_
3.14.0
------
- Add ``Coroutine`` provider.
- Add ``DelegatedCoroutine`` provider.
- Add ``AbstractCoroutine`` provider.
- Add ``CoroutineDelegate`` provider.
- Fix type-hinting of ``*args`` & ``**kwargs`` that was specified in doc
blocks of various providers and caused inspection problems in PyCharm.
- Regenerate C sources using Cython 0.28.5.
3.13.2
------
- Add additional benchmark of ``Factory`` provider.

View File

@ -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:

View 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::

View File

@ -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:

View File

@ -20,6 +20,7 @@ Providers package API docs - :py:mod:`dependency_injector.providers`
factory
singleton
callable
coroutine
object
dependency
overriding

View 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)

View 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)

View File

@ -1,4 +1,4 @@
cython==0.28.4
cython==0.28.5
tox
unittest2
coverage

View File

@ -1,6 +1,6 @@
"""Dependency injector top-level package."""
__version__ = '3.13.2'
__version__ = '3.14.0'
"""Version number that follows semantic versioning.
:type: str

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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,
@ -339,12 +352,6 @@ cdef class Dependency(Provider):
def __call__(self, *args, **kwargs):
"""Return provided instance.
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
:raise: :py:exc:`dependency_injector.errors.Error`
:rtype: object
@ -621,12 +628,6 @@ cdef class Callable(Provider):
: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, '
@ -689,10 +690,7 @@ cdef class Callable(Provider):
return tuple(args)
def add_args(self, *args):
"""Add postional argument injections.
:param args: Tuple of injections.
:type args: tuple
"""Add positional argument injections.
:return: Reference ``self``
"""
@ -705,9 +703,6 @@ cdef class Callable(Provider):
Existing positional argument injections are dropped.
:param args: Tuple of injections.
:type args: tuple
:return: Reference ``self``
"""
self.__args = parse_positional_injections(args)
@ -739,9 +734,6 @@ cdef class Callable(Provider):
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)
@ -753,9 +745,6 @@ cdef class Callable(Provider):
Existing keyword argument injections are dropped.
:param kwargs: Dictionary of injections.
:type kwargs: dict
:return: Reference ``self``
"""
self.__kwargs = parse_named_injections(kwargs)
@ -848,6 +837,122 @@ 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
"""
if not asyncio:
raise Error('Package 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.
@ -1076,12 +1181,6 @@ cdef class Factory(Provider):
: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)):
@ -1135,9 +1234,6 @@ cdef class Factory(Provider):
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)
@ -1148,9 +1244,6 @@ cdef class Factory(Provider):
Existing __init__ positional argument injections are dropped.
:param args: Tuple of injections.
:type args: tuple
:return: Reference ``self``
"""
self.__instantiator.set_args(*args)
@ -1172,9 +1265,6 @@ cdef class Factory(Provider):
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)
@ -1185,9 +1275,6 @@ cdef class Factory(Provider):
Existing __init__ keyword argument injections are dropped.
:param kwargs: Dictionary of injections.
:type kwargs: dict
:return: Reference ``self``
"""
self.__instantiator.set_kwargs(**kwargs)
@ -1217,9 +1304,6 @@ cdef class Factory(Provider):
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)
@ -1231,9 +1315,6 @@ cdef class Factory(Provider):
Existing attribute injections are dropped.
:param args: Tuple of injections.
:type args: tuple
:return: Reference ``self``
"""
self.__attributes = parse_named_injections(kwargs)
@ -1394,9 +1475,6 @@ cdef class FactoryAggregate(Provider):
def override(self, _):
"""Override provider with another provider.
:param provider: Overriding provider.
:type provider: :py:class:`Provider`
:raise: :py:exc:`dependency_injector.errors.Error`
:return: Overriding context.
@ -1423,12 +1501,6 @@ cdef class BaseSingleton(Provider):
: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)):
@ -1477,10 +1549,7 @@ cdef class BaseSingleton(Provider):
return self.__instantiator.args
def add_args(self, *args):
"""Add __init__ postional argument injections.
:param args: Tuple of injections.
:type args: tuple
"""Add __init__ positional argument injections.
:return: Reference ``self``
"""
@ -1488,20 +1557,17 @@ cdef class BaseSingleton(Provider):
return self
def set_args(self, *args):
"""Set __init__ postional argument injections.
"""Set __init__ positional 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.
"""Drop __init__ positional argument injections.
:return: Reference ``self``
"""
@ -1516,9 +1582,6 @@ cdef class BaseSingleton(Provider):
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)
@ -1529,9 +1592,6 @@ cdef class BaseSingleton(Provider):
Existing __init__ keyword argument injections are dropped.
:param kwargs: Dictionary of injections.
:type kwargs: dict
:return: Reference ``self``
"""
self.__instantiator.set_kwargs(**kwargs)
@ -1553,9 +1613,6 @@ cdef class BaseSingleton(Provider):
def add_attributes(self, **kwargs):
"""Add attribute injections.
:param args: Tuple of injections.
:type args: tuple
:return: Reference ``self``
"""
self.__instantiator.add_attributes(**kwargs)
@ -1566,9 +1623,6 @@ cdef class BaseSingleton(Provider):
Existing attribute injections are dropped.
:param args: Tuple of injections.
:type args: tuple
:return: Reference ``self``
"""
self.__instantiator.set_attributes(**kwargs)
@ -1626,12 +1680,6 @@ cdef class Singleton(BaseSingleton):
: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)
@ -1686,12 +1734,6 @@ cdef class ThreadSafeSingleton(BaseSingleton):
: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.__storage_lock = self.__class__.storage_lock
@ -1757,12 +1799,6 @@ cdef class ThreadLocalSingleton(BaseSingleton):
: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)

View 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
View File

@ -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