Python Forum
How to declare a dynamic class 'header'
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to declare a dynamic class 'header'
#1
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):
      pass
Failed 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):
      pass
Failed 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)
Reply
#2
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
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#3
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
Reply
#4
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)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  SQL Alchemy dynamic class - declarative_base losing attributes mrdominikku 4 3,709 Jan-10-2020, 06:46 PM
Last Post: mrdominikku
  How to declare TextBlob var 3115Tech 2 2,715 Apr-21-2018, 07:04 PM
Last Post: 3115Tech
  Fastest Way to declare this list. Kowalski 2 2,819 Feb-21-2018, 06:26 PM
Last Post: DeaD_EyE

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020