mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-16 19:40:59 +03:00
Merge branch 'release/4.23.2' into master
This commit is contained in:
commit
6e59b4ab6f
|
@ -7,6 +7,11 @@ 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.23.2
|
||||||
|
------
|
||||||
|
- Improve async mode exceptions handling.
|
||||||
|
- Fix double printing of exception when async resource initialization causes an error.
|
||||||
|
|
||||||
4.23.1
|
4.23.1
|
||||||
------
|
------
|
||||||
- Hotfix a bug with importing FastAPI ``Request``.
|
- Hotfix a bug with importing FastAPI ``Request``.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Top-level package."""
|
"""Top-level package."""
|
||||||
|
|
||||||
__version__ = '4.23.1'
|
__version__ = '4.23.2'
|
||||||
"""Version number.
|
"""Version number.
|
||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -455,9 +455,14 @@ cdef inline void __async_prepare_args_kwargs_callback(
|
||||||
object awaitables,
|
object awaitables,
|
||||||
object future,
|
object future,
|
||||||
):
|
):
|
||||||
|
try:
|
||||||
awaited = future.result()
|
awaited = future.result()
|
||||||
|
|
||||||
for value, (key, _) in zip(awaited, awaitables):
|
for value, (key, _) in zip(awaited, awaitables):
|
||||||
args[key] = value
|
args[key] = value
|
||||||
|
except Exception as exception:
|
||||||
|
future_result.set_exception(exception)
|
||||||
|
else:
|
||||||
future_result.set_result(args)
|
future_result.set_result(args)
|
||||||
|
|
||||||
|
|
||||||
|
@ -498,8 +503,14 @@ 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):
|
||||||
|
try:
|
||||||
instance, attributes = future.result()
|
instance, attributes = future.result()
|
||||||
__inject_attributes(instance, attributes)
|
|
||||||
|
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)
|
future_result.set_result(instance)
|
||||||
|
|
||||||
|
|
||||||
|
@ -560,19 +571,26 @@ 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:
|
||||||
args, kwargs = future.result()
|
args, kwargs = future.result()
|
||||||
result = call(*args, **kwargs)
|
result = call(*args, **kwargs)
|
||||||
|
except Exception as exception:
|
||||||
|
future_result.set_exception(exception)
|
||||||
|
else:
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
cdef inline object __async_result_callback(object future_result, object future):
|
cdef inline object __async_result_callback(object future_result, object future):
|
||||||
future_result.set_result(future.result())
|
try:
|
||||||
|
result = future.result()
|
||||||
|
except Exception as exception:
|
||||||
|
future_result.set_exception(exception)
|
||||||
|
else:
|
||||||
|
future_result.set_result(result)
|
||||||
|
|
||||||
|
|
||||||
cdef inline object __callable_call(Callable self, tuple args, dict kwargs):
|
cdef inline object __callable_call(Callable self, tuple args, dict kwargs):
|
||||||
|
|
|
@ -3486,7 +3486,6 @@ cdef class Resource(Provider):
|
||||||
resource = initializer.result()
|
resource = initializer.result()
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__initialized = False
|
self.__initialized = False
|
||||||
raise
|
|
||||||
else:
|
else:
|
||||||
self.__resource = resource
|
self.__resource = resource
|
||||||
self.__shutdowner = shutdowner
|
self.__shutdowner = shutdowner
|
||||||
|
|
|
@ -190,6 +190,64 @@ class FactoryTests(AsyncTestCase):
|
||||||
|
|
||||||
self.assertIsNot(service1.client, service2.client)
|
self.assertIsNot(service1.client, service2.client)
|
||||||
|
|
||||||
|
def test_injection_error(self):
|
||||||
|
async def init_resource():
|
||||||
|
raise Exception('Something went wrong')
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
resource_with_error = providers.Resource(init_resource)
|
||||||
|
|
||||||
|
client = providers.Factory(
|
||||||
|
Client,
|
||||||
|
resource1=resource_with_error,
|
||||||
|
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_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.assertIn("create_client() got", str(context.exception))
|
||||||
|
self.assertIn("unexpected keyword argument", str(context.exception))
|
||||||
|
|
||||||
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))
|
||||||
|
@ -236,6 +294,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))
|
||||||
|
|
|
@ -449,14 +449,45 @@ class AsyncResourceTest(AsyncTestCase):
|
||||||
self.assertTrue(provider.initialized)
|
self.assertTrue(provider.initialized)
|
||||||
self.assertTrue(provider.is_async_mode_enabled())
|
self.assertTrue(provider.is_async_mode_enabled())
|
||||||
|
|
||||||
# Disable default exception handling to prevent output
|
with self.assertRaises(RuntimeError):
|
||||||
asyncio.get_event_loop().set_exception_handler(lambda loop, context: ...)
|
self._run(future)
|
||||||
|
|
||||||
|
self.assertFalse(provider.initialized)
|
||||||
|
self.assertTrue(provider.is_async_mode_enabled())
|
||||||
|
|
||||||
|
def test_init_async_gen_with_error(self):
|
||||||
|
async def _init():
|
||||||
|
raise RuntimeError()
|
||||||
|
yield
|
||||||
|
|
||||||
|
provider = providers.Resource(_init)
|
||||||
|
|
||||||
|
future = provider()
|
||||||
|
self.assertTrue(provider.initialized)
|
||||||
|
self.assertTrue(provider.is_async_mode_enabled())
|
||||||
|
|
||||||
with self.assertRaises(RuntimeError):
|
with self.assertRaises(RuntimeError):
|
||||||
self._run(future)
|
self._run(future)
|
||||||
|
|
||||||
# Restore default exception handling
|
self.assertFalse(provider.initialized)
|
||||||
asyncio.get_event_loop().set_exception_handler(None)
|
self.assertTrue(provider.is_async_mode_enabled())
|
||||||
|
|
||||||
|
def test_init_async_subclass_with_error(self):
|
||||||
|
class _Resource(resources.AsyncResource):
|
||||||
|
async def init(self):
|
||||||
|
raise RuntimeError()
|
||||||
|
|
||||||
|
async def shutdown(self, resource):
|
||||||
|
pass
|
||||||
|
|
||||||
|
provider = providers.Resource(_Resource)
|
||||||
|
|
||||||
|
future = provider()
|
||||||
|
self.assertTrue(provider.initialized)
|
||||||
|
self.assertTrue(provider.is_async_mode_enabled())
|
||||||
|
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
self._run(future)
|
||||||
|
|
||||||
self.assertFalse(provider.initialized)
|
self.assertFalse(provider.initialized)
|
||||||
self.assertTrue(provider.is_async_mode_enabled())
|
self.assertTrue(provider.is_async_mode_enabled())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user