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

View File

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

View File

@ -7,6 +7,16 @@ that were made in every particular version.
From version 0.7.6 *Dependency Injector* framework strictly From version 0.7.6 *Dependency Injector* framework strictly
follows `Semantic versioning`_ 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 3.13.2
------ ------
- Add additional benchmark of ``Factory`` provider. - 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 :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:

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

View File

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

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 tox
unittest2 unittest2
coverage coverage

View File

@ -1,6 +1,6 @@
"""Dependency injector top-level package.""" """Dependency injector top-level package."""
__version__ = '3.13.2' __version__ = '3.14.0'
"""Version number that follows semantic versioning. """Version number that follows semantic versioning.
:type: str :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 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

View File

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