[PyQt] How to expose function accepting array of struct to D-Bus?
Evade Flow
evadeflow at gmail.com
Fri Aug 10 16:59:48 BST 2012
> It seems the trick is to specify QDBusMessage as the slot argument...
>
> @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?
Indeed, it does! Thanks so much, Phil!!
On Fri, Aug 10, 2012 at 5:04 AM, Phil Thompson
<phil at riverbankcomputing.com> wrote:
> 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