Cannot return a single value
AdmiralNemo opened this issue · comments
It does not seem to be possible for a method to return a single value. Any method that attempts to do so will raise a ValueError
. The specific exception depends on the type.
Here is a short example that implements a method for each type. Each method that returns a single value fails, while the methods that return multiple values work correctly.
% python -m pip show dbussy
Name: DBussy
Version: 1.3
Summary: language bindings for libdbus, for Python 3.5 or later
Home-page: https://github.com/ldo/dbussy
Author: Lawrence D'Oliveiro
Author-email: ldo@geek-central.gen.nz
License: LGPL v2.1+
Location: /home/dhatch/.local/lib/python3.8/site-packages
Requires:
Required-by:
Example
import asyncio
import ravel
@ravel.interface(ravel.INTERFACE.SERVER, name='com.example.test1')
class Server:
async def setup(self, loop):
self.bus = await ravel.session_bus_async(loop)
self.bus.register('/com/example/test1', False, Server())
self.bus.request_name(
'com.example.test1', ravel.DBUS.NAME_FLAG_DO_NOT_QUEUE
)
@ravel.method(in_signature='', out_signature='s')
async def get_string(self):
return 'hello'
@ravel.method(in_signature='', out_signature='ss')
async def get_two_strings(self):
return 'hello', 'world'
@ravel.method(in_signature='', out_signature='i')
async def get_int(self):
return 1
@ravel.method(in_signature='', out_signature='ii')
async def get_two_ints(self):
return 1, 1
@ravel.method(in_signature='', out_signature='as')
async def get_array(self):
return ['hello', 'world']
@ravel.method(in_signature='', out_signature='asas')
async def get_two_arrays(self):
return ['hello', 'world'], ['goodnight', 'moon']
@ravel.method(in_signature='', out_signature='a{ss}')
async def get_dict(self):
return {'hello': 'world'}
@ravel.method(in_signature='', out_signature='a{ss}a{ss}')
async def get_two_dicts(self):
return {'hello': 'world'}, {'goodnight': 'moon'}
@ravel.method(in_signature='', out_signature='(ss)')
async def get_struct(self):
return 'hello', 'world'
@ravel.method(in_signature='', out_signature='(ss)(ss)')
async def get_two_structs(self):
return ('hello', 'world'), ('goodnight', 'moon')
def main():
loop = asyncio.get_event_loop()
server = Server()
loop.run_until_complete(server.setup(loop))
try:
loop.run_forever()
finally:
loop.close()
if __name__ == '__main__':
main()
Single String
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_string
Error org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
Task exception was never retrieved
future: <Task finished name='Task-2' coro=<_message_interface_dispatch.<locals>.await_result() done, defined at /home/dhatch/.local/lib/python3.8/site-packages/ravel.py:2006> exception=ValueError("invalid handler result 'hello'")>
Traceback (most recent call last):
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 2016, in await_result
return_result_common(call_info, result)
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 1890, in return_result_common
raise ValueError("invalid handler result %s" % repr(result))
ValueError: invalid handler result 'hello'
Two Strings
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_two_strings
method return time=1590672580.522903 sender=:1.151623 -> destination=:1.151636 serial=5 reply_serial=2
string "hello"
string "world"
Single Int
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_int
Error org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
Task exception was never retrieved
future: <Task finished name='Task-4' coro=<_message_interface_dispatch.<locals>.await_result() done, defined at /home/dhatch/.local/lib/python3.8/site-packages/ravel.py:2006> exception=ValueError('invalid handler result 1')>
Traceback (most recent call last):
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 2016, in await_result
return_result_common(call_info, result)
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 1890, in return_result_common
raise ValueError("invalid handler result %s" % repr(result))
ValueError: invalid handler result 1
Two Ints
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_two_ints
method return time=1590672642.983118 sender=:1.151623 -> destination=:1.151646 serial=6 reply_serial=2
int32 1
int32 1
Single Array
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_array
Error org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
Task exception was never retrieved
future: <Task finished name='Task-2' coro=<_message_interface_dispatch.<locals>.await_result() done, defined at /home/dhatch/.local/lib/python3.8/site-packages/ravel.py:2006> exception=ValueError("mismatch between signature entries [ArrayType[BasicType(<TYPE.STRING: 115>)]] and number of sequence elements ('hello', 'world')")>
Traceback (most recent call last):
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 2016, in await_result
return_result_common(call_info, result)
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 1892, in return_result_common
_send_method_return \
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 1770, in _send_method_return
reply.append_objects(sig, *args)
File "/home/dhatch/.local/lib/python3.8/site-packages/dbussy.py", line 4451, in append_objects
append_sub(parse_signature(signature), args, self.iter_init_append())
File "/home/dhatch/.local/lib/python3.8/site-packages/dbussy.py", line 4390, in append_sub
raise ValueError \
ValueError: mismatch between signature entries [ArrayType[BasicType(<TYPE.STRING: 115>)]] and number of sequence elements ('hello', 'world')
Two Arrays
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_two_arrays
method return time=1590671953.124213 sender=:1.151413 -> destination=:1.151444 serial=5 reply_serial=2
array [
string "hello"
string "world"
]
array [
string "goodnight"
string "moon"
]
Single Dict
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_dict
Error org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
Task exception was never retrieved
future: <Task finished name='Task-4' coro=<_message_interface_dispatch.<locals>.await_result() done, defined at /home/dhatch/.local/lib/python3.8/site-packages/ravel.py:2006> exception=ValueError("invalid handler result {'hello': 'world'}")>
Traceback (most recent call last):
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 2016, in await_result
return_result_common(call_info, result)
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 1890, in return_result_common
raise ValueError("invalid handler result %s" % repr(result))
ValueError: invalid handler result {'hello': 'world'}
Two Dicts
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_two_dicts
method return time=1590672078.127905 sender=:1.151413 -> destination=:1.151463 serial=6 reply_serial=2
array [
dict entry(
string "hello"
string "world"
)
]
array [
dict entry(
string "goodnight"
string "moon"
)
]
Single Struct
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_struct
Error org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
Task exception was never retrieved
future: <Task finished name='Task-6' coro=<_message_interface_dispatch.<locals>.await_result() done, defined at /home/dhatch/.local/lib/python3.8/site-packages/ravel.py:2006> exception=ValueError("mismatch between signature entries [StructType((BasicType(<TYPE.STRING: 115>), BasicType(<TYPE.STRING: 115>)))] and number of sequence elements ('hello', 'world')")>
Traceback (most recent call last):
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 2016, in await_result
return_result_common(call_info, result)
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 1892, in return_result_common
_send_method_return \
File "/home/dhatch/.local/lib/python3.8/site-packages/ravel.py", line 1770, in _send_method_return
reply.append_objects(sig, *args)
File "/home/dhatch/.local/lib/python3.8/site-packages/dbussy.py", line 4451, in append_objects
append_sub(parse_signature(signature), args, self.iter_init_append())
File "/home/dhatch/.local/lib/python3.8/site-packages/dbussy.py", line 4390, in append_sub
raise ValueError \
ValueError: mismatch between signature entries [StructType((BasicType(<TYPE.STRING: 115>), BasicType(<TYPE.STRING: 115>)))] and number of sequence elements ('hello', 'world')
Two Structs
% dbus-send --session --print-reply --dest=com.example.test1 /com/example/test1 com.example.test1.get_two_structs
method return time=1590672175.076293 sender=:1.151413 -> destination=:1.151477 serial=7 reply_serial=2
struct {
string "hello"
string "world"
}
struct {
string "goodnight"
string "moon"
}
Faced the same issue too. Returning a tuple with single element worked for me.
like this
async def get_int(self):
return (1,)
But I agree it still look inconvenient.
BTW the same issue with single value returned as tuple on receiver side.
didn't fined a way to work it out without patching ravel like in attached patch
ravel.txt
Yes, it has to be a 1-element tuple. I decided early on that trying to guess when or when not to convert to/from a tuple was just too much trouble.
Considering trying to a return a single value which is a 1-element array, for example.
Are you willing to reconsider this design decision? It is extremely inconvenient on both the server side and the client side as @carrotstealer mentioned. It also means that the value of out_signature
in the @method
decorator does not match the type annotation, e.g.:
@ravel.method(in_signature='', out_signature='s')
def get_string(self) -> Tuple[str]:
return 'hello',
This is confusing and inconvenient.
If nothing else, maybe this could be more clearly indicated in the documentation?
Considering trying to a return a single value which is a 1-element array, for example.
wouldn't the DBus type specification take care of that?
I think the out_signature
of a 1-element array (of int) would be ai
while the out_signature
of a int is i
.
So this signature can be used if we need to determine whether a tuple or list needs to be unpacked. Or am I missing something?