Reputation: 140
I have a LogMixIn class. I want to create a Logger class that I can expose to QML for my QML to use. Since all the methods I want to use are from LogMixIn, is there a way to decorate inherited methods instead of having to redefine them like I do in the example below?
my_logging_lib.py
class LogMixIn():
def logDebug(self, msg):
# Log msg at Debug Severity
qml_logger.py
from PyQt5.QtCore import QObject, pyqtSlot
from my_logging_lib import LogMixIn
class QmlLogger(QObject, LogMixIn):
@pyqtSlot(str)
def logDebug(self, msg):
super().logDebug(msg)
note 1: LogMixIn is use in a large portion of non-UI code so it's desireable to keep it QT agnostic.
Upvotes: 1
Views: 364
Reputation: 120688
In PyQt5, pyqtSlot
can decorate methods of classes that do not inherit from QObject
, such as ordinary Python mixin classes. You can easily check this by examining the meta-object of a subclass that inherits such a mixin:
from PyQt5.QtCore import pyqtSlot, QObject, QMetaMethod
class LogMixIn:
def logDebug(self, msg):
pass
@pyqtSlot(str)
def logDebugEx(self, msg):
pass
class QmlLogger(QObject, LogMixIn):
@pyqtSlot(str)
def logDebug(self, msg):
super().logDebug(msg)
foo = QmlLogger()
meta = foo.metaObject()
for index in range(meta.methodCount()):
method = meta.method(index)
if method.methodType() == QMetaMethod.Slot:
print(method.methodSignature())
Output:
b'deleteLater()'
b'_q_reregisterTimers(void*)'
b'logDebug(QString)'
b'logDebugEx(QString)'
As you can see, it makes no difference how the slots are defined. This is because PyQt does not need to check the type of the containing class until an actual connection is made. If the receiver is found to be a QObject
at that time, PyQt can create an internal proxy QObject
with a slot that can be used by Qt. For QML, the only thing that matters is that the methods are accessible via the meta-object system so that they can be called via e.g. invokeMethod.
Note that pyqtSignal
and pyqtProperty
can also be used in mixins. However, this behaviour was only introduced in PyQt5, so it won't work at all in PyQt4. I believe that similar behaviour is found in all versions of PySide, though.
UPDATE:
If you cannot decorate the mixin directly, the slots can be created within the subclass definition like this:
class QmlLogger(QObject, LogMixIn):
logDebug = pyqtSlot(str)(LogMixIn.logDebug)
Upvotes: 1