pythonqt icon indicating copy to clipboard operation
pythonqt copied to clipboard

super() does not work for Qt classes

Open usiems opened this issue 4 years ago • 5 comments

I just want to share some insights into this issue, I currently have no intention to fix the issue, as that would be somewhat complicated.

This is an example of what does not work:

from PythonQt.QtGui import QDoubleValidator

class MyFunnyValidator(QDoubleValidator):
  def setRange(self, minimum, maximum, decimals):
    super().setRange(minimum, maximum, decimals+1)

The problem boils down to the fact that the method lookup of super() directly accesses the internal tp_dict member of the super classes, which is only filled to an absolute minimum by PythonQt (for performance reasons). Everything else is delivered through tp_getattro calls, but this does not work for super.

I discussed with Florian Link what would have to be done to fill the tp_dict.

  • This would probably need to happen in PythonQtInstanceWrapper_init the first time an instance of the class is created.
  • One could have a look at PythonQtClassWrapper_getattro how this is done, where the __dict__ member is dynamically filled.
  • But one would have to have in mind that QObject class wrappers can get updated methods when, e.g., the Qt bindings are loaded, so the class tp_dict would have to be updated then or at least flushed.
  • There might be other unforeseen consequences.

We both agreed that this change is somewhat tricky and probably currently not worthwhile.

usiems avatar Feb 09 '21 14:02 usiems

@usiems Is there any known workaround on the python-code side for this?

tonka3000 avatar Oct 26 '23 16:10 tonka3000

When taking the above example, you can always do QDoubleValidator.setRange(self, minimum, maximum, decimals+1) instead.

usiems avatar Oct 27 '23 08:10 usiems

I had a problem yesterday with sizeHint from QWidget. I was aware of the variant you described for QDoubleValidator but I had problems with a property.

My Class is a simple Code block which should resize the content of the text.

Here is a rough version (not working 100% for the resize).

class Code(QPlainTextEdit):
    def __init__(self, parent=None):
        super(Code, self).__init__(parent)

   def heightForWidth(self):
        # some calc here
        return 30

    def sizeHint(self):
        original_hint = super(QWidget, self).sizeHint # does not work as described in the description of the issue
        original_hint = QPlainTextEdit.sizeHint(self) # exception: QSize object no callable
        original_hint = QPlainTextEdit(self).sizeHint # the only which seems to work
        
        return QSize(original_hint.width(), self.heightForWidth(original_hint.width()))

original_hint = QPlainTextEdit(self).sizeHint # the only which seems to work was the only version which was working or in other words don't throw an exception. It creates a second QPlainTextEdit as far as I can see.

What iss the correct way to get a property?

tonka3000 avatar Oct 27 '23 09:10 tonka3000

QPlainTextEdit(self).sizeHint is probably not what you want; this should create a new QPlainTextEdit with your instance as the parent. QPlainTextEdit.sizeHint(self) would be the correct solution, but PythonQt seems to treat sizeHint like a property, though only instances have properties, not their classes. I wonder which QSize is returned here. Anyway, I consider this a bug, but no promises by me if and when this will be fixed.

So, I believe there is currently no way to do this correctly for properties.

usiems avatar Oct 27 '23 11:10 usiems

@usiems Thanks for looking into this. QPlainTextEdit.sizeHint(self) was also my logical answer, good to know that this should be right. I'm not on the latest PythonQt version, so I will migrate and will try again.

tonka3000 avatar Oct 27 '23 12:10 tonka3000