Loading promoted subclass from Qt Designer results in TypeError

Question:

I’m using Qt Designer and trying to promote a subclass QLabel. I created a ui.file and tried to load it with the individual Label. The code (main.py file) looks like this:

from PyQt5.QtWidgets import *
from PyQt5 import uic
import os
import sys


class MyDialog(QDialog):
    def __init__(self):
        super(MyDialog, self).__init__()
        uic.loadUi(os.path.join(basedir, "gui", "Test.ui"))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyDragDropWindow()
    window.setGeometry(800, 100, 1000, 800)
    window.show()
    sys.exit(app.exec_())

The corresponding code of MyLabel is:

from PyQt5.QtWidgets import *

class MyLabel(QLabel):
    def __init__(self):
        super(MyLabel).__init__()

When running the code, the following error occurs: TypeError: __init__() takes 1 positional argument but 2 were given.

The promoting window looks like this:
enter image description here
The MyLabel file is located in the MyWidgets folder, which is in the same folder as the main.py file.

This solution does not work.

Asked By: Mazze

||

Answers:

All QWidget based classes always accept a keyword argument for their parent, which defaults to None.

The UI loader always creates widgets with their parent as argument.

While, for most situations, it’s normally enough to just declare the __init__ with a single "parent" positional argument, it’s considered best practice to always use the *args, **kwargs signature for both the function definition and the super call (as long as the arguments respect the base class constructors).

class MyLabel(QLabel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

In case you need custom arguments for dynamically created widgets, then you have different choices, considering that the first argument will always be the parent:

  • define a specific signature, like def __init__(self, parent, someArg, [...][, *args][, **kwargs]): and then super().__init__(parent);
  • (better) use keyworder/named arguments, and, in that case:
    • if you declare named arguments, always use a default parent=None as first argument;
    • pop other possible keyworded arguments from kwargs before calling the base implementation;
    • use keyworded arguments for custom Qt properties through the pyqtProperty (Property for PySide) decorator or function, but also remember that they will always be set in the super().__init__() call, so if there’s anything that’s required to the processing of those arguments happens after that, you need to pop those values from kwargs and eventually set the property afterwards;

Note: since Python 3, super() doesn’t normally need any argument, but if you specify them, they have to be correct: super(MyLabel).__init__() is wrong, as the instance must be declared along with the class in order to properly resolve the initialization: you either do super(MyLabel, self).__init__() or you just use the default and normally suggested super().__init__().

Answered By: musicamante
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.