1
votes

I'm trying to use PyQt5's DBus module to interact with the KDE PowerManagerAgent. When calling the AddInhibition method I need to send the first paramter as an uint32 (Unsigned int), but the code sends the value as a singed int.

The code is written using Python 3

self.dBus = QtDBus.QDBusConnection.sessionBus()
msg = QtDBus.QDBusMessage.createMethodCall(self.dBusService, self.dBusPath,self.dBusInterface,'AddInhibition')
msg << 1 << who << reason
reply = QtDBus.QDBusReply(self.dBus.call(msg))

Looking at the output from dbus-monitor I can tell that the code does indeed contact the powermonitor but fails to find the correct AddInhibition method due to the first parameter being type as int32

Output from dbus-monitor when trying to call AddInhibition

Call

method call time=1549706946.073218 sender=:1.172 -> destination=org.kde.Solid.PowerManagement.PolicyAgent serial=5 path=/org/kde/Solid/PowerManagement/PolicyAgent; interface=org.kde.Solid.PowerManagement.PolicyAgent; member=AddInhibition int32 1 string "This" string "fails"

Reply

error time=1549706946.073536 sender=:1.29 -> destination=:1.172 error_name=org.freedesktop.DBus.Error.UnknownMethod reply_serial=5 string "No such method 'AddInhibition' in interface 'org.kde.Solid.PowerManagement.PolicyAgent' at object path '/org/kde/Solid/PowerManagement/PolicyAgent' (signature 'iss')"

Output from dbus-monitor when using QDBusViewer application

Call

method call time=1549723045.320128 sender=:1.82 -> destination=org.kde.Solid.PowerManagement.PolicyAgent serial=177 path=/org/kde/Solid/PowerManagement/PolicyAgent; interface=org.kde.Solid.PowerManagement.PolicyAgent; member=AddInhibition uint32 1 string "This" string "Works"

Reply

method return time=1549723045.320888 sender=:1.29 -> destination=:1.82 serial=1370 reply_serial=177 uint32 30

Since Python is not strongly typed how do I specify the the parameter must be typed as an unsigned int?

1

1 Answers

0
votes

You can use the DBusArgument class to do this by specifying the QMetaType of the argument.

For example, say you want to use the RequestName method from org.freedesktop.DBus (see the spec). The flags argument is an unsigned int, so you'll run into this problem:

>>> from PyQt5.QtDBus import QDBusConnection, QDBusInterface
>>> sessionbus = QDBusConnection.sessionBus()
>>> iface = QDBusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", sessionbus)
>>> c = iface.call('RequestName', 'com.mydomain.myapp', 4)
>>> c.arguments()
['Call to RequestName has wrong args (si, expected su)\n']

So, it's saying it got a string and an integer (si), but it wanted a string and an unsigned integer (su). So, we'll use the QDBusArgument class and specify QMetaType.UInt:

>>> from PyQt5.QtCore import QMetaType
>>> from PyQt5.QtDBus import QDBusConnection, QDBusInterface, QDBusArgument
>>> sessionbus = QDBusConnection.sessionBus()
>>> iface = QDBusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", sessionbus)
>>> a1 = QDBusArgument()
>>> a1.add('com.mydomain.myapp', QMetaType.QString)
>>> a2 = QDBusArgument(4, QMetaType.UInt)
>>> c = iface.call('RequestName', a1, a2)
>>> c.arguments()
[1]

Since the string was fine, that didn't have to be a QDBusArgument. I just wanted to show the two ways of constructing it (with the .add() method and just using the constructor).