Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Alternative to Q_CLASSINFO macro (PyQt5)
Forum Updated to NodeBB v4.3 + New Features

Alternative to Q_CLASSINFO macro (PyQt5)

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 2 Posters 529 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Alfalfa
    wrote on last edited by
    #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. Is there a way to bypass Q_CLASSINFO?

    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)
    

    Failed attempt #3, factory function:

    #!/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
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Can you describe your use case with more details. It's not really clear what you want to achieve.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • A Offline
        A Offline
        Alfalfa
        wrote on last edited by Alfalfa
        #3

        Thanks for your reply. I am using 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)
        
        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          I don't see any replacement of {name} anywhere in your code.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved