spyder-ide / qtpy

Provides an uniform layer to support PyQt5, PySide2, PyQt6, PySide6 with a single codebase
MIT License
955 stars 151 forks source link

Qtpy is non-functional with PySide 6.7.0 #480

Open trwilliams79 opened 2 months ago

trwilliams79 commented 2 months ago

PySide 6.7.0 just came out, and it appears to have broken things in QtPy, in particular with QSplitter. For the moment I'm limiting my application to PySide6~=6.6.0, but that's not ideal for the long run.

The following example code works when the from qtpy. calls are replaced with from PySide6.. It also works when a PySide6 version less than 6.7.0 is used, or when any version of PyQt is used.

import sys
from qtpy.QtWidgets import *
from qtpy.QtGui import *
from qtpy.QtCore import *

class Example(QWidget):
    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):
        listwidget =  QListWidget()
        listwidget.addItems(['list 1', 'list 2', 'list 3'])

        treewidget =  QTreeWidget()
        item_one = QTreeWidgetItem(treewidget, ['item 1'])
        QTreeWidgetItem(item_one, ['item 1 child 1'])
        QTreeWidgetItem(item_one, ['item 1 child 2'])
        item_two = QTreeWidgetItem(treewidget, ['item 2'])
        QTreeWidgetItem(item_two, ['item 2 child 1'])
        QTreeWidgetItem(item_two, ['item 2 child 2'])

        textedit =  QTextEdit('Text entry')

        splitter =  QSplitter(self)
        splitter.addWidget(listwidget)
        splitter.addWidget(treewidget)
        splitter.addWidget(textedit)

        hbox = QHBoxLayout(self)
        hbox.addWidget(splitter)
        self.setLayout(hbox)
        self.setGeometry(300, 300, 400, 300)
        self.setWindowTitle('QSplitter demo')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

However, when run as provided, it throws the following error.

Traceback (most recent call last):
  File "C:\Projects\Python\QSplitterTest\test.py", line 43, in <module>
    main()
  File "C:\Projects\Python\QSplitterTest\test.py", line 39, in main
    ex = Example()
  File "C:\Projects\Python\QSplitterTest\test.py", line 9, in __init__
    self.initUI()
  File "C:\Projects\Python\QSplitterTest\test.py", line 26, in initUI
    splitter.addWidget(listwidget)
TypeError: 'PySide6.QtWidgets.QSplitter.addWidget' called with wrong argument types:
  PySide6.QtWidgets.QSplitter.addWidget(QListWidget)
Supported signatures:
  PySide6.QtWidgets.QSplitter.addWidget(PySide6.QtWidgets.QWidget)
hmaarrfk commented 2 months ago

I came here to see if this was indeed a qtpy issue or a PySide6 issue, and it seems to in fact be some strange interaction:

Even reducing the imports to the strict minimum:

import sys
from PySide6.QtWidgets import QTreeWidget, QTreeWidgetItem, QTextEdit, QListWidget, QSplitter, QWidget, QApplication, QHBoxLayout

class Example(QWidget):

I have a feeling it might be related to: https://bugreports.qt.io/browse/PYSIDE-2675

Will continue to investigate (fyi, I'm not a developer of qtpy, just a mere user trying to help)

ccordoba12 commented 2 months ago

@hmaarrfk, thanks for chiming in and providing additional context for this issue!

I doubt that this is a problem with Qtpy because for the most part it's a wrapper for PySide/PyQt (we patch some objects for compatibility between bindings and versions, but we try to keep that to a minimum).

hmaarrfk commented 2 months ago

I really think it has something to do with their lazy import structure. The issue I referred to and some notes from https://wiki.qt.io/Qt_for_Python_Development_Notes hint that they are working through a few things with it.

import sys
from PySide6.QtWidgets import QWidget
from qtpy.QtWidgets import *
from qtpy.QtGui import *
from qtpy.QtCore import *

class Example(QWidget):

"works" So I think it is related to the note:

image

hmaarrfk commented 2 months ago

So FYI, for my code, I had to add above all other qtpy wigets imports and whatnot

import qtpy
if qtpy.PYSIDE6:
     from PySide6.QtWidgets import QWidget

with an adequate note as to when it can be removed. It isn't ideal, but it "works".

trwilliams79 commented 2 months ago

So FYI, for my code, I had to add above all other qtpy wigets imports and whatnot

import qtpy
if qtpy.PYSIDE6:
     from PySide6.QtWidgets import QWidget

with an adequate note as to when it can be removed. It isn't ideal, but it "works".

It should be noted that I'm not lazy importing in production code, just in the example. That said, I suspect the solution you provided will work. Its not ideal, but it should work. I'll have to try it out when I return to the office on Monday.

hmaarrfk commented 2 months ago

The screenshot of their development notes indicates that * importing may be a source of problems.

This compatibility layer uses star style imports.

ewerybody commented 2 months ago

I wonder if it works again If one unrolls ALL members that would be imported via * like:

...
elif PYSIDE6:
    import PySide6.QtCore
    from PySide6.QtCore import (
        ClassInfo, MetaFunction, Property, QAbstractAnimation, QAbstractEventDispatcher,
        QAbstractItemModel, QAbstractListModel, QAbstractNativeEventFilter, QAbstractProxyModel,
        QAbstractTableModel, QAnimationGroup, QBasicMutex, QBasicTimer, QBitArray, QBuffer,
        QByteArray, QByteArrayMatcher, QCborArray, QCborError, QCborKnownTags, QCborMap,
        QCborParserError, QCborSimpleType, QCborStreamReader, QCborStreamWriter,
        QCborStringResultByteArray, QCborStringResultString, QCborValue, QChildEvent, QCollator,
        QCollatorSortKey, QCommandLineOption, QCommandLineParser, QCoreApplication,
        QCryptographicHash, QDataStream, QDate ...

(snip from qtpy/QtCore.py)

Probably. I'm not gonna try for my hobby projects (will simply deprecate PySide2 support) But might be an idea for qtpy (and our wrapper at work)

trwilliams79 commented 2 months ago

The screenshot of their development notes indicates that * importing may be a source of problems.

This compatibility layer uses star style imports.

Ah, my bad, I misread what you'd originally entered.

dd-ssc commented 2 months ago

Does anyone have quickfix / hack to make qta-browser work with PySide 6.7.0 ? (see also qtawesome #261). Doesn't matter how bad, I just need to get icon names again. I tried adding the if qtpy.PYSIDE6: thing from above, but that doesn't fix the issue. Alternatively, I could of course create a venv with the previous PySide version and use it from there...

ccordoba12 commented 2 months ago

I think there's no workaround possible at the moment, sorry.

th3w1zard1 commented 1 month ago

Does anyone have quickfix / hack to make qta-browser work with PySide 6.7.0 ? (see also qtawesome #261). Doesn't matter how bad, I just need to get icon names again. I tried adding the if qtpy.PYSIDE6: thing from above, but that doesn't fix the issue. Alternatively, I could of course create a venv with the previous PySide version and use it from there...

PySide6 v6.7 is BRAND new. Why not just use PySide6 v6.6.1 until various devs can catch up? There's a reason pip freeze defaults to saving exact versions when creating requirements.txt files

psobolewskiPhD commented 1 month ago

FYI: this might be fixed in 6.7.1 https://bugreports.qt.io/browse/PYSIDE-2675