Skip to content

Commit

Permalink
Allow async capability implementation methods to return a tuple
Browse files Browse the repository at this point in the history
  • Loading branch information
LasseBlaauwbroek authored and haata committed Jun 7, 2023
1 parent c037342 commit d53aa24
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 16 deletions.
32 changes: 20 additions & 12 deletions capnp/lib/capnp.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,21 @@ cdef api void promise_task_add_done_callback(object task, object callback, VoidP
cdef api void promise_task_cancel(object task):
task.cancel()

def fill_context(method_name, context, returned_data):
if returned_data is None:
return
if not isinstance(returned_data, tuple):
returned_data = (returned_data,)
names = _find_field_order(context.results.schema.node.struct)
if len(returned_data) > len(names):
raise KjException(
"Too many values returned from `{}`. Expected {} and got {}"
.format(method_name, len(names), len(returned_data)))

results = context.results
for arg_name, arg_val in zip(names, returned_data):
setattr(results, arg_name, arg_val)

cdef api VoidPromise * call_server_method(object server,
char * _method_name, CallContext & _context) except * with gil:
method_name = <object>_method_name
Expand Down Expand Up @@ -141,22 +156,15 @@ cdef api VoidPromise * call_server_method(object server,
elif type(ret) is _Promise:
return new VoidPromise(helpers.convert_to_voidpromise(move((<_Promise>ret).thisptr)))
elif asyncio.iscoroutine(ret):
task = asyncio.create_task(ret)
async def finalize():
fill_context(method_name, context, await ret)
task = asyncio.create_task(finalize())
callback = _partial(void_task_done_callback, method_name)
return new VoidPromise(helpers.taskToPromise(
capnp.heap[PyRefCounter](<PyObject*>task),
<PyObject*>callback))
if not isinstance(ret, tuple):
ret = (ret,)
names = _find_field_order(context.results.schema.node.struct)
if len(ret) > len(names):
raise KjException(
"Too many values returned from `{}`. Expected {} and got {}"
.format(method_name, len(names), len(ret)))

results = context.results
for arg_name, arg_val in zip(names, ret):
setattr(results, arg_name, arg_val)
else:
fill_context(method_name, context, ret)

return NULL

Expand Down
6 changes: 2 additions & 4 deletions examples/async_calculator_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ async def call(self, params, _context, **kwargs):
another promise"""

assert len(params) == self.paramCount
value = await evaluate_impl(self.body, params)
_context.results.value = value
return await evaluate_impl(self.body, params)


class OperatorImpl(calculator_capnp.Calculator.Function.Server):
Expand Down Expand Up @@ -101,8 +100,7 @@ class CalculatorImpl(calculator_capnp.Calculator.Server):
"Implementation of the Calculator Cap'n Proto interface."

async def evaluate(self, expression, _context, **kwargs):
value = await evaluate_impl(expression)
_context.results.value = ValueImpl(value)
return ValueImpl(await evaluate_impl(expression))

def defFunction(self, paramCount, body, _context, **kwargs):
return FunctionImpl(paramCount, body)
Expand Down

0 comments on commit d53aa24

Please sign in to comment.