mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-10-26 05:31:27 +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