Implement attribute injections and add tests

This commit is contained in:
Roman Mogylatov 2020-12-12 20:52:30 -05:00
parent 53a5d07b3a
commit f07f3e4943
4 changed files with 2448 additions and 428 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -438,17 +438,46 @@ cdef inline void __async_prepare_args_kwargs_callback(object future):
@cython.boundscheck(False)
@cython.wraparound(False)
cdef inline object __inject_attributes(
object instance,
tuple attributes,
int attributes_len,
):
cdef inline object __provide_attributes(tuple attributes, int attributes_len):
cdef NamedInjection attr_injection
cdef dict attribute_injections = {}
cdef list awaitables = []
for index in range(attributes_len):
attr_injection = <NamedInjection>attributes[index]
setattr(instance,
__get_name(attr_injection),
__get_value(attr_injection))
name = __get_name(attr_injection)
value = __get_value(attr_injection)
attribute_injections[name] = value
if __isawaitable(value):
awaitables.append((name, value))
if awaitables:
return __awaitable_args_kwargs_future(attribute_injections, awaitables)
return attribute_injections
cdef inline object __async_inject_attributes(future_instance, future_attributes):
future_result = asyncio.Future()
future = asyncio.Future()
future.set_result(future_result)
attributes_ready = asyncio.gather(future, future_instance, future_attributes)
attributes_ready.add_done_callback(__async_inject_attributes_callback)
asyncio.ensure_future(attributes_ready)
return future_result
cdef inline void __async_inject_attributes_callback(future):
future_result, instance, attributes = future.result()
__inject_attributes(instance, attributes)
future_result.set_result(instance)
cdef inline void __inject_attributes(object instance, dict attributes):
for name, value in attributes.items():
setattr(instance, name, value)
cdef inline object __call(
@ -485,7 +514,6 @@ cdef inline object __call(
future.set_result(kwargs)
kwargs = future
future_result = asyncio.Future()
future = asyncio.Future()
@ -524,9 +552,25 @@ cdef inline object __factory_call(Factory self, tuple args, dict kwargs):
instance = __callable_call(self.__instantiator, args, kwargs)
if self.__attributes_len > 0:
__inject_attributes(instance,
self.__attributes,
self.__attributes_len)
attributes = __provide_attributes(self.__attributes, self.__attributes_len)
instance_awaitable = __isawaitable(instance)
attributes_awaitable = __isawaitable(attributes)
if instance_awaitable or attributes_awaitable:
if not instance_awaitable:
future = asyncio.Future()
future.set_result(instance)
instance = future
if not attributes_awaitable:
future = asyncio.Future()
future.set_result(attributes)
attributes = future
return __async_inject_attributes(instance, attributes)
__inject_attributes(instance, attributes)
return instance

View File

@ -172,3 +172,49 @@ class FactoryTests(AsyncTestCase):
self.assertIs(service2.client.resource2, RESOURCE2)
self.assertIsNot(service1.client, service2.client)
def test_attributes_injection(self):
class ContainerWithAttributes(containers.DeclarativeContainer):
resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
client = providers.Factory(
Client,
resource1,
resource2=None,
)
client.add_attributes(resource2=resource2)
service = providers.Factory(
Service,
client=None,
)
service.add_attributes(client=client)
container = ContainerWithAttributes()
client1 = self._run(container.client())
client2 = self._run(container.client())
self.assertIsInstance(client1, Client)
self.assertIs(client1.resource1, RESOURCE1)
self.assertIs(client1.resource2, RESOURCE2)
self.assertIsInstance(client2, Client)
self.assertIs(client2.resource1, RESOURCE1)
self.assertIs(client2.resource2, RESOURCE2)
service1 = self._run(container.service())
service2 = self._run(container.service())
self.assertIsInstance(service1, Service)
self.assertIsInstance(service1.client, Client)
self.assertIs(service1.client.resource1, RESOURCE1)
self.assertIs(service1.client.resource2, RESOURCE2)
self.assertIsInstance(service2, Service)
self.assertIsInstance(service2.client, Client)
self.assertIs(service2.client.resource1, RESOURCE1)
self.assertIs(service2.client.resource2, RESOURCE2)
self.assertIsNot(service1.client, service2.client)