mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-10-31 07:57:43 +03:00 
			
		
		
		
	Merge branch 'release/4.39.1' into master
This commit is contained in:
		
						commit
						4188f721d6
					
				|  | @ -7,6 +7,12 @@ that were made in every particular version. | |||
| From version 0.7.6 *Dependency Injector* framework strictly  | ||||
| follows `Semantic versioning`_ | ||||
| 
 | ||||
| 4.39.1 | ||||
| ------ | ||||
| - Fix bug `#574 <https://github.com/ets-labs/python-dependency-injector/issues/574>`_: | ||||
|   "``@inject`` breaks ``inspect.iscoroutinefunction``". Thanks to | ||||
|   `@burritoatspoton (Rafał Burczyński) <https://github.com/burritoatspoton>`_ for reporting the issue. | ||||
| 
 | ||||
| 4.39.0 | ||||
| ------ | ||||
| - Optimize injections and wiring from x1.5 to x7 times depending on the use case. | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| # TODO: unpin 3.5.0 when this bug is fixed: https://github.com/sphinx-doc/sphinx/issues/8885 | ||||
| sphinx<3.5.0 | ||||
| -e git://github.com/rmk135/sphinxcontrib-disqus.git#egg=sphinxcontrib-disqus | ||||
| -e git+https://github.com/rmk135/sphinxcontrib-disqus.git#egg=sphinxcontrib-disqus | ||||
| 
 | ||||
| -r requirements-ext.txt | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| """Top-level package.""" | ||||
| 
 | ||||
| __version__ = "4.39.0" | ||||
| __version__ = "4.39.1" | ||||
| """Version number. | ||||
| 
 | ||||
| :type: str | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -9,23 +9,27 @@ import types | |||
| from . import providers | ||||
| from .wiring import _Marker | ||||
| 
 | ||||
| from .providers cimport Provider | ||||
| 
 | ||||
| 
 | ||||
| def _get_sync_patched(fn): | ||||
|     @functools.wraps(fn) | ||||
|     def _patched(*args, **kwargs): | ||||
|         cdef object result | ||||
|         cdef dict to_inject | ||||
|         cdef object arg_key | ||||
|         cdef Provider provider | ||||
| 
 | ||||
|         to_inject = kwargs.copy() | ||||
|         for injection, provider in _patched.__injections__.items(): | ||||
|             if injection not in kwargs or isinstance(kwargs[injection], _Marker): | ||||
|                 to_inject[injection] = provider() | ||||
|         for arg_key, provider in _patched.__injections__.items(): | ||||
|             if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker): | ||||
|                 to_inject[arg_key] = provider() | ||||
| 
 | ||||
|         result = fn(*args, **to_inject) | ||||
| 
 | ||||
|         if _patched.__closing__: | ||||
|             for injection, provider in _patched.__closing__.items(): | ||||
|                 if injection in kwargs and not isinstance(kwargs[injection], _Marker): | ||||
|             for arg_key, provider in _patched.__closing__.items(): | ||||
|                 if arg_key in kwargs and not isinstance(kwargs[arg_key], _Marker): | ||||
|                     continue | ||||
|                 if not isinstance(provider, providers.Resource): | ||||
|                     continue | ||||
|  | @ -35,49 +39,45 @@ def _get_sync_patched(fn): | |||
|     return _patched | ||||
| 
 | ||||
| 
 | ||||
| def _get_async_patched(fn): | ||||
|     @functools.wraps(fn) | ||||
|     async def _patched(*args, **kwargs): | ||||
|         cdef object result | ||||
|         cdef dict to_inject | ||||
|         cdef list to_inject_await = [] | ||||
|         cdef list to_close_await = [] | ||||
| async def _async_inject(object fn, tuple args, dict kwargs, dict injections, dict closings): | ||||
|     cdef object result | ||||
|     cdef dict to_inject | ||||
|     cdef list to_inject_await = [] | ||||
|     cdef list to_close_await = [] | ||||
|     cdef object arg_key | ||||
|     cdef Provider provider | ||||
| 
 | ||||
|         to_inject = kwargs.copy() | ||||
|         for injection, provider in _patched.__injections__.items(): | ||||
|             if injection not in kwargs or isinstance(kwargs[injection], _Marker): | ||||
|                 provide = provider() | ||||
|                 if _isawaitable(provide): | ||||
|                     to_inject_await.append((injection, provide)) | ||||
|                 else: | ||||
|                     to_inject[injection] = provide | ||||
|     to_inject = kwargs.copy() | ||||
|     for arg_key, provider in injections.items(): | ||||
|         if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker): | ||||
|             provide = provider() | ||||
|             if provider.is_async_mode_enabled(): | ||||
|                 to_inject_await.append((arg_key, provide)) | ||||
|             elif _isawaitable(provide): | ||||
|                 to_inject_await.append((arg_key, provide)) | ||||
|             else: | ||||
|                 to_inject[arg_key] = provide | ||||
| 
 | ||||
|         if to_inject_await: | ||||
|             async_to_inject = await asyncio.gather(*(provide for _, provide in to_inject_await)) | ||||
|             for provide, (injection, _) in zip(async_to_inject, to_inject_await): | ||||
|                 to_inject[injection] = provide | ||||
|     if to_inject_await: | ||||
|         async_to_inject = await asyncio.gather(*(provide for _, provide in to_inject_await)) | ||||
|         for provide, (injection, _) in zip(async_to_inject, to_inject_await): | ||||
|             to_inject[injection] = provide | ||||
| 
 | ||||
|         result = await fn(*args, **to_inject) | ||||
|     result = await fn(*args, **to_inject) | ||||
| 
 | ||||
|         if _patched.__closing__: | ||||
|             for injection, provider in _patched.__closing__.items(): | ||||
|                 if injection in kwargs \ | ||||
|                         and isinstance(kwargs[injection], _Marker): | ||||
|                     continue | ||||
|                 if not isinstance(provider, providers.Resource): | ||||
|                     continue | ||||
|                 shutdown = provider.shutdown() | ||||
|                 if _isawaitable(shutdown): | ||||
|                     to_close_await.append(shutdown) | ||||
|     if closings: | ||||
|         for arg_key, provider in closings.items(): | ||||
|             if arg_key in kwargs and isinstance(kwargs[arg_key], _Marker): | ||||
|                 continue | ||||
|             if not isinstance(provider, providers.Resource): | ||||
|                 continue | ||||
|             shutdown = provider.shutdown() | ||||
|             if _isawaitable(shutdown): | ||||
|                 to_close_await.append(shutdown) | ||||
| 
 | ||||
|             await asyncio.gather(*to_close_await) | ||||
|         await asyncio.gather(*to_close_await) | ||||
| 
 | ||||
|         return result | ||||
| 
 | ||||
|     # Hotfix for iscoroutinefunction() for Cython < 3.0.0; can be removed after migration to Cython 3.0.0+ | ||||
|     _patched._is_coroutine = asyncio.coroutines._is_coroutine | ||||
| 
 | ||||
|     return _patched | ||||
|     return result | ||||
| 
 | ||||
| 
 | ||||
| cdef bint _isawaitable(object instance): | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -25,6 +25,10 @@ cdef class Provider(object): | |||
|     cdef tuple __overrides | ||||
|     cdef int __async_mode | ||||
| 
 | ||||
|     cpdef bint is_async_mode_enabled(self) | ||||
|     cpdef bint is_async_mode_disabled(self) | ||||
|     cpdef bint is_async_mode_undefined(self) | ||||
| 
 | ||||
|     cpdef object _provide(self, tuple args, dict kwargs) | ||||
|     cpdef void _copy_overridings(self, Provider copied, dict memo) | ||||
| 
 | ||||
|  |  | |||
|  | @ -406,15 +406,15 @@ cdef class Provider(object): | |||
|         """ | ||||
|         self.__async_mode = ASYNC_MODE_UNDEFINED | ||||
| 
 | ||||
|     def is_async_mode_enabled(self): | ||||
|     cpdef bint is_async_mode_enabled(self): | ||||
|         """Check if async mode is enabled.""" | ||||
|         return self.__async_mode == ASYNC_MODE_ENABLED | ||||
| 
 | ||||
|     def is_async_mode_disabled(self): | ||||
|     cpdef bint is_async_mode_disabled(self): | ||||
|         """Check if async mode is disabled.""" | ||||
|         return self.__async_mode == ASYNC_MODE_DISABLED | ||||
| 
 | ||||
|     def is_async_mode_undefined(self): | ||||
|     cpdef bint is_async_mode_undefined(self): | ||||
|         """Check if async mode is undefined.""" | ||||
|         return self.__async_mode == ASYNC_MODE_UNDEFINED | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| """Wiring module.""" | ||||
| 
 | ||||
| import functools | ||||
| import inspect | ||||
| import importlib | ||||
| import importlib.machinery | ||||
|  | @ -895,4 +895,19 @@ _loader = AutoLoader() | |||
| 
 | ||||
| # Optimizations | ||||
| from ._cwiring import _get_sync_patched  # noqa | ||||
| from ._cwiring import _get_async_patched  # noqa | ||||
| from ._cwiring import _async_inject  # noqa | ||||
| 
 | ||||
| 
 | ||||
| # Wiring uses the following Python wrapper because there is | ||||
| # no possibility to compile a first-type citizen coroutine in Cython. | ||||
| def _get_async_patched(fn): | ||||
|     @functools.wraps(fn) | ||||
|     async def _patched(*args, **kwargs): | ||||
|         return await _async_inject( | ||||
|             fn, | ||||
|             args, | ||||
|             kwargs, | ||||
|             _patched.__injections__, | ||||
|             _patched.__closing__, | ||||
|         ) | ||||
|     return _patched | ||||
|  |  | |||
							
								
								
									
										22
									
								
								tests/unit/wiring/test_introspection_py36.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/unit/wiring/test_introspection_py36.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| """Tests for compatibility of @inject-patched functions with asyncio and inspect module checks.""" | ||||
| 
 | ||||
| import asyncio | ||||
| import inspect | ||||
| 
 | ||||
| from dependency_injector.wiring import inject | ||||
| 
 | ||||
| 
 | ||||
| def test_asyncio_iscoroutinefunction(): | ||||
|     @inject | ||||
|     async def foo(): | ||||
|         ... | ||||
| 
 | ||||
|     assert asyncio.iscoroutinefunction(foo) | ||||
| 
 | ||||
| 
 | ||||
| def test_inspect_iscoroutinefunction(): | ||||
|     @inject | ||||
|     async def foo(): | ||||
|         ... | ||||
| 
 | ||||
|     assert inspect.iscoroutinefunction(foo) | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user