mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-11-04 09:57:37 +03:00 
			
		
		
		
	Improve async mode exceptions handling
This commit is contained in:
		
							parent
							
								
									131373227c
								
							
						
					
					
						commit
						77b8d55203
					
				| 
						 | 
					@ -9,8 +9,8 @@ follows `Semantic versioning`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Development version
 | 
					Development version
 | 
				
			||||||
-------------------
 | 
					-------------------
 | 
				
			||||||
- Improve async mode exceptions handling to prevent infinite hanging when exception occurs.
 | 
					- Improve async mode exceptions handling.
 | 
				
			||||||
- Fix double printing of exception when resource initialization causes an error.
 | 
					- Fix double printing of exception when resource initialization causes an error in async mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4.23.1
 | 
					4.23.1
 | 
				
			||||||
------
 | 
					------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -457,11 +457,12 @@ cdef inline void __async_prepare_args_kwargs_callback(
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        awaited = future.result()
 | 
					        awaited = future.result()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for value, (key, _) in zip(awaited, awaitables):
 | 
				
			||||||
 | 
					            args[key] = value
 | 
				
			||||||
    except Exception as exception:
 | 
					    except Exception as exception:
 | 
				
			||||||
        future_result.set_exception(exception)
 | 
					        future_result.set_exception(exception)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        for value, (key, _) in zip(awaited, awaitables):
 | 
					 | 
				
			||||||
            args[key] = value
 | 
					 | 
				
			||||||
        future_result.set_result(args)
 | 
					        future_result.set_result(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -502,9 +503,15 @@ cdef inline object __async_inject_attributes(future_instance, future_attributes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef inline void __async_inject_attributes_callback(object future_result, object future):
 | 
					cdef inline void __async_inject_attributes_callback(object future_result, object future):
 | 
				
			||||||
    instance, attributes = future.result()
 | 
					    try:
 | 
				
			||||||
    __inject_attributes(instance, attributes)
 | 
					        instance, attributes = future.result()
 | 
				
			||||||
    future_result.set_result(instance)
 | 
					
 | 
				
			||||||
 | 
					        for name, value in attributes.items():
 | 
				
			||||||
 | 
					            setattr(instance, name, value)
 | 
				
			||||||
 | 
					    except Exception as exception:
 | 
				
			||||||
 | 
					        future_result.set_exception(exception)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        future_result.set_result(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef inline void __inject_attributes(object instance, dict attributes):
 | 
					cdef inline void __inject_attributes(object instance, dict attributes):
 | 
				
			||||||
| 
						 | 
					@ -566,16 +573,14 @@ cdef inline object __call(
 | 
				
			||||||
cdef inline void __async_call_callback(object future_result, object call, object future):
 | 
					cdef inline void __async_call_callback(object future_result, object call, object future):
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        args, kwargs = future.result()
 | 
					        args, kwargs = future.result()
 | 
				
			||||||
 | 
					        result = call(*args, **kwargs)
 | 
				
			||||||
    except Exception as exception:
 | 
					    except Exception as exception:
 | 
				
			||||||
        future_result.set_exception(exception)
 | 
					        future_result.set_exception(exception)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        result = call(*args, **kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if __isawaitable(result):
 | 
					        if __isawaitable(result):
 | 
				
			||||||
            result = asyncio.ensure_future(result)
 | 
					            result = asyncio.ensure_future(result)
 | 
				
			||||||
            result.add_done_callback(functools.partial(__async_result_callback, future_result))
 | 
					            result.add_done_callback(functools.partial(__async_result_callback, future_result))
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					 | 
				
			||||||
        future_result.set_result(result)
 | 
					        future_result.set_result(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,7 +190,7 @@ class FactoryTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertIsNot(service1.client, service2.client)
 | 
					        self.assertIsNot(service1.client, service2.client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_kwargs_error_injection(self):
 | 
					    def test_injection_error(self):
 | 
				
			||||||
        async def init_resource():
 | 
					        async def init_resource():
 | 
				
			||||||
            raise Exception('Something went wrong')
 | 
					            raise Exception('Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -209,6 +209,47 @@ class FactoryTests(AsyncTestCase):
 | 
				
			||||||
            self._run(container.client())
 | 
					            self._run(container.client())
 | 
				
			||||||
        self.assertEqual(str(context.exception), 'Something went wrong')
 | 
					        self.assertEqual(str(context.exception), 'Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_injection_runtime_error_async_provides(self):
 | 
				
			||||||
 | 
					        async def create_client(*args,  **kwargs):
 | 
				
			||||||
 | 
					            raise Exception('Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Factory(
 | 
				
			||||||
 | 
					                create_client,
 | 
				
			||||||
 | 
					                resource1=resource,
 | 
				
			||||||
 | 
					                resource2=None,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(Exception) as context:
 | 
				
			||||||
 | 
					            self._run(container.client())
 | 
				
			||||||
 | 
					        self.assertEqual(str(context.exception), 'Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_injection_call_error_async_provides(self):
 | 
				
			||||||
 | 
					        async def create_client():  # <-- no args defined
 | 
				
			||||||
 | 
					            ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Factory(
 | 
				
			||||||
 | 
					                create_client,
 | 
				
			||||||
 | 
					                resource1=resource,
 | 
				
			||||||
 | 
					                resource2=None,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(TypeError) as context:
 | 
				
			||||||
 | 
					            self._run(container.client())
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            str(context.exception),
 | 
				
			||||||
 | 
					            "create_client() got an unexpected keyword argument 'resource1'",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_attributes_injection(self):
 | 
					    def test_attributes_injection(self):
 | 
				
			||||||
        class ContainerWithAttributes(containers.DeclarativeContainer):
 | 
					        class ContainerWithAttributes(containers.DeclarativeContainer):
 | 
				
			||||||
            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
					            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
| 
						 | 
					@ -255,6 +296,53 @@ class FactoryTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertIsNot(service1.client, service2.client)
 | 
					        self.assertIsNot(service1.client, service2.client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_attributes_injection_attribute_error(self):
 | 
				
			||||||
 | 
					        class ClientWithException(Client):
 | 
				
			||||||
 | 
					            @property
 | 
				
			||||||
 | 
					            def attribute_set_error(self):
 | 
				
			||||||
 | 
					                return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @attribute_set_error.setter
 | 
				
			||||||
 | 
					            def attribute_set_error(self, value):
 | 
				
			||||||
 | 
					                raise Exception('Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Factory(
 | 
				
			||||||
 | 
					                ClientWithException,
 | 
				
			||||||
 | 
					                resource1=resource,
 | 
				
			||||||
 | 
					                resource2=resource,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            client.add_attributes(attribute_set_error=123)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(Exception) as context:
 | 
				
			||||||
 | 
					            self._run(container.client())
 | 
				
			||||||
 | 
					        self.assertEqual(str(context.exception), 'Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_attributes_injection_runtime_error(self):
 | 
				
			||||||
 | 
					        async def init_resource():
 | 
				
			||||||
 | 
					            raise Exception('Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource = providers.Resource(init_resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Factory(
 | 
				
			||||||
 | 
					                Client,
 | 
				
			||||||
 | 
					                resource1=None,
 | 
				
			||||||
 | 
					                resource2=None,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            client.add_attributes(resource1=resource)
 | 
				
			||||||
 | 
					            client.add_attributes(resource2=resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(Exception) as context:
 | 
				
			||||||
 | 
					            self._run(container.client())
 | 
				
			||||||
 | 
					        self.assertEqual(str(context.exception), 'Something went wrong')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_async_instance_and_sync_attributes_injection(self):
 | 
					    def test_async_instance_and_sync_attributes_injection(self):
 | 
				
			||||||
        class ContainerWithAttributes(containers.DeclarativeContainer):
 | 
					        class ContainerWithAttributes(containers.DeclarativeContainer):
 | 
				
			||||||
            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
					            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user