[PyQt] How to expose function accepting array of struct to D-Bus?
Phil Thompson
phil at riverbankcomputing.com
Fri Aug 10 10:04:07 BST 2012
On Tue, 7 Aug 2012 15:45:43 -0400, Evade Flow <evadeflow at gmail.com> wrote:
>> In theory you should be able to use QDBusArgument but I've not tested
>> it - I've always struggled to find test cases.
>
> Maybe the little server app appended below will help. Using dbus-send, I
> can exercise the 'name' property and 'echo' method, as well as the
> introspection interface:
>
> # Call 'echo' method
> dbus-send --print-reply --dest=com.example.dbus /com/example/dbus \
> com.example.dbus.echo string:Hello
>
> # Exercise introspection interface
> dbus-send --print-reply --dest=com.example.dbus /com/example/dbus \
> org.freedesktop.DBus.Introspectable.Introspect
>
> # Get the 'name' property
> dbus-send --print-reply --dest=com.example.dbus /com/example/dbus \
> org.freedesktop.DBus.Properties.Get string:com.example.dbus
> string:name
>
> # Set 'name'
> dbus-send --print-reply --dest=com.example.dbus /com/example/dbus \
> org.freedesktop.DBus.Properties.Set string:com.example.dbus \
> string:name variant:string:MyNewName
>
> # Call 'setPosition' method
> dbus-send --print-reply --dest=com.example.dbus /com/example/dbus \
> com.example.dbus.setPosition double:1.0 double:2.0 double:3.0
>
> Unfortunately for me, attempts to call setPosition() result in:
>
> Error org.freedesktop.DBus.Error.UnknownMethod: No such method
> 'setPosition' in interface 'com.example.dbus' at object path
> '/com/example/dbus' (signature 'ddd')
>
> I suppose this makes sense, but I was hoping there might be a
> workaround. It would be really great to be able to write a PyQt-based
> implementation of *any* D-Bus specification. That way, I could mock out
> any arbitrary server's functionality for testing.
>
> For now, it looks like structs aren't supported? I'd be willing to help
> add that support if it seems doable, but I'm not sure where to start, or
> what the effort level might be. (I can probably spend about 20 hours on
> it without getting into too much trouble...)
>
> ----------
>
> from PyQt4 import QtDBus
> from PyQt4.QtCore import (QCoreApplication, QObject, Q_CLASSINFO,
pyqtSlot,
> pyqtProperty)
> from PyQt4.QtDBus import QDBusArgument, QDBusConnection,
> QDBusAbstractAdaptor
>
> class MyServer(QObject):
>
> def __init__(self):
> QObject.__init__(self)
> self.__dbusAdaptor = ServerAdaptor(self)
> self.__name = 'myname'
>
> def echo(self, value):
> return'Received: {0}'.format(value)
>
> @property
> def name(self):
> return self.__name
>
> @name.setter
> def name(self, value):
> self.__name = value
>
>
> class ServerAdaptor(QDBusAbstractAdaptor):
> Q_CLASSINFO("D-Bus Interface", "com.example.dbus")
> Q_CLASSINFO("D-Bus Introspection",
> ' <interface name="com.example.dbus">\n'
> ' <property name="name" type="s" access="readwrite"/>\n'
> ' <method name="echo">\n'
> ' <arg direction="in" type="s" name="phrase"/>\n'
> ' <arg direction="out" type="s" name="echoed"/>\n'
> ' </method>\n'
> ' <method name="setPosition">\n'
> ' <arg direction="in" type="(ddd)" name="pos"/>\n'
> ' </method>\n'
> ' </interface>\n')
>
> def __init__(self, parent):
> super().__init__(parent)
>
> @pyqtSlot(str, result=str)
> def echo(self, phrase):
> return self.parent().echo(phrase)
>
> @pyqtSlot(QDBusArgument)
> def setPosition(self, pos):
> print("How can I call this function?")
>
>
> @pyqtProperty(str)
> def name(self):
> return self.parent().name
>
> @name.setter
> def name(self, value):
> self.parent().name = value
>
> def start():
> app = QCoreApplication([])
> bus = QDBusConnection.sessionBus()
> server = MyServer()
> bus.registerObject('/com/example/dbus', server)
> bus.registerService('com.example.dbus')
> app.exec()
>
> if __name__ == '__main__':
> start()
It seems the trick is to specify QDBusMessage as the slot argument and use
its arguments() method to get at the actual arguments.
For example, if you have a method setColors() that takes a single argument
that is an array of structs of three ints (i.e. an array of RGB values).
This would have a DBus signature of "a(iii)". The Python implementation
would be...
@pyqtSlot(QDBusMessage)
def setColors(self, msg):
for red, green, blue in msg.arguments()[0]:
print(red, green, blue)
Does this technique solve all your issues?
I'll update the docs.
Phil
More information about the PyQt
mailing list