Skip to content

Commit 9a785de

Browse files
authored
Coroutine provider (ets-labs#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
1 parent ac0e5eb commit 9a785de

25 files changed

+28403
-21617
lines changed

.travis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ language:
77
- python
88
matrix:
99
include:
10-
- python: 2.7
10+
- python: 3.6
1111
env: TOXENV=coveralls DEPENDENCY_INJECTOR_DEBUG_MODE=1
1212
install:
1313
- pip install tox
1414
- pip install cython
1515
- make cythonize
16-
- python: 2.7
16+
- python: 3.6
1717
env: TOXENV=pylint
18-
- python: 2.7
18+
- python: 3.6
1919
env: TOXENV=flake8
20-
- python: 2.7
20+
- python: 3.6
2121
env: TOXENV=pydocstyle
2222
- python: 2.7
2323
env: TOXENV=py27

Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,17 @@ install: uninstall clean cythonize
4242
uninstall:
4343
- pip uninstall -y -q dependency-injector 2> /dev/null
4444

45-
test: build
45+
test-py2: build
4646
# Unit tests with coverage report
4747
coverage erase
48-
coverage run --rcfile=./.coveragerc -m unittest2 discover tests/unit
48+
coverage run --rcfile=./.coveragerc -m unittest2 discover -s tests/unit/ -p test_*_py2_py3.py
49+
coverage report --rcfile=./.coveragerc
50+
coverage html --rcfile=./.coveragerc
51+
52+
test-py3: build
53+
# Unit tests with coverage report
54+
coverage erase
55+
coverage run --rcfile=./.coveragerc -m unittest2 discover -s tests/unit/ -p test_*py3.py
4956
coverage report --rcfile=./.coveragerc
5057
coverage html --rcfile=./.coveragerc
5158

docs/main/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ follows `Semantic versioning`_
99

1010
Development version
1111
-------------------
12+
- Add ``Coroutine`` provider.
13+
- Add ``DelegatedCoroutine`` provider.
14+
- Add ``AbstractCoroutine`` provider.
15+
- Add ``CoroutineDelegate`` provider.
1216
- Regenerate C sources using Cython 0.28.5.
1317

1418
3.13.2

docs/providers/callable.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Callable providers and injections
1111
:py:class:`Callable` provider takes a various number of positional and keyword
1212
arguments that are used as wrapped callable injections. Every time, when
1313
:py:class:`Callable` provider is called, positional and keyword argument
14-
injections would be passed as an callable arguments.
14+
injections would be passed as callable arguments.
1515

1616
Injections are done according to the next rules:
1717

docs/providers/coroutine.rst

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
Coroutine providers
2+
-------------------
3+
4+
.. currentmodule:: dependency_injector.providers
5+
6+
:py:class:`Coroutine` provider create wrapped coroutine on every call.
7+
8+
:py:class:`Coroutine` provider is designed for making better integration with
9+
``asyncio`` coroutines. In particular, :py:class:`Coroutine` provider returns
10+
``True`` for ``asyncio.iscoroutinefunction()`` checks.
11+
12+
.. note::
13+
14+
:py:class:`Coroutine` provider works only for Python 3.4+.
15+
16+
Example of usage :py:class:`Coroutine` provider with ``async / await``-based
17+
coroutine:
18+
19+
.. literalinclude:: ../../examples/providers/coroutine_async_await.py
20+
:language: python
21+
:linenos:
22+
23+
Coroutine providers and injections
24+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25+
26+
:py:class:`Coroutine` provider takes a various number of positional and keyword
27+
arguments that are used as wrapped coroutine injections. Every time, when
28+
:py:class:`Coroutine` provider is called, positional and keyword argument
29+
injections would be passed as coroutine arguments.
30+
31+
Injections are done according to the next rules:
32+
33+
+ All providers (instances of :py:class:`Provider`) are called every time
34+
when injection needs to be done.
35+
+ Providers could be injected "as is" (delegated), if it is defined obviously.
36+
Check out :ref:`coroutine_providers_delegation`.
37+
+ All other injectable values are provided *"as is"*.
38+
+ Positional context arguments will be appended after :py:class:`Coroutine`
39+
positional injections.
40+
+ Keyword context arguments have priority on :py:class:`Coroutine` keyword
41+
injections and will be merged over them.
42+
43+
.. note::
44+
45+
Examples of making injections could be found in API docs -
46+
:py:class:`Coroutine`.
47+
48+
.. _coroutine_providers_delegation:
49+
50+
Coroutine providers delegation
51+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52+
53+
:py:class:`Coroutine` provider could be delegated to any other provider via
54+
any kind of injection.
55+
56+
Delegation of :py:class:`Coroutine` providers is the same as
57+
:py:class:`Factory` providers delegation, please follow
58+
:ref:`factory_providers_delegation` section for examples (with exception
59+
of using :py:class:`DelegatedCoroutine` instead of
60+
:py:class:`DelegatedFactory`).
61+
62+
Abstract coroutine providers
63+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
64+
65+
:py:class:`AbstractCoroutine` provider is a :py:class:`Coroutine` provider that
66+
must be explicitly overridden before calling.
67+
68+
Behaviour of :py:class:`AbstractCoroutine` providers is the same as of
69+
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
70+
section for examples (with exception of using :py:class:`AbstractCoroutine`
71+
provider instead of :py:class:`AbstractFactory`).
72+
73+
.. disqus::

docs/providers/factory.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Factory providers and __init__ injections
2222
:py:class:`Factory` takes a various number of positional and keyword arguments
2323
that are used as ``__init__()`` injections. Every time, when
2424
:py:class:`Factory` creates new one instance, positional and keyword
25-
argument injections would be passed as an instance's arguments.
25+
argument injections would be passed as instance arguments.
2626

2727
Injections are done according to the next rules:
2828

docs/providers/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Providers package API docs - :py:mod:`dependency_injector.providers`
2020
factory
2121
singleton
2222
callable
23+
coroutine
2324
object
2425
dependency
2526
overriding

examples/providers/coroutine.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""`Coroutine` providers example with @asyncio.coroutine decorator.
2+
3+
Current example works only fot Python 3.4+.
4+
"""
5+
6+
import asyncio
7+
8+
import dependency_injector.providers as providers
9+
10+
11+
@asyncio.coroutine
12+
def coroutine_function(arg1, arg2):
13+
"""Sample coroutine function."""
14+
yield from asyncio.sleep(0.1)
15+
return arg1, arg2
16+
17+
18+
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
19+
20+
21+
if __name__ == '__main__':
22+
loop = asyncio.get_event_loop()
23+
arg1, arg2 = loop.run_until_complete(coroutine_provider())
24+
25+
assert (arg1, arg2) == (1, 2)
26+
assert asyncio.iscoroutinefunction(coroutine_provider)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""`Coroutine` providers example with async / await syntax.
2+
3+
Current example works only fot Python 3.5+.
4+
"""
5+
6+
import asyncio
7+
8+
import dependency_injector.providers as providers
9+
10+
11+
async def coroutine_function(arg1, arg2):
12+
"""Sample coroutine function."""
13+
await asyncio.sleep(0.1)
14+
return arg1, arg2
15+
16+
17+
coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2)
18+
19+
20+
if __name__ == '__main__':
21+
loop = asyncio.get_event_loop()
22+
arg1, arg2 = loop.run_until_complete(coroutine_provider())
23+
24+
assert (arg1, arg2) == (1, 2)
25+
assert asyncio.iscoroutinefunction(coroutine_provider)

0 commit comments

Comments
 (0)