[PyQt] How to expose function accepting array of struct to D-Bus?

Evade Flow evadeflow at gmail.com
Mon Aug 6 18:59:08 BST 2012


On Mon, Aug 6, 2012 at 1:03 PM, Phil Thompson
<phil at riverbankcomputing.com> wrote:
> On Mon, 6 Aug 2012 12:49:21 -0400, Evade Flow <evadeflow at gmail.com> wrote:
>> On Mon, Aug 6, 2012 at 12:29 PM, Phil Thompson
>> <phil at riverbankcomputing.com> wrote:
>>> On Mon, 6 Aug 2012 12:15:44 -0400, Evade Flow <evadeflow at gmail.com>
>>> wrote:
>>>> I'm trying to write a PyQt4-based mock object for a C++ app exposed
> over
>>>> D-Bus with the following interface:
>>>>
>>>>     Q_CLASSINFO("D-Bus Interface", "com.acme.Audio.Control")
>>>>     Q_CLASSINFO("D-Bus Introspection",
>>>>     '  <interface name="com.acme.Audio.Control">\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="setParams">\n'
>>>>     '      <arg direction="out" type="(i)" name="error"/>\n'
>>>>     '      <arg direction="in" type="a(iiiii)"
>>>>     name="audioSourceParameter"/>\n'
>>>>     '      <annotation value="QVector<AudioSourceParameters>"
>>>> name="com.trolltech.QtDBus.QtTypeName.In0"/>\n'
>>>>     '      <annotation value="Errors::ErrorCode"
>>>> name="com.trolltech.QtDBus.QtTypeName.Out0"/>\n'
>>>>     '    </method>\n'
>>>>     '  </interface>\n')
>>>>
>>>> It's unclear to me how how the setParams() function should be
> decorated.
>>>> For the echo() function, I have:
>>>>
>>>>     @pyqtSlot(str, result=str)
>>>>     def echo(self, phrase):
>>>>         return self.parent().echo(phrase)
>>>>
>>>> But what should I put for setParams()? I was tempted to write:
>>>>
>>>>     @pyqtSlot('a(iiiii)', result='(i)')
>>>>     def setParams(self, volume):
>>>>         return self.parent().echo(phrase)
>>>>
>>>> But this results in:
>>>>
>>>> TypeError: C++ type 'a(iiiii)' is not supported as a pyqtSlot type
>>>> argument type
>>>>
>>>> So... how does one expose a function to D-Bus that accepts an array of
>>>> structs, each containing 5 ints?
>>>
>>> What would be the C++ signature? Try that as a string.
>>>
>>> Phil
>>
>> The C++ signature is:
>>
>>   void setParams(QList<AudioSourceParameters> audioSourceParameters,
>>                  Errors::ErrorCode &error);
>>
>> where AudioSourceParameters is defined as:
>>
>>   struct AudioSourceParameters
>>   {
>>       int volume;
>>       int balance;
>>       int fader;
>>       int fadein;
>>       int fadeout;
>>   };
>>
>> The C++ code sets things up with:
>>
>>   Q_DECLARE_METATYPE(QList<AudioSourceParameters>);
>>
>> and:
>>
>>    qDBusRegisterMetaType<AudioSourceParameters>();
>>    qDBusRegisterMetaType<QList<AudioSourceParameters> >();
>>
>> The introspection XML (presumably output by qdbuscpp2xml) shows this as
>> 'a(iiiii)'. That's what the client app (the one I'm trying to provide a
>> mock server for) is expecting to see.
>>
>> Any ideas how to make this work with PyQt?
>
> You probably can't using the QtDBus module because PyQt doesn't know
> anything about AudioSourceParameters.
>
> You should be able to use the standard Python dbus module which will
> bypass the Qt conversions.
>
> Phil

What clients expect is 'a(iiiii)', so the convenience type declared in
the C++ server I'm trying to mock out shouldn't matter for my purposes
(should it?)

It makes sense that PyQt wouldn't know anything about
'AudioSourceParameters', but can it handle 'a(iiiii)'? Or are D-Bus
arrays and structs (and arrays-of-structs) not supported?

I've seen a few PyQt code examples that use QDBusArgument to marshal
arbitrary arguments, but I haven't seen any examples where complex
objects are demarshalled.

This seems fine:

  @pyqtSlot('QList<int>')
  def func(self, args):
      pass

but this:

    @pyqtSlot('QList<QList<int> >')
      def func(self, args):
        pass

results in:

  File "fake_hifi_audio.py", line 44, in HifiAudioServerAdaptor
    @pyqtSlot('QList<QList<int> >')
TypeError: C++ type 'QList<QList<int> >' is not supported as a
pyqtSlot type argument type

If arrays of structs aren't supported, is there some way I can get the
thing that clients send as 'a(iiiii)' into a QDBusArgument variable and
demarshal it manually? PyQt's DBus bindings are *so* much better than
the standard python dbus module that I shudder at the thought of having
to go back to it... `:-}


More information about the PyQt mailing list