Implement positional injections, add tests and make refactoring

This commit is contained in:
Roman Mogylatov 2020-12-12 12:26:14 -05:00
parent af51779477
commit 53a5d07b3a
4 changed files with 2498 additions and 1671 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -339,25 +339,33 @@ cdef inline tuple __separate_prefixed_kwargs(dict kwargs):
@cython.boundscheck(False)
@cython.wraparound(False)
cdef inline tuple __provide_positional_args(
cdef inline object __provide_positional_args(
tuple args,
tuple inj_args,
int inj_args_len,
):
cdef int index
cdef list positional_args
cdef list positional_args = []
cdef list awaitables = []
cdef PositionalInjection injection
if inj_args_len == 0:
return args
positional_args = list()
for index in range(inj_args_len):
injection = <PositionalInjection>inj_args[index]
positional_args.append(__get_value(injection))
value = __get_value(injection)
positional_args.append(value)
if __isawaitable(value):
awaitables.append((index, value))
positional_args.extend(args)
return tuple(positional_args)
if awaitables:
return __awaitable_args_kwargs_future(positional_args, awaitables)
return positional_args
@cython.boundscheck(False)
@ -403,24 +411,29 @@ cdef inline object __provide_keyword_args(
awaitables.append((name, value))
if awaitables:
future_result = asyncio.Future()
args_future = asyncio.Future()
args_future.set_result((future_result, kwargs, awaitables))
kwargs_ready = asyncio.gather(args_future, *[value for _, value in awaitables])
kwargs_ready.add_done_callback(__async_prepare_kwargs_callback)
asyncio.ensure_future(kwargs_ready)
return future_result
return __awaitable_args_kwargs_future(kwargs, awaitables)
return kwargs
cdef inline void __async_prepare_kwargs_callback(object future):
(future_result, kwargs, awaitables), *awaited = future.result()
for value, (name, _) in zip(awaited, awaitables):
kwargs[name] = value
future_result.set_result(kwargs)
cdef inline object __awaitable_args_kwargs_future(object args, list awaitables):
future_result = asyncio.Future()
args_future = asyncio.Future()
args_future.set_result((future_result, args, awaitables))
args_ready = asyncio.gather(args_future, *[value for _, value in awaitables])
args_ready.add_done_callback(__async_prepare_args_kwargs_callback)
asyncio.ensure_future(args_ready)
return future_result
cdef inline void __async_prepare_args_kwargs_callback(object future):
(future_result, args, awaitables), *awaited = future.result()
for value, (key, _) in zip(awaited, awaitables):
args[key] = value
future_result.set_result(args)
@cython.boundscheck(False)
@ -458,12 +471,27 @@ cdef inline object __call(
injection_kwargs_len,
)
if __isawaitable(kwargs):
args_awaitable = __isawaitable(args)
kwargs_awaitable = __isawaitable(kwargs)
if args_awaitable or kwargs_awaitable:
if not args_awaitable:
future = asyncio.Future()
future.set_result(args)
args = future
if not kwargs_awaitable:
future = asyncio.Future()
future.set_result(kwargs)
kwargs = future
future_result = asyncio.Future()
args_future = asyncio.Future()
args_future.set_result((future_result, call, args))
args_kwargs_ready = asyncio.gather(args_future, kwargs)
future = asyncio.Future()
future.set_result((future_result, call))
args_kwargs_ready = asyncio.gather(future, args, kwargs)
args_kwargs_ready.add_done_callback(__async_call_callback)
asyncio.ensure_future(args_kwargs_ready)
@ -473,7 +501,7 @@ cdef inline object __call(
cdef inline void __async_call_callback(object future):
(future_result, call, args), kwargs = future.result()
(future_result, call), args, kwargs = future.result()
result = call(*args, **kwargs)
future_result.set_result(result)

View File

@ -56,8 +56,96 @@ class Container(containers.DeclarativeContainer):
class FactoryTests(AsyncTestCase):
def test_direct_injection(self):
container = Container()
def test_args_injection(self):
class ContainerWithArgs(containers.DeclarativeContainer):
resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
client = providers.Factory(
Client,
resource1,
resource2,
)
service = providers.Factory(
Service,
client,
)
container = ContainerWithArgs()
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)
def test_kwargs_injection(self):
container = Container()
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)
def test_args_kwargs_injection(self):
class ContainerWithArgsAndKwArgs(containers.DeclarativeContainer):
resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
client = providers.Factory(
Client,
resource1,
resource2=resource2,
)
service = providers.Factory(
Service,
client=client,
)
container = ContainerWithArgsAndKwArgs()
client1 = self._run(container.client())
client2 = self._run(container.client())
@ -70,9 +158,6 @@ class FactoryTests(AsyncTestCase):
self.assertIs(client2.resource1, RESOURCE1)
self.assertIs(client2.resource2, RESOURCE2)
def test_children_injection(self):
container = Container()
service1 = self._run(container.service())
service2 = self._run(container.service())