ldo / dbussy

Python binding for D-Bus using asyncio

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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?