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!
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()
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())
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!
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()
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())