When using PyQt and PyDbus, how I do pass a map containing QDBusVariants to the D-Bus?

122 Views Asked by At

I am having trouble calling a method to the D-Bus. Check this code:

class DBusAdaptor(QDBusAbstractAdaptor):
    pyqtClassInfo('D-Bus Interface', 'org.pyqt.LinuxCleaner')
    pyqtClassInfo('D-Bus Path', '/LinuxCleaner')

    def __init__(self, parent):
        super().__init__(parent)
        connect = QDBusConnection.connectToBus(QDBusConnection.BusType.SessionBus, 'LinuxCleaner')
        conn_iface = connect.interface()
        if not connect.registerService('org.pyqt.LinuxCleaner'):
            print('Failed to register service')
        if not connect.registerObject('/LinuxCleaner', self):
            print('Failed to register Object!')
        print(connect.baseService())
        self._check_polkit_privilege(conn_iface, 'org.pyqt.LinuxCleaner')

    def _check_polkit_privilege(self, conn_iface, service):
        """
        :param conn_iface: D-Bus connection interface.
        :type conn_iface: QDBusConnectionInterface
        :param service: D-Bus service name.
        :type service: str
        :return:
        """
        pid = conn_iface.servicePid(service).value()
        interface = QDBusInterface('org.freedesktop.PolicyKit1',
                                   '/org/freedesktop/PolicyKit1/Authority',
                                   'org.freedesktop.PolicyKit1.Authority',
                                   QDBusConnection.systemBus())
        struct = QDBusArgument()
        struct.beginStructure()
        struct.add('unix-process', 10)
        struct.beginMap(10, 3)
        struct.beginMapEntry()
        struct.add('pid', 10)
        struct.add(pid, 3)
        struct.endMapEntry()
        struct.beginMapEntry()
        struct.add('start-time', 10)
        struct.add(0, 3)
        struct.endMapEntry()
        struct.endMap()
        struct.endStructure()
        struct.add('org.pyqt.LinuxCleaner.auth', 10)
        struct.beginMap(10, 10)
        struct.beginMapEntry()
        struct.add('AllowUserInteraction', 10)
        struct.add('true', 10)
        struct.endMapEntry()
        struct.endMap()
        struct.add(1, 3)
        struct.add('', 10)
        reply = interface.call('CheckAuthorization', struct)
        print(reply.errorMessage())

I get the following error message: Type of message, “((sa{su}))”, does not match expected type “((sa{sv})sa{ss}us)” I take that to mean that {sv} requires a QDBusVariant (according to Qt docs), yet beginMap() only accepts QMetaType's as arguments. QDBusVariant is not an exposed Meta Type. How would I solve this? How can I pass a QDBusVariant to beginMap()? I can't, can I?

1

There are 1 best solutions below

3
Christi On

The following code for PyQt5 creates a QDBusArgument of type "a{sv}" (a dict/map of string keys with DBusVariant values).

map = QDBusArgument()
map.beginMap(QMetaType.QString, QMetaType.type("QDBusVariant"))
map.beginMapEntry()
map.add("key")
map.add(QDBusVariant("value"))
map.endMapEntry()
map.endMap()

This requires the use of the type() method of QMetaType, about which the Qt6 docs say "This function is deprecated. We strongly advise against using it in new code". QMetaType.fromName() may work instead on Qt6, but I have not tested this.