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

Phil Thompson phil at riverbankcomputing.com
Mon Aug 6 22:23:45 BST 2012


On Mon, 6 Aug 2012 13:59:08 -0400, Evade Flow <evadeflow at gmail.com> wrote:
> 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

Because QList<int> is explicitly supported by PyQt.

> 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

Because QList<QList<int> > isn't supported.

> 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... `:-}

In theory you should be able to use QDBusArgument but I've not tested it -
I've always struggled to find test cases.

Phil


More information about the PyQt mailing list