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  | From version 0.7.6 *Dependency Injector* framework strictly  | ||||||
| follows `Semantic versioning`_ | 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 | 4.39.0 | ||||||
| ------ | ------ | ||||||
| - Optimize injections and wiring from x1.5 to x7 times depending on the use case. | - 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 | # TODO: unpin 3.5.0 when this bug is fixed: https://github.com/sphinx-doc/sphinx/issues/8885 | ||||||
| sphinx<3.5.0 | 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 | -r requirements-ext.txt | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| """Top-level package.""" | """Top-level package.""" | ||||||
| 
 | 
 | ||||||
| __version__ = "4.39.0" | __version__ = "4.39.1" | ||||||
| """Version number. | """Version number. | ||||||
| 
 | 
 | ||||||
| :type: str | :type: str | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -9,23 +9,27 @@ import types | ||||||
| from . import providers | from . import providers | ||||||
| from .wiring import _Marker | from .wiring import _Marker | ||||||
| 
 | 
 | ||||||
|  | from .providers cimport Provider | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| def _get_sync_patched(fn): | def _get_sync_patched(fn): | ||||||
|     @functools.wraps(fn) |     @functools.wraps(fn) | ||||||
|     def _patched(*args, **kwargs): |     def _patched(*args, **kwargs): | ||||||
|         cdef object result |         cdef object result | ||||||
|         cdef dict to_inject |         cdef dict to_inject | ||||||
|  |         cdef object arg_key | ||||||
|  |         cdef Provider provider | ||||||
| 
 | 
 | ||||||
|         to_inject = kwargs.copy() |         to_inject = kwargs.copy() | ||||||
|         for injection, provider in _patched.__injections__.items(): |         for arg_key, provider in _patched.__injections__.items(): | ||||||
|             if injection not in kwargs or isinstance(kwargs[injection], _Marker): |             if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker): | ||||||
|                 to_inject[injection] = provider() |                 to_inject[arg_key] = provider() | ||||||
| 
 | 
 | ||||||
|         result = fn(*args, **to_inject) |         result = fn(*args, **to_inject) | ||||||
| 
 | 
 | ||||||
|         if _patched.__closing__: |         if _patched.__closing__: | ||||||
|             for injection, provider in _patched.__closing__.items(): |             for arg_key, provider in _patched.__closing__.items(): | ||||||
|                 if injection in kwargs and not isinstance(kwargs[injection], _Marker): |                 if arg_key in kwargs and not isinstance(kwargs[arg_key], _Marker): | ||||||
|                     continue |                     continue | ||||||
|                 if not isinstance(provider, providers.Resource): |                 if not isinstance(provider, providers.Resource): | ||||||
|                     continue |                     continue | ||||||
|  | @ -35,49 +39,45 @@ def _get_sync_patched(fn): | ||||||
|     return _patched |     return _patched | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _get_async_patched(fn): | async def _async_inject(object fn, tuple args, dict kwargs, dict injections, dict closings): | ||||||
|     @functools.wraps(fn) |     cdef object result | ||||||
|     async def _patched(*args, **kwargs): |     cdef dict to_inject | ||||||
|         cdef object result |     cdef list to_inject_await = [] | ||||||
|         cdef dict to_inject |     cdef list to_close_await = [] | ||||||
|         cdef list to_inject_await = [] |     cdef object arg_key | ||||||
|         cdef list to_close_await = [] |     cdef Provider provider | ||||||
| 
 | 
 | ||||||
|         to_inject = kwargs.copy() |     to_inject = kwargs.copy() | ||||||
|         for injection, provider in _patched.__injections__.items(): |     for arg_key, provider in injections.items(): | ||||||
|             if injection not in kwargs or isinstance(kwargs[injection], _Marker): |         if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker): | ||||||
|                 provide = provider() |             provide = provider() | ||||||
|                 if _isawaitable(provide): |             if provider.is_async_mode_enabled(): | ||||||
|                     to_inject_await.append((injection, provide)) |                 to_inject_await.append((arg_key, provide)) | ||||||
|                 else: |             elif _isawaitable(provide): | ||||||
|                     to_inject[injection] = provide |                 to_inject_await.append((arg_key, provide)) | ||||||
|  |             else: | ||||||
|  |                 to_inject[arg_key] = provide | ||||||
| 
 | 
 | ||||||
|         if to_inject_await: |     if to_inject_await: | ||||||
|             async_to_inject = await asyncio.gather(*(provide for _, provide in 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): |         for provide, (injection, _) in zip(async_to_inject, to_inject_await): | ||||||
|                 to_inject[injection] = provide |             to_inject[injection] = provide | ||||||
| 
 | 
 | ||||||
|         result = await fn(*args, **to_inject) |     result = await fn(*args, **to_inject) | ||||||
| 
 | 
 | ||||||
|         if _patched.__closing__: |     if closings: | ||||||
|             for injection, provider in _patched.__closing__.items(): |         for arg_key, provider in closings.items(): | ||||||
|                 if injection in kwargs \ |             if arg_key in kwargs and isinstance(kwargs[arg_key], _Marker): | ||||||
|                         and isinstance(kwargs[injection], _Marker): |                 continue | ||||||
|                     continue |             if not isinstance(provider, providers.Resource): | ||||||
|                 if not isinstance(provider, providers.Resource): |                 continue | ||||||
|                     continue |             shutdown = provider.shutdown() | ||||||
|                 shutdown = provider.shutdown() |             if _isawaitable(shutdown): | ||||||
|                 if _isawaitable(shutdown): |                 to_close_await.append(shutdown) | ||||||
|                     to_close_await.append(shutdown) |  | ||||||
| 
 | 
 | ||||||
|             await asyncio.gather(*to_close_await) |         await asyncio.gather(*to_close_await) | ||||||
| 
 | 
 | ||||||
|         return result |     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 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef bint _isawaitable(object instance): | 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 tuple __overrides | ||||||
|     cdef int __async_mode |     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 object _provide(self, tuple args, dict kwargs) | ||||||
|     cpdef void _copy_overridings(self, Provider copied, dict memo) |     cpdef void _copy_overridings(self, Provider copied, dict memo) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -406,15 +406,15 @@ cdef class Provider(object): | ||||||
|         """ |         """ | ||||||
|         self.__async_mode = ASYNC_MODE_UNDEFINED |         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.""" |         """Check if async mode is enabled.""" | ||||||
|         return self.__async_mode == ASYNC_MODE_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.""" |         """Check if async mode is disabled.""" | ||||||
|         return self.__async_mode == ASYNC_MODE_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.""" |         """Check if async mode is undefined.""" | ||||||
|         return self.__async_mode == ASYNC_MODE_UNDEFINED |         return self.__async_mode == ASYNC_MODE_UNDEFINED | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| """Wiring module.""" | """Wiring module.""" | ||||||
| 
 | import functools | ||||||
| import inspect | import inspect | ||||||
| import importlib | import importlib | ||||||
| import importlib.machinery | import importlib.machinery | ||||||
|  | @ -895,4 +895,19 @@ _loader = AutoLoader() | ||||||
| 
 | 
 | ||||||
| # Optimizations | # Optimizations | ||||||
| from ._cwiring import _get_sync_patched  # noqa | 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