Connect to DBus signal – Correct syntax – PySide6

Question:

can you help me with the correct syntax to connect to a DBus signal?

This is one of my many tries which at least runs and matches the signature in the docs:

from PySide6 import QtDBus
from PySide6.QtCore import Q
from PySide6.QtWidgets import QMainWindow

class MainWindow(QMainWindow):
    __slots__ = ["__mainwidget"]
    __mainwidget:QWidget

    def __init__ (self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        service = 'org.freedesktop.DBus'
        path = '/org/freedesktop/DBus'
        iface = 'org.freedesktop.DBus'
        conn = QtDBus.QDBusConnection.systemBus()
        conn.connect(service, path, iface, "NameOwnerChanged", self, "nochangeslot")
        #smp = QtDBus.QDBusInterface(service, path, iface, connection=QtDBus.QDBusConnection.systemBus()


    def nochangeslot(self, arg:object) -> None:
        print(arg)
        pass

But it doesn’t work and looks weird with the slot as string…

On the output I see:

qt.dbus.integration: Could not connect "org.freedesktop.DBus" to ochangeslot

Please consider this is a PySide6 issue and not a PyQt5 issue, the signature of the call is slightly different and my code doesn’t hang like in similar topics on stackoverflow.

Thank you in advance for any help!

Asked By: Drexel

||

Answers:

There are two problems with the example, the first of which is already answered here:

So you firstly just need to add the following line to the example:

conn.registerObject('/', self)

The second problem is very easily fixed in PyQt (which is shown clearly in the question linked above). However, it seems PySide is still using the ugly and error-prone C++ syntax in it’s dbus APIs, which can make connecting signals and slots extremely unintuitive if you’re not a long-term user of PyQt/PySide. By contrast, PyQt sends a generic QDBusMessage, which greatly simplifies matters because there’s no need to know the exact form of the signature beforehand. To illustrate the difference, here’s two basic working examples:

PyQt6:

from PyQt6 import QtCore, QtWidgets, QtDBus

class MainWindow(QtWidgets.QMainWindow):
    def __init__ (self):
        super().__init__()
        service = 'org.freedesktop.DBus'
        path = '/org/freedesktop/DBus'
        iface = 'org.freedesktop.DBus'
        conn = QtDBus.QDBusConnection.systemBus()
        conn.registerObject('/', self)
        conn.connect(service, path, iface, 'NameAcquired', self.nochangeslot)

    @QtCore.pyqtSlot(QtDBus.QDBusMessage)
    def nochangeslot(self, msg):
        print(f'signature: {msg.signature()!r}, '
              f'arguments: {msg.arguments()!r}')

app = QtWidgets.QApplication(['Test'])
window = MainWindow()
window.show()
app.exec()

PySide6:

from PySide6 import QtCore, QtWidgets, QtDBus

class MainWindow(QtWidgets.QMainWindow):
    def __init__ (self):
        super().__init__()
        service = 'org.freedesktop.DBus'
        path = '/org/freedesktop/DBus'
        iface = 'org.freedesktop.DBus'
        conn = QtDBus.QDBusConnection.systemBus()
        conn.registerObject('/', self)
        conn.connect(service, path, iface, 'NameAcquired',
                     self, QtCore.SLOT('nochangeslot(QString)'))

    @QtCore.Slot(str)
    def nochangeslot(self, args):
        print(f'arguments: {args!r}')

app = QtWidgets.QApplication(['Test'])
window = MainWindow()
window.show()
app.exec()
Answered By: ekhumoro

This es the full solution to my initial post, I got this running with the QT/PySide support and they also acknowledged the hangig bug and a Python crash:

import sys
from PySide6.QtWidgets import QMainWindow
from PySide6 import QtDBus, QtCore
from PySide6.QtCore import QLibraryInfo, qVersion, Slot
from PySide6.QtWidgets import QApplication, QMainWindow

class MainWindow(QMainWindow):

    def __init__ (self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        service = "org.freedesktop.DBus"
        path = "/org/freedesktop/DBus"
        iface = "org.freedesktop.DBus"
        conn = QtDBus.QDBusConnection.systemBus()

        #without this, the conn.connect call hangs, seems to be a bug, is already reported and fixed.
        conn.registerObject('/', self)

        conn.connect(service, path, iface, "NameOwnerChanged", self, QtCore.SLOT("nameownerchanged(QString, QString, QString)"))    
        pass

    @Slot(str, str, str)
    def nameownerchanged(self, arg1:str, arg2:str, arg3:str) -> None:
        print(arg1)
        print(arg2)
        print(arg3)
        pass

if __name__ == '__main__':
    print('Python {}.{}.{} {}'.format(sys.version_info[0], sys.version_info[1],
                                       sys.version_info[2], sys.platform))
    print(QLibraryInfo.build())
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setWindowTitle(qVersion())
    window.resize(800, 480)
    window.show()
    sys.exit(app.exec())
Answered By: Drexel
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.