How to expose DBus methods and properties using QDBusAbstractAdaptor with PyQt4?

I am trying to get the base code running on DBus using PyQt4, specifically QtDBus. I am using the Python3 version of PyQt4. I already got the code that I want to run in Qt (C ++), but I want the same code to work using only Python. I want to set the methods, signals / slots and properties in DBus for another Python code to call.

In Qt, you use the macro / function Q_CLASSINFO to perform an introspection of DBus. Although I pulled the Q_CLASSINFO method, I cannot get it to create the same type of functionality. As far as I can tell, there is zero documentation on the Q_CLASSINFO method, so I'm not sure if there is another way. Using D-Feet, I clearly see that no methods are automatically displayed, so I'm kind of stuck.

Here is what I still have.

from PyQt4 import QtDBus from PyQt4.QtCore import QCoreApplication, QObject, Q_CLASSINFO, pyqtSlot, pyqtProperty from PyQt4.QtDBus import QDBusConnection, QDBusAbstractAdaptor SERVICE = 'com.home.dbus' class MyServer(QObject): def __init__(self): QObject.__init__(self) self.__dbusAdaptor = ServerAdaptor(self) def close(self): pass def echo(self, value): echoed = 'Received {0}'.format(value) return echoed def name(self): return 'myname' def dbus_adaptor(self): return self.__dbusAdaptor class ServerAdaptor(QDBusAbstractAdaptor): """ This provides the DBus adaptor to the outside world""" def __init__(self, parent): super().__init__(parent) self.__parent = parent Q_CLASSINFO("D-Bus Introspection", " <interface name=\"com.home.dbus\">\n" " <method name=\"name\">\n" " <arg direction=\"out\" type=\"s\" name=\"name\"/>\n" " </method>\n" " <method name=\"echo\">\n" " <arg direction=\"in\" type=\"s\" name=\"phrase\"/>\n" " <arg directory=\"out\" type=\"s\" name=\"echoed\"/>\n" " </method>\n" " </interface>\n") def close(self): parent.close() def echo(self, value): return parent.echo(value) def name(self): return parent.name def start(): app = QCoreApplication([]) if QDBusConnection.sessionBus().isConnected() == False: print('Cannot connect to D-Bus session bus') return print('Starting') server = MyServer() if not QDBusConnection.sessionBus().registerService(SERVICE): print('Unable to register service name') return if not QDBusConnection.sessionBus().registerObject('/mydbus', server.dbus_adaptor): print('Unable to register object at service path') return app.exec(); print('Exited') if __name__ == '__main__': start() 

I really like to use QtDBus in C ++ because of the way I want to structure this large project, I really need an object that access through DBus should be written in Python3.

+1
source share
1 answer

There are several problems in your program. I recommend looking at examples of remotecontrolledcar and pingpong from the latest PyQt sources, they are very useful. Key notes:

  • You should pass an instance of MyServer (not ServerAdaptor ) to registerObject()
  • Add pyqtSlot() decorators to the functions you want to open via D-Bus
  • Call Q_CLASSINFO() at the top of the adapter class, and not in its __init__() function
  • Also set the "D-Bus Interface" with Q_CLASSINFO()
  • Your introspective XML contains a typo ("directory" instead of "direction")

Here is an example that works for me (Python 3.2.3 / Qt 4.8.2 / PyQt 4.9.4):

 from PyQt4 import QtDBus from PyQt4.QtCore import (QCoreApplication, QObject, Q_CLASSINFO, pyqtSlot, pyqtProperty) from PyQt4.QtDBus import QDBusConnection, QDBusAbstractAdaptor class MyServer(QObject): def __init__(self): QObject.__init__(self) self.__dbusAdaptor = ServerAdaptor(self) self.__name = 'myname' def echo(self, value): return'Received: {0}'.format(value) @property def name(self): return self.__name @name.setter def name(self, value): self.__name = value class ServerAdaptor(QDBusAbstractAdaptor): """ This provides the DBus adaptor to the outside world""" Q_CLASSINFO("D-Bus Interface", "com.home.dbus") Q_CLASSINFO("D-Bus Introspection", ' <interface name="com.home.dbus">\n' ' <property name="name" type="s" access="readwrite"/>\n' ' <method name="echo">\n' ' <arg direction="in" type="s" name="phrase"/>\n' ' <arg direction="out" type="s" name="echoed"/>\n' ' </method>\n' ' </interface>\n') def __init__(self, parent): super().__init__(parent) @pyqtSlot(str, result=str) def echo(self, phrase): return self.parent().echo(phrase) @pyqtProperty(str) def name(self): return self.parent().name @name.setter def name(self, value): self.parent().name = value def start(): app = QCoreApplication([]) bus = QDBusConnection.sessionBus() server = MyServer() bus.registerObject('/mydbus', server) bus.registerService('com.home.dbus') app.exec() if __name__ == '__main__': start() 
+4
source

Source: https://habr.com/ru/post/919382/


All Articles