![]() |
How to declare a dynamic class 'header' - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: How to declare a dynamic class 'header' (/thread-12729.html) |
How to declare a dynamic class 'header' - Alfalfa - Sep-09-2018 I need to use a macro from the Qt framework in a class header (before __init__). In the example below, I would like to replace "obhub" by a variable, but I couldn't find how to do it. I need this to make a module and reuse the code more easily. This is the working, static version: #!/usr/bin/python3 from PyQt5 import QtCore, QtDBus class QDBusObject(QtCore.QObject): def __init__(self, parent): QtCore.QObject.__init__(self) self.__dbusAdaptor = QDBusServerAdapter(self, parent) self.start() def start(self): bus = QtDBus.QDBusConnection.sessionBus() bus.registerObject("/org/obhub/session", self) bus.registerService("org.obhub.session") return bus class QDBusServerAdapter(QtDBus.QDBusAbstractAdaptor): QtCore.Q_CLASSINFO("D-Bus Interface", "org.obhub.session") QtCore.Q_CLASSINFO('D-Bus Introspection', ' <interface name="org.obhub.session">\n' ' <method name="parse">\n' ' <arg direction="in" type="s" name="cmd"/>\n' ' </method>\n' ' </interface>\n') def __init__(self, server, parent): super().__init__(server) self.parent = parent @QtCore.pyqtSlot(str) def parse(self, cmd): passFailed attempt 1, decorator: #!/usr/bin/python3 from PyQt5 import QtCore, QtDBus class QDBusObject(QtCore.QObject): def __init__(self, parent): QtCore.QObject.__init__(self) self.__dbusAdaptor = QDBusServerAdapter(self, parent) self.start() def start(self): bus = QtDBus.QDBusConnection.sessionBus() bus.registerObject("/org/obhub/session", self) bus.registerService("org.obhub.session") return bus def qDbusHeader(func): def wrapper(*args, **kargs): QtCore.Q_CLASSINFO("D-Bus Interface", "org.obhub.session") QtCore.Q_CLASSINFO('D-Bus Introspection', ' <interface name="org.obhub.session">\n' ' <method name="parse">\n' ' <arg direction="in" type="s" name="cmd"/>\n' ' </method>\n' ' </interface>\n') func(*args, **kargs) return wrapper @qDbusHeader class QDBusServerAdapter(QtDBus.QDBusAbstractAdaptor): def __init__(self, server, parent): super().__init__(server) self.parent = parent @QtCore.pyqtSlot(str) def parse(self, cmd): passFailed attempt 2, metaclass: #!/usr/bin/python3 from PyQt5 import QtCore, QtDBus class QDBusObject(QtCore.QObject): def __init__(self, parent): QtCore.QObject.__init__(self) self.__dbusAdaptor = MetaClass(self, parent) self.start() def start(self): bus = QtDBus.QDBusConnection.sessionBus() bus.registerObject("/org/obhub/session", self) bus.registerService("org.obhub.session") return bus class QDBusServerAdapter(QtDBus.QDBusAbstractAdaptor): def __init__(self, server, parent): super().__init__(server) self.parent = parent @QtCore.pyqtSlot(str) def parse(self, cmd): pass class MetaClass(QDBusServerAdapter): def __init__(self, server, parent): QtCore.Q_CLASSINFO("D-Bus Interface", "org.obhub.session") QtCore.Q_CLASSINFO('D-Bus Introspection', ' <interface name="org.obhub.session">\n' ' <method name="parse">\n' ' <arg direction="in" type="s" name="cmd"/>\n' ' </method>\n' ' </interface>\n') QDBusServerAdapter.__init__(self, server, parent) RE: How to declare a dynamic class 'header' - ichabod801 - Sep-10-2018 Factory function? def factory_func(org_name): class QDBusTemp(QtDBus.QDBusAbstractAdaptor): QtCore.Q_CLASSINFO("D-Bus Interface", "org.{}.session".format(org_name)) QtCore.Q_CLASSINFO('D-Bus Introspection', ' <interface name="org.{}.session">\n'.format(org_name) ' <method name="parse">\n' ' <arg direction="in" type="s" name="cmd"/>\n' ' </method>\n' ' </interface>\n') def __init__(self, server, parent): super().__init__(server) self.parent = parent @QtCore.pyqtSlot(str) def parse(self, cmd): pass return QDBusTemp RE: How to declare a dynamic class 'header' - Alfalfa - Sep-10-2018 That does not seem to work unfortunatly. I tried this: #!/usr/bin/python3 from PyQt5 import QtCore, QtDBus class QDBusObject(QtCore.QObject): def __init__(self, parent): QtCore.QObject.__init__(self) self.__dbusAdaptor = factory_func("obhub", self, parent) self.start() def start(self): bus = QtDBus.QDBusConnection.sessionBus() bus.registerObject("/org/obhub/session", self) bus.registerService("org.obhub.session") return bus def factory_func(org_name, server, parent): class QDBusServerAdapter(QtDBus.QDBusAbstractAdaptor): QtCore.Q_CLASSINFO(f"D-Bus Interface", "org.{org_name}.session") QtCore.Q_CLASSINFO('D-Bus Introspection', f' <interface name="org.{org_name}.session">\n' ' <method name="parse">\n' ' <arg direction="in" type="s" name="cmd"/>\n' ' </method>\n' ' </interface>\n') def __init__(self, server, parent): super().__init__(server) self.parent = parent @QtCore.pyqtSlot(str) def parse(self, cmd): pass return QDBusServerAdapter RE: How to declare a dynamic class 'header' - Alfalfa - Sep-11-2018 To be more specific, here are the details. I use QtDBus as a command line interface. When the application is launched, it verify if a dbus already exist. If it does, it simply pass the command throught it and exit. Else, it create a new instance of the program. Therefore the app is opened only once and can receive commands system wide. I use the example below in many of my apps, just by replacing "foo" with the app name. Therefore I would like to use qdbus.py as a module without having to modify it's code manually every time. To do so I need to customize the content of Q_CLASSINFO dynamically, or to find an alternate way to apply the same settings on the class object. In the attempts above, no error occur, but the dbus object is not created with the appropriate header. So I thought that perhaps, there might be other ways to set "D-Bus Interface" and "D-Bus Introspection" properties, that would be more suitable for portable code. __init__.py #!/usr/bin/python3 from PyQt5 import QtDBus import sys def main(): # Look for the dbus object bus = QtDBus.QDBusConnection.sessionBus() interface = QtDBus.QDBusInterface("org.foo.session", "/org/foo/session", "org.foo.session", bus) # Pass the arguments to the existing bus cmd = "%".join(str(arg) for arg in sys.argv[1:]) if interface.isValid(): interface.call("parse", cmd) sys.exit(0) else: # Create a new instance import foo foo.main() if __name__ == '__main__': main()foo.py #!/usr/bin/python3 import os import sys from PyQt5 import QtWidgets, QtCore, QtDBus import qdbus class Main(QtWidgets.QMainWindow): def __init__(self, parent): super().__init__() self.parent = parent self.bus = qdbus.QDBusObject(self) self.bus.cli.connect(self.parseCommands) def parseCommands(self, cmd): if "action" in cmd: for action in cmd["action"]: print("exec:", action) if "echo" in cmd: print(cmd["echo"]) if "quit" in cmd: self.parent.exit() def main(): app = QtWidgets.QApplication([]) app.setQuitOnLastWindowClosed(False) daemon = Main(app) sys.exit(app.exec_())qdbus.py #!/usr/bin/python3 from PyQt5 import QtCore, QtDBus global name; name = "foo" class QDBusObject(QtCore.QObject): cli = QtCore.pyqtSignal(object) def __init__(self, parent): QtCore.QObject.__init__(self) self.__dbusAdaptor = QDBusServerAdapter(self) self.start() def start(self): bus = QtDBus.QDBusConnection.sessionBus() bus.registerObject(f"/org/{name}/session", self) bus.registerService(f"org.{name}.session") return bus class QDBusServerAdapter(QtDBus.QDBusAbstractAdaptor): QtCore.Q_CLASSINFO("D-Bus Interface", f"org.{name}.session") QtCore.Q_CLASSINFO("D-Bus Introspection", f'<interface name="org.{name}.session">\n' ' <method name="parse">\n' ' <arg direction="in" type="s" name="cmd"/>\n' ' </method>\n' '</interface>\n') def __init__(self, parent): super().__init__(parent) self.parent = parent @QtCore.pyqtSlot(str) def parse(self, cmd): # Serialize the string of commands if cmd: commands = {} current = "" for arg in cmd.split("%"): if arg.startswith("-"): current = arg.lstrip("-") elif current: commands[current].append(arg) if current not in commands: commands[current] = [] self.parent.cli.emit(commands) |