From 80dc006094fab4e4a950b2cf0fbb74ad130d5dbd Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 22 Feb 2024 07:43:38 -0700 Subject: [PATCH 01/37] Added PySide6 Support --- Qt.py | 137 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 26 deletions(-) diff --git a/Qt.py b/Qt.py index b68f9a73..08b5c036 100644 --- a/Qt.py +++ b/Qt.py @@ -3,14 +3,16 @@ DOCUMENTATION Qt.py was born in the film and visual effects industry to address the growing need for the development of software capable of running - with more than one flavour of the Qt bindings for Python - PySide, - PySide2, PyQt4 and PyQt5. + with more than one flavour of the Qt bindings for Python. + + Supported Binding: PySide, PySide2, PySide6, PyQt4, PyQt5 1. Build for one, run with all 2. Explicit is better than implicit 3. Support co-existence Default resolution order: + - PySide6 - PySide2 - PyQt5 - PySide @@ -80,10 +82,12 @@ _common_members = { "QtCore": [ + "Property", "QAbstractAnimation", "QAbstractEventDispatcher", "QAbstractItemModel", "QAbstractListModel", + "QAbstractProxyModel", "QAbstractState", "QAbstractTableModel", "QAbstractTransition", @@ -114,6 +118,8 @@ "QGenericArgument", "QGenericReturnArgument", "QHistoryState", + "QItemSelection", + "QItemSelectionModel", "QItemSelectionRange", "QIODevice", "QLibraryInfo", @@ -155,8 +161,10 @@ "QSize", "QSizeF", "QSocketNotifier", + "QSortFilterProxyModel", "QState", "QStateMachine", + "QStringListModel", "QSysInfo", "QSystemSemaphore", "QT_TRANSLATE_NOOP", @@ -211,7 +219,9 @@ "qVersion", "qWarning", "qrand", - "qsrand" + "qsrand", + "Signal", + "Slot" ], "QtGui": [ "QAbstractTextDocumentLayout", @@ -730,12 +740,14 @@ def messageOutputHandler(*args): passObject = messageOutputHandler if handler else handler if Qt.IsPySide or Qt.IsPyQt4: return Qt._QtCore.qInstallMsgHandler(passObject) - elif Qt.IsPySide2 or Qt.IsPyQt5: + elif Qt.IsPySide2 or Qt.IsPyQt5 or Qt.IsPySide6: return Qt._QtCore.qInstallMessageHandler(passObject) def _getcpppointer(object): - if hasattr(Qt, "_shiboken2"): + if hasattr(Qt, "_shiboken6"): + return getattr(Qt, "_shiboken6").getCppPointer(object)[0] + elif hasattr(Qt, "_shiboken2"): return getattr(Qt, "_shiboken2").getCppPointer(object)[0] elif hasattr(Qt, "_shiboken"): return getattr(Qt, "_shiboken").getCppPointer(object)[0] @@ -773,6 +785,8 @@ def _wrapinstance(ptr, base=None): func = getattr(Qt, "_sip").wrapinstance elif Qt.IsPySide2: func = getattr(Qt, "_shiboken2").wrapInstance + elif Qt.IsPySide6: + func = getattr(Qt, "_shiboken6").wrapInstance elif Qt.IsPySide: func = getattr(Qt, "_shiboken").wrapInstance else: @@ -812,7 +826,10 @@ def _isvalid(object): object (QObject): QObject to check the validity of. """ - if hasattr(Qt, "_shiboken2"): + if hasattr(Qt, "_shiboken6"): + return getattr(Qt, "_shiboken6").isValid(object) + + elif hasattr(Qt, "_shiboken2"): return getattr(Qt, "_shiboken2").isValid(object) elif hasattr(Qt, "_shiboken"): @@ -1014,17 +1031,29 @@ def createWidget(self, class_name, parent=None, name=""): """ _misplaced_members = { + "PySide6": { + "QtGui.QShortcut": "QtWidgets.QShortcut", + "QtGui.QStringListModel": "QtCore.QStringListModel", + "QtGui.QAction": "QtWidgets.QAction", + "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], + "shiboken6.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance], + "shiboken6.getCppPointer": ["QtCompat.getCppPointer", _getcpppointer], + "shiboken6.isValid": ["QtCompat.isValid", _isvalid], + "QtWidgets.qApp": "QtWidgets.QApplication.instance()", + "QtCore.QCoreApplication.translate": [ + "QtCompat.translate", _translate + ], + "QtWidgets.QApplication.translate": [ + "QtCompat.translate", _translate + ], + "QtCore.qInstallMessageHandler": [ + "QtCompat.qInstallMessageHandler", _qInstallMessageHandler + ], + "QtWidgets.QStyleOptionViewItem": "QtCompat.QStyleOptionViewItemV4", + "QtMultimedia.QSound": "QtMultimedia.QSound", + }, "PySide2": { - "QtCore.QStringListModel": "QtCore.QStringListModel", "QtGui.QStringListModel": "QtCore.QStringListModel", - "QtCore.Property": "QtCore.Property", - "QtCore.Signal": "QtCore.Signal", - "QtCore.Slot": "QtCore.Slot", - "QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel", - "QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", - "QtCore.QItemSelection": "QtCore.QItemSelection", - "QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel", - "QtCore.QItemSelectionRange": "QtCore.QItemSelectionRange", "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], "shiboken2.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance], "shiboken2.getCppPointer": ["QtCompat.getCppPointer", _getcpppointer], @@ -1046,12 +1075,6 @@ def createWidget(self, class_name, parent=None, name=""): "QtCore.pyqtProperty": "QtCore.Property", "QtCore.pyqtSignal": "QtCore.Signal", "QtCore.pyqtSlot": "QtCore.Slot", - "QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel", - "QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", - "QtCore.QStringListModel": "QtCore.QStringListModel", - "QtCore.QItemSelection": "QtCore.QItemSelection", - "QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel", - "QtCore.QItemSelectionRange": "QtCore.QItemSelectionRange", "uic.loadUi": ["QtCompat.loadUi", _loadUi], "sip.wrapinstance": ["QtCompat.wrapInstance", _wrapinstance], "sip.unwrapinstance": ["QtCompat.getCppPointer", _getcpppointer], @@ -1075,9 +1098,6 @@ def createWidget(self, class_name, parent=None, name=""): "QtGui.QStringListModel": "QtCore.QStringListModel", "QtGui.QItemSelection": "QtCore.QItemSelection", "QtGui.QItemSelectionModel": "QtCore.QItemSelectionModel", - "QtCore.Property": "QtCore.Property", - "QtCore.Signal": "QtCore.Signal", - "QtCore.Slot": "QtCore.Slot", "QtGui.QItemSelectionRange": "QtCore.QItemSelectionRange", "QtGui.QAbstractPrintDialog": "QtPrintSupport.QAbstractPrintDialog", "QtGui.QPageSetupDialog": "QtPrintSupport.QPageSetupDialog", @@ -1122,7 +1142,6 @@ def createWidget(self, class_name, parent=None, name=""): "QtGui.QPrintPreviewWidget": "QtPrintSupport.QPrintPreviewWidget", "QtGui.QPrinter": "QtPrintSupport.QPrinter", "QtGui.QPrinterInfo": "QtPrintSupport.QPrinterInfo", - # "QtCore.pyqtSignature": "QtCore.Slot", "uic.loadUi": ["QtCompat.loadUi", _loadUi], "sip.wrapinstance": ["QtCompat.wrapInstance", _wrapinstance], "sip.unwrapinstance": ["QtCompat.getCppPointer", _getcpppointer], @@ -1157,6 +1176,26 @@ def createWidget(self, class_name, parent=None, name=""): } """ _compatibility_members = { + "PySide6": { + "QWidget": { + "grab": "QtWidgets.QWidget.grab", + }, + "QHeaderView": { + "sectionsClickable": "QtWidgets.QHeaderView.sectionsClickable", + "setSectionsClickable": + "QtWidgets.QHeaderView.setSectionsClickable", + "sectionResizeMode": "QtWidgets.QHeaderView.sectionResizeMode", + "setSectionResizeMode": + "QtWidgets.QHeaderView.setSectionResizeMode", + "sectionsMovable": "QtWidgets.QHeaderView.sectionsMovable", + "setSectionsMovable": "QtWidgets.QHeaderView.setSectionsMovable", + }, + "QFileDialog": { + "getOpenFileName": "QtWidgets.QFileDialog.getOpenFileName", + "getOpenFileNames": "QtWidgets.QFileDialog.getOpenFileNames", + "getSaveFileName": "QtWidgets.QFileDialog.getSaveFileName", + }, + }, "PySide2": { "QWidget": { "grab": "QtWidgets.QWidget.grab", @@ -1435,6 +1474,50 @@ def _build_compatibility_members(binding, decorators=None): setattr(Qt.QtCompat, classname, compat_class) +def _pyside6(): + """Initialise PySide6 + + These functions serve to test the existence of a binding + along with set it up in such a way that it aligns with + the final step; adding members from the original binding + to Qt.py + + """ + + import PySide6 as module + extras = ["QtUiTools"] + try: + import shiboken6 + extras.append("shiboken6") + except ImportError as e: + print("ImportError: %s" % e) + + _setup(module, extras) + Qt.__binding_version__ = module.__version__ + + if hasattr(Qt, "_shiboken6"): + Qt.QtCompat.wrapInstance = _wrapinstance + Qt.QtCompat.getCppPointer = _getcpppointer + Qt.QtCompat.delete = shiboken6.delete + + if hasattr(Qt, "_QtUiTools"): + Qt.QtCompat.loadUi = _loadUi + + if hasattr(Qt, "_QtCore"): + Qt.__qt_version__ = Qt._QtCore.qVersion() + Qt.QtCompat.dataChanged = ( + lambda self, topleft, bottomright, roles=None: + self.dataChanged.emit(topleft, bottomright, roles or []) + ) + + if hasattr(Qt, "_QtWidgets"): + Qt.QtCompat.setSectionResizeMode = \ + Qt._QtWidgets.QHeaderView.setSectionResizeMode + + _reassign_misplaced_members("PySide6") + _build_compatibility_members("PySide6") + + def _pyside2(): """Initialise PySide2 @@ -1821,7 +1904,7 @@ def __call__(self, *a, **kw): def _install(): # Default order (customize order and content via QT_PREFERRED_BINDING) - default_order = ("PySide2", "PyQt5", "PySide", "PyQt4") + default_order = ("PySide6", "PySide2", "PyQt5", "PySide", "PyQt4") preferred_order = None if QT_PREFERRED_BINDING_JSON: # A per-vendor preferred binding customization was defined @@ -1854,6 +1937,7 @@ def _install(): order = preferred_order or default_order available = { + "PySide6": _pyside6, "PySide2": _pyside2, "PyQt5": _pyqt5, "PySide": _pyside, @@ -1938,6 +2022,7 @@ def _install(): _install() # Setup Binding Enum states +Qt.IsPySide6 = Qt.__binding__ == "PySide6" Qt.IsPySide2 = Qt.__binding__ == 'PySide2' Qt.IsPyQt5 = Qt.__binding__ == 'PyQt5' Qt.IsPySide = Qt.__binding__ == 'PySide' From a25cc94ba02b5a8e9a3697d5e431efc0062c1b2a Mon Sep 17 00:00:00 2001 From: zoshua Date: Wed, 28 Feb 2024 15:52:23 -0700 Subject: [PATCH 02/37] Create pyside6.yml --- .github/workflows/pyside6.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/pyside6.yml diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml new file mode 100644 index 00000000..e8a1eb84 --- /dev/null +++ b/.github/workflows/pyside6.yml @@ -0,0 +1,34 @@ +name: Run PySide6 Tests + +on: + push: + branches: + - "*" + pull_request: + branches: + - "*" + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - os: ubuntu-latest + VFXPLATFORM: "2018" + PYTHON: "3.6" + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: pip install PySide6 + run: | + pip install PySide6 + + - name: Run tests in Docker container + run: | + docker run --rm \ + -v $(pwd):/Qt.py \ + -e PYTHON=${{ matrix.PYTHON }} \ + fredrikaverpil/qt.py:${{ matrix.VFXPLATFORM }} From 55889edf626f921abb9a9762f561d8f5eb8b5dd4 Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 29 Feb 2024 08:26:19 -0700 Subject: [PATCH 03/37] Updated pyside6.yml removed strategy block updated pip install step updated the run tests step --- .github/workflows/pyside6.yml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index e8a1eb84..417502c8 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -10,25 +10,16 @@ on: jobs: test: - runs-on: ubuntu-latest - strategy: - matrix: - include: - - os: ubuntu-latest - VFXPLATFORM: "2018" - PYTHON: "3.6" + runs-on: ubuntu-22.04 steps: - name: Checkout code uses: actions/checkout@v4 - - name: pip install PySide6 + - name: Pip install PySide6 and dependencies run: | - pip install PySide6 + python3.10 -m pip install PySide6 nose nosepipe six packaging setuptools wheel - - name: Run tests in Docker container + - name: Run tests from entrypoint.sh run: | - docker run --rm \ - -v $(pwd):/Qt.py \ - -e PYTHON=${{ matrix.PYTHON }} \ - fredrikaverpil/qt.py:${{ matrix.VFXPLATFORM }} + PYTHON=3.10 ./entrypoint.sh From 47ac768504d18289732f4f08ca32ec893e198474 Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 29 Feb 2024 08:30:17 -0700 Subject: [PATCH 04/37] Update pyside6.yml added step Set entrypoint.sh script permissions --- .github/workflows/pyside6.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 417502c8..6b86c00b 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -20,6 +20,10 @@ jobs: run: | python3.10 -m pip install PySide6 nose nosepipe six packaging setuptools wheel + - name: Set entrypoint.sh script permissions + run: | + chmod +x ./entrypoint.sh + - name: Run tests from entrypoint.sh run: | PYTHON=3.10 ./entrypoint.sh From f9936954b1e47393689a42571352fb5a655c5b59 Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 29 Feb 2024 08:52:03 -0700 Subject: [PATCH 05/37] Update entrypoint.sh changed nosetests${PYTHON} to python${PYTHON} -m nose --- entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index bed3c6b5..90f85fb3 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -22,13 +22,13 @@ printf "#\n# Testing implementation..\n" python${PYTHON} -u run_tests.py printf "#\n# Testing caveats..\n" python${PYTHON} build_caveats.py - nosetests${PYTHON} \ + python${PYTHON} -m nose \ --verbose \ --with-doctest \ --with-process-isolation \ test_caveats.py printf "#\n# Testing examples..\n" - nosetests${PYTHON} \ + python${PYTHON} -m nose \ --verbose \ --with-process-isolation \ --with-doctest \ From 5209c24ba178a1b09a71cdfd1bd7e6d1a0765546 Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 29 Feb 2024 09:03:04 -0700 Subject: [PATCH 06/37] Update pyside6.yml updated pip install step to use nose2 --- .github/workflows/pyside6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 6b86c00b..64a9a609 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -18,7 +18,7 @@ jobs: - name: Pip install PySide6 and dependencies run: | - python3.10 -m pip install PySide6 nose nosepipe six packaging setuptools wheel + python3.10 -m pip install PySide6 nose2 nosepipe six packaging setuptools wheel - name: Set entrypoint.sh script permissions run: | From 39c28dd150069551873d7257d5c48a6e1cbd8a03 Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 29 Feb 2024 09:04:32 -0700 Subject: [PATCH 07/37] Update entrypoint.sh updated to use nose2 --- entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 90f85fb3..2593f9df 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -22,13 +22,13 @@ printf "#\n# Testing implementation..\n" python${PYTHON} -u run_tests.py printf "#\n# Testing caveats..\n" python${PYTHON} build_caveats.py - python${PYTHON} -m nose \ + python${PYTHON} -m nose2 \ --verbose \ --with-doctest \ --with-process-isolation \ test_caveats.py printf "#\n# Testing examples..\n" - python${PYTHON} -m nose \ + python${PYTHON} -m nose2 \ --verbose \ --with-process-isolation \ --with-doctest \ From c0d64e07b067f4d192e12e4f6e88697df95e9dbe Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 29 Feb 2024 09:12:40 -0700 Subject: [PATCH 08/37] Update entrypoint.sh removed incompatible nose2 command line arguments --- entrypoint.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 2593f9df..25bcfc1b 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -24,15 +24,10 @@ printf "#\n# Testing caveats..\n" python${PYTHON} build_caveats.py python${PYTHON} -m nose2 \ --verbose \ - --with-doctest \ - --with-process-isolation \ test_caveats.py printf "#\n# Testing examples..\n" python${PYTHON} -m nose2 \ --verbose \ - --with-process-isolation \ - --with-doctest \ - --exe \ examples/*/*.py printf Done From d855ccf6444d7ed4175346f595c1d64d23a59a7a Mon Sep 17 00:00:00 2001 From: zoshua Date: Thu, 29 Feb 2024 09:25:54 -0700 Subject: [PATCH 09/37] Update entrypoint.sh more nose2 usage updates --- entrypoint.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 25bcfc1b..f6e20eec 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -18,16 +18,20 @@ done printf "#\n# Running tests in Python ${PYTHON}\n" export NOSETESTS_BINARY=nosetests${PYTHON} + printf "#\n# Testing implementation..\n" python${PYTHON} -u run_tests.py + printf "#\n# Testing caveats..\n" python${PYTHON} build_caveats.py python${PYTHON} -m nose2 \ --verbose \ - test_caveats.py + test_caveats + printf "#\n# Testing examples..\n" + cd examples python${PYTHON} -m nose2 \ - --verbose \ - examples/*/*.py + --verbose + cd .. printf Done From e23780c776d6e089a443d2f837a1188ec7478623 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 07:16:18 -0700 Subject: [PATCH 10/37] Update entrypoint.sh - rolling back changes --- entrypoint.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index f6e20eec..bed3c6b5 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -18,20 +18,21 @@ done printf "#\n# Running tests in Python ${PYTHON}\n" export NOSETESTS_BINARY=nosetests${PYTHON} - printf "#\n# Testing implementation..\n" python${PYTHON} -u run_tests.py - printf "#\n# Testing caveats..\n" python${PYTHON} build_caveats.py - python${PYTHON} -m nose2 \ + nosetests${PYTHON} \ --verbose \ - test_caveats - + --with-doctest \ + --with-process-isolation \ + test_caveats.py printf "#\n# Testing examples..\n" - cd examples - python${PYTHON} -m nose2 \ - --verbose - cd .. + nosetests${PYTHON} \ + --verbose \ + --with-process-isolation \ + --with-doctest \ + --exe \ + examples/*/*.py printf Done From f9b4ca141787354b65016482c4909fd5d10a1881 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 07:16:58 -0700 Subject: [PATCH 11/37] Update pyside6.yml - run tests directly --- .github/workflows/pyside6.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 64a9a609..2fc8ebbf 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -20,10 +20,20 @@ jobs: run: | python3.10 -m pip install PySide6 nose2 nosepipe six packaging setuptools wheel - - name: Set entrypoint.sh script permissions + - name: Testing implementation.. run: | - chmod +x ./entrypoint.sh + python3.10 -u run_tests.py - - name: Run tests from entrypoint.sh + - name: Building caveats.. run: | - PYTHON=3.10 ./entrypoint.sh + python3.10 -u build_caveats.py + + - name: Testing caveats.. + run: | + python3.10 -m nose2 --verbose test_caveats + + - name: Testing examples.. + run: | + cd examples + python3.10 -m nose2 --verbose + cd .. From 6d6f955ee66dba39e313177b471e7475a35947f1 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 08:03:52 -0700 Subject: [PATCH 12/37] Update pyside6.yml - Testing examples step Specifying Testing examples directly per nose2 --- .github/workflows/pyside6.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 2fc8ebbf..3e82a17f 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -35,5 +35,7 @@ jobs: - name: Testing examples.. run: | cd examples - python3.10 -m nose2 --verbose + python3.10 -m nose2 --verbose loadUi.baseinstance1 + python3.10 -m nose2 --verbose loadUi.baseinstance2 + python3.10 -m nose2 --verbose QtSiteConfig.main cd .. From 158651d40b88275c5ae5ffd5a35fe203d71b7cfd Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 09:10:31 -0700 Subject: [PATCH 13/37] Update pyside6.yml - Testing Example PYTHONPATH added PWD to current PYTHONPATH --- .github/workflows/pyside6.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 3e82a17f..c9b4a2fa 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -39,3 +39,5 @@ jobs: python3.10 -m nose2 --verbose loadUi.baseinstance2 python3.10 -m nose2 --verbose QtSiteConfig.main cd .. + env: + PYTHONPATH: ${{ env.PYTHONPATH }}:$(pwd) From 392f0cd0ba5c4dc4644c8e49753c38d959d9e5b5 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 11:14:55 -0700 Subject: [PATCH 14/37] Update run_tests.py - added with binding PySide6 --- run_tests.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/run_tests.py b/run_tests.py index d47fce19..81d1c126 100644 --- a/run_tests.py +++ b/run_tests.py @@ -52,5 +52,8 @@ def binding(binding): with binding("PySide2"): errors += subprocess.call(argv) + with binding("PySide6"): + errors += subprocess.call(argv) + if errors: raise Exception("%i binding(s) failed." % errors) From 4e1fd21dc6cdc3cea0fc53953dc7f0f3dbdcdfab Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 11:16:32 -0700 Subject: [PATCH 15/37] Update pyside6.yml - added step Pip install . --- .github/workflows/pyside6.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index c9b4a2fa..5b8e40e0 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -16,6 +16,10 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Pip install . + run: | + python3.10 -m pip install . + - name: Pip install PySide6 and dependencies run: | python3.10 -m pip install PySide6 nose2 nosepipe six packaging setuptools wheel From 606010c96082a127f14f7682b4569a14060f6f23 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 12:58:24 -0700 Subject: [PATCH 16/37] Update run_tests.py - rolling back last commit --- run_tests.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/run_tests.py b/run_tests.py index 81d1c126..d47fce19 100644 --- a/run_tests.py +++ b/run_tests.py @@ -52,8 +52,5 @@ def binding(binding): with binding("PySide2"): errors += subprocess.call(argv) - with binding("PySide6"): - errors += subprocess.call(argv) - if errors: raise Exception("%i binding(s) failed." % errors) From 5083eb98e0ab2e52ca56d103d99f97dd4d917aef Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 13:05:50 -0700 Subject: [PATCH 17/37] Update pyside6.yml - changed step Testing implementation.. Experiment changing step Testing implementation.. now running nose2 tests.py directly --- .github/workflows/pyside6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 5b8e40e0..9ea92929 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -26,7 +26,7 @@ jobs: - name: Testing implementation.. run: | - python3.10 -u run_tests.py + python3.10 -m nose2 --verbose tests - name: Building caveats.. run: | From a31ea4a79e43cbe7ea98fdd865a0ae6b7ea31d39 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 1 Mar 2024 13:17:46 -0700 Subject: [PATCH 18/37] Update pyside6.yml - updated jobs/env (Experimental) added QT_PREFERRED_BINDING set to PySide6 added PYTHONPATH to include the the starting dir --- .github/workflows/pyside6.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 9ea92929..806ff056 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -12,6 +12,10 @@ jobs: test: runs-on: ubuntu-22.04 + env: + QT_PREFERRED_BINDING: PySide6 + PYTHONPATH: "${{ github.workspace }}" + steps: - name: Checkout code uses: actions/checkout@v4 @@ -27,7 +31,7 @@ jobs: - name: Testing implementation.. run: | python3.10 -m nose2 --verbose tests - + - name: Building caveats.. run: | python3.10 -u build_caveats.py @@ -43,5 +47,3 @@ jobs: python3.10 -m nose2 --verbose loadUi.baseinstance2 python3.10 -m nose2 --verbose QtSiteConfig.main cd .. - env: - PYTHONPATH: ${{ env.PYTHONPATH }}:$(pwd) From 310535179ddfa9c2df58e590417150c932383825 Mon Sep 17 00:00:00 2001 From: zoshua Date: Mon, 1 Apr 2024 11:41:06 -0600 Subject: [PATCH 19/37] Major overhaul to: 1. update Qt.py _common_members using memberhip.py 2. extend tests.py to accomodate PySide6 --- Qt.py | 127 ++++--------------------------------- tests.py | 188 ++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 170 insertions(+), 145 deletions(-) diff --git a/Qt.py b/Qt.py index 95606e65..ca86e77e 100644 --- a/Qt.py +++ b/Qt.py @@ -82,15 +82,11 @@ _common_members = { "QtCore": [ - "Property", "QAbstractAnimation", "QAbstractEventDispatcher", "QAbstractItemModel", "QAbstractListModel", - "QAbstractProxyModel", - "QAbstractState", "QAbstractTableModel", - "QAbstractTransition", "QAnimationGroup", "QBasicTimer", "QBitArray", @@ -110,17 +106,11 @@ "QElapsedTimer", "QEvent", "QEventLoop", - "QEventTransition", "QFile", "QFileInfo", "QFileSystemWatcher", - "QFinalState", "QGenericArgument", "QGenericReturnArgument", - "QHistoryState", - "QItemSelection", - "QItemSelectionModel", - "QItemSelectionRange", "QIODevice", "QLibraryInfo", "QLine", @@ -150,20 +140,15 @@ "QReadWriteLock", "QRect", "QRectF", - "QRegExp", "QResource", "QRunnable", "QSemaphore", "QSequentialAnimationGroup", "QSettings", "QSignalMapper", - "QSignalTransition", "QSize", "QSizeF", "QSocketNotifier", - "QSortFilterProxyModel", - "QState", - "QStateMachine", "QStringListModel", "QSysInfo", "QSystemSemaphore", @@ -172,9 +157,6 @@ "QT_TR_NOOP_UTF8", "QTemporaryFile", "QTextBoundaryFinder", - "QTextCodec", - "QTextDecoder", - "QTextEncoder", "QTextStream", "QTextStreamManipulator", "QThread", @@ -185,6 +167,7 @@ "QTimerEvent", "QTranslator", "QUrl", + "QUuid", "QVariantAnimation", "QWaitCondition", "QWriteLocker", @@ -197,15 +180,9 @@ "QXmlStreamReader", "QXmlStreamWriter", "Qt", - "QtCriticalMsg", - "QtDebugMsg", - "QtFatalMsg", "QtMsgType", - "QtSystemMsg", - "QtWarningMsg", "qAbs", "qAddPostRoutine", - "qChecksum", "qCritical", "qDebug", "qFatal", @@ -218,10 +195,7 @@ "qUnregisterResourceData", "qVersion", "qWarning", - "qrand", - "qsrand", - "Signal", - "Slot" + "Signal" ], "QtGui": [ "QAbstractTextDocumentLayout", @@ -287,14 +261,12 @@ "QPalette", "QPen", "QPicture", - "QPictureIO", "QPixmap", "QPixmapCache", "QPolygon", "QPolygonF", "QQuaternion", "QRadialGradient", - "QRegExpValidator", "QRegion", "QResizeEvent", "QSessionManager", @@ -363,17 +335,6 @@ "QHelpSearchQueryWidget", "QHelpSearchResultWidget" ], - "QtMultimedia": [ - "QAbstractVideoBuffer", - "QAbstractVideoSurface", - "QAudio", - "QAudioDeviceInfo", - "QAudioFormat", - "QAudioInput", - "QAudioOutput", - "QVideoFrame", - "QVideoSurfaceFormat" - ], "QtNetwork": [ "QAbstractNetworkCache", "QAbstractSocket", @@ -385,8 +346,6 @@ "QNetworkAccessManager", "QNetworkAddressEntry", "QNetworkCacheMetaData", - "QNetworkConfiguration", - "QNetworkConfigurationManager", "QNetworkCookie", "QNetworkCookieJar", "QNetworkDiskCache", @@ -396,18 +355,17 @@ "QNetworkProxyQuery", "QNetworkReply", "QNetworkRequest", - "QNetworkSession", "QSsl", + "QSslCertificate", + "QSslCipher", + "QSslConfiguration", + "QSslError", + "QSslKey", + "QSslSocket", "QTcpServer", "QTcpSocket", "QUdpSocket" ], - "QtOpenGL": [ - "QGL", - "QGLContext", - "QGLFormat", - "QGLWidget" - ], "QtPrintSupport": [ "QAbstractPrintDialog", "QPageSetupDialog", @@ -418,28 +376,9 @@ "QPrinter", "QPrinterInfo" ], - "QtSql": [ - "QSql", - "QSqlDatabase", - "QSqlDriver", - "QSqlDriverCreatorBase", - "QSqlError", - "QSqlField", - "QSqlIndex", - "QSqlQuery", - "QSqlQueryModel", - "QSqlRecord", - "QSqlRelation", - "QSqlRelationalDelegate", - "QSqlRelationalTableModel", - "QSqlResult", - "QSqlTableModel" - ], "QtSvg": [ - "QGraphicsSvgItem", "QSvgGenerator", - "QSvgRenderer", - "QSvgWidget" + "QSvgRenderer" ], "QtTest": [ "QTest" @@ -452,8 +391,6 @@ "QAbstractScrollArea", "QAbstractSlider", "QAbstractSpinBox", - "QAction", - "QActionGroup", "QApplication", "QBoxLayout", "QButtonGroup", @@ -468,11 +405,9 @@ "QDataWidgetMapper", "QDateEdit", "QDateTimeEdit", - "QDesktopWidget", "QDial", "QDialog", "QDialogButtonBox", - "QDirModel", "QDockWidget", "QDoubleSpinBox", "QErrorMessage", @@ -533,7 +468,6 @@ "QItemDelegate", "QItemEditorCreatorBase", "QItemEditorFactory", - "QKeyEventTransition", "QLCDNumber", "QLabel", "QLayout", @@ -548,7 +482,6 @@ "QMenu", "QMenuBar", "QMessageBox", - "QMouseEventTransition", "QPanGesture", "QPinchGesture", "QPlainTextDocumentLayout", @@ -560,7 +493,6 @@ "QRubberBand", "QScrollArea", "QScrollBar", - "QShortcut", "QSizeGrip", "QSizePolicy", "QSlider", @@ -624,9 +556,6 @@ "QTreeWidget", "QTreeWidgetItem", "QTreeWidgetItemIterator", - "QUndoCommand", - "QUndoGroup", - "QUndoStack", "QUndoView", "QVBoxLayout", "QWhatsThis", @@ -636,9 +565,6 @@ "QWizard", "QWizardPage" ], - "QtX11Extras": [ - "QX11Info" - ], "QtXml": [ "QDomAttr", "QDomCDATASection", @@ -656,38 +582,7 @@ "QDomNodeList", "QDomNotation", "QDomProcessingInstruction", - "QDomText", - "QXmlAttributes", - "QXmlContentHandler", - "QXmlDTDHandler", - "QXmlDeclHandler", - "QXmlDefaultHandler", - "QXmlEntityResolver", - "QXmlErrorHandler", - "QXmlInputSource", - "QXmlLexicalHandler", - "QXmlLocator", - "QXmlNamespaceSupport", - "QXmlParseException", - "QXmlReader", - "QXmlSimpleReader" - ], - "QtXmlPatterns": [ - "QAbstractMessageHandler", - "QAbstractUriResolver", - "QAbstractXmlNodeModel", - "QAbstractXmlReceiver", - "QSourceLocation", - "QXmlFormatter", - "QXmlItem", - "QXmlName", - "QXmlNamePool", - "QXmlNodeModelIndex", - "QXmlQuery", - "QXmlResultItems", - "QXmlSchema", - "QXmlSchemaValidator", - "QXmlSerializer" + "QDomText" ] } @@ -877,7 +772,7 @@ def get_arg(index): else: encoding = n_or_encoding - if Qt.__binding__ in ("PySide2", "PyQt5"): + if Qt.__binding__ in ("PySide2", "PySide6","PyQt5"): sanitized_args = [context, sourceText, disambiguation, n] else: sanitized_args = [ diff --git a/tests.py b/tests.py index 7cb5cea0..7ddfe234 100644 --- a/tests.py +++ b/tests.py @@ -14,9 +14,36 @@ # Third-party dependency import six -from nose.tools import ( - assert_raises, -) + +try: + # Try importing assert_raises from nose.tools + from nose.tools import assert_raises +except ImportError: + # Fallback: Define assert_raises using unittest if the import fails + import unittest + + def assert_raises(expected_exception, callable_obj=None, *args, **kwargs): + """ + Custom implementation of assert_raises using unittest. + + Parameters: + - expected_exception: The exception type that is expected to be raised. + - callable_obj: The callable object that is expected to raise the exception. + - *args, **kwargs: Arguments and keyword arguments to pass to the callable object. + + Usage example: + with assert_raises(SomeException): + function_that_raises_some_exception() + """ + context = unittest.TestCase().assertRaises(expected_exception) + + # If callable_obj is provided, directly call the function with the context manager + if callable_obj: + with context: + callable_obj(*args, **kwargs) + else: + # Otherwise, return the context manager to be used with a 'with' statement + return context PYTHON = sys.version_info[0] # e.g. 2 or 3 @@ -242,6 +269,7 @@ class Widget(QtWidgets.QWidget): """ + qpycustomwidget_ui = u"""\ @@ -273,6 +301,7 @@ class Widget(QtWidgets.QWidget): """ + python_custom_widget = u''' def CustomWidget(parent=None): """ @@ -286,6 +315,7 @@ class Widget(QtWidgets.QWidget): return Widget(parent) ''' + def setup(): """Module-wide initialisation @@ -305,13 +335,26 @@ def saveUiFile(filename, ui_template): self.ui_qmainwindow = saveUiFile("qmainwindow.ui", qmainwindow_ui) self.ui_qdialog = saveUiFile("qdialog.ui", qdialog_ui) self.ui_qdockwidget = saveUiFile("qdockwidget.ui", qdockwidget_ui) - self.ui_qcustomwidget = saveUiFile("qcustomwidget.ui", qcustomwidget_ui) - self.ui_qpycustomwidget = saveUiFile("qpycustomwidget.ui", qpycustomwidget_ui) + self.ui_qpycustomwidget = saveUiFile("qcustomwidget.ui", qcustomwidget_ui) + + +def setUpModule(): + """Module-wide initialisation + + This function runs once, followed by tearDownModule() below once + all tests have completed. + + """ + setup() + def teardown(): shutil.rmtree(self.tempdir) +def tearDownModule(): + teardown() + def binding(binding): """Isolate test to a particular binding @@ -353,9 +396,12 @@ def test_environment(): if sys.version_info < (3, 5): # PySide is not available for Python > 3.4 imp.find_module("PySide") - imp.find_module("PySide2") - imp.find_module("PyQt4") - imp.find_module("PyQt5") + elif os.environ.get("QT_PREFERRED_BINDING") == "PySide6": + imp.find_module("PySide6") + else: + imp.find_module("PySide2") + imp.find_module("PyQt4") + imp.find_module("PyQt5") def test_load_ui_returntype(): @@ -363,7 +409,11 @@ def test_load_ui_returntype(): import sys from Qt import QtWidgets, QtCore, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() obj = QtCompat.loadUi(self.ui_qwidget) assert isinstance(obj, QtCore.QObject) app.exit() @@ -373,7 +423,11 @@ def test_load_ui_baseinstance(): """Tests to see if the baseinstance loading loads a QWidget on properly""" import sys from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QWidget() QtCompat.loadUi(self.ui_qwidget, win) assert hasattr(win, 'lineEdit'), "loadUi could not load instance to win" @@ -384,7 +438,11 @@ def test_load_ui_signals(): """Tests to see if the baseinstance connects signals properly""" import sys from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QWidget() QtCompat.loadUi(self.ui_qwidget, win) @@ -399,7 +457,11 @@ def test_load_ui_mainwindow(): import sys from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QMainWindow() QtCompat.loadUi(self.ui_qmainwindow, win) @@ -415,7 +477,11 @@ def test_load_ui_dialog(): import sys from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QDialog() QtCompat.loadUi(self.ui_qdialog, win) @@ -431,7 +497,11 @@ def test_load_ui_dockwidget(): import sys from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QDockWidget() QtCompat.loadUi(self.ui_qdockwidget, win) @@ -447,10 +517,14 @@ def test_load_ui_customwidget(): import sys from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QMainWindow() - QtCompat.loadUi(self.ui_qcustomwidget, win) + QtCompat.loadUi(self.ui_qpycustomwidget, win) # Ensure that the derived class was properly created # and not the base class (in case of failure) @@ -461,6 +535,7 @@ def test_load_ui_customwidget(): app.exit() + def test_load_ui_pycustomwidget(): """Tests to see if loadUi loads a custom widget properly""" import sys @@ -485,7 +560,12 @@ def test_load_ui_pycustomwidget(): # append the path to ensure the future import can be loaded 'relative' to the tempdir sys.path.append(self.tempdir) - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() + win = QtWidgets.QMainWindow() QtCompat.loadUi(self.ui_qpycustomwidget, win) @@ -504,7 +584,11 @@ def test_load_ui_invalidpath(): """Tests to see if loadUi successfully fails on invalid paths""" import sys from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() assert_raises(IOError, QtCompat.loadUi, 'made/up/path') app.exit() @@ -522,7 +606,11 @@ def test_load_ui_invalidxml(): from xml.etree import ElementTree from Qt import QtWidgets, QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() assert_raises(ElementTree.ParseError, QtCompat.loadUi, invalid_xml) app.exit() @@ -536,7 +624,11 @@ def test_load_ui_existingLayoutOnDialog(): '"Dialog", which already has a layout' with ignoreQtMessageHandler([msgs]): - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QDialog() QtWidgets.QComboBox(win) QtWidgets.QHBoxLayout(win) @@ -553,7 +645,11 @@ def test_load_ui_existingLayoutOnMainWindow(): '"", which already has a layout' with ignoreQtMessageHandler([msgs]): - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QMainWindow() QtWidgets.QComboBox(win) QtWidgets.QHBoxLayout(win) @@ -570,7 +666,11 @@ def test_load_ui_existingLayoutOnDockWidget(): '"", which already has a layout' with ignoreQtMessageHandler([msgs]): - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QDockWidget() QtWidgets.QComboBox(win) QtWidgets.QHBoxLayout(win) @@ -587,7 +687,11 @@ def test_load_ui_existingLayoutOnWidget(): '"Form", which already has a layout' with ignoreQtMessageHandler([msgs]): - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() win = QtWidgets.QWidget() QtWidgets.QComboBox(win) QtWidgets.QHBoxLayout(win) @@ -664,14 +768,14 @@ def test_vendoring(): # # Test invalid json data - # + print("Testing invalid json data..") env = os.environ.copy() env["QT_PREFERRED_BINDING_JSON"] = '{"Qt":["PyQt5","PyQt4"],}' cmd = "import myproject.vendor.Qt;" cmd += "import Qt;" - cmd += "assert myproject.vendor.Qt.__binding__ != 'None', 'vendor';" - cmd += "assert Qt.__binding__ != 'None', 'Qt';" + cmd += "assert myproject.vendor.Qt.__binding__ != None, 'vendor';" + cmd += "assert Qt.__binding__ != None, 'Qt';" popen = subprocess.Popen( [sys.executable, "-c", cmd], @@ -883,6 +987,7 @@ def test_binding_states(): import Qt assert Qt.IsPySide == binding("PySide") assert Qt.IsPySide2 == binding("PySide2") + assert Qt.IsPySide6 == binding("PySide6") assert Qt.IsPyQt5 == binding("PyQt5") assert Qt.IsPyQt4 == binding("PyQt4") @@ -893,7 +998,11 @@ def test_qtcompat_base_class(): import Qt from Qt import QtWidgets from Qt import QtCompat - app = QtWidgets.QApplication(sys.argv) + + if not QtWidgets.QApplication.instance(): + app = QtWidgets.QApplication(sys.argv) + else: + app = QtWidgets.QApplication.instance() # suppress `local variable 'app' is assigned to but never used` app header = QtWidgets.QHeaderView(Qt.QtCore.Qt.Horizontal) @@ -1247,13 +1356,34 @@ def test_coexistence(): """Qt.py may be use alongside the actual binding""" from Qt import QtCore - import PySide2.QtGui + import PySide2.QtCore + + # Qt remaps QStringListModel + assert QtCore.QStringListModel + + # But does not delete the original + assert PySide2.QtCore.QStringListModel + + +if binding("PySide6"): + def test_preferred_pyside6(): + """QT_PREFERRED_BINDING = PySide6 properly forces the binding""" + import Qt + assert Qt.__binding__ == "PySide6", ( + "PySide6 should have been picked, " + "instead got %s" % Qt.__binding__) + + def test_coexistence(): + """Qt.py may be use alongside the actual binding""" + + from Qt import QtCore + import PySide6.QtCore # Qt remaps QStringListModel assert QtCore.QStringListModel # But does not delete the original - assert PySide2.QtGui.QStringListModel + assert PySide6.QtCore.QStringListModel if binding("PyQt4") or binding("PyQt5"): From a3dffae5869cfba0d96a8953a795d42946b67db5 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 07:58:11 -0600 Subject: [PATCH 20/37] Updated _misplaced_members PySide6 and PySide2 --- Qt.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Qt.py b/Qt.py index ca86e77e..1b889866 100644 --- a/Qt.py +++ b/Qt.py @@ -935,7 +935,6 @@ def createWidget(self, class_name, parent=None, name=""): _misplaced_members = { "PySide6": { "QtGui.QShortcut": "QtWidgets.QShortcut", - "QtGui.QStringListModel": "QtCore.QStringListModel", "QtGui.QAction": "QtWidgets.QAction", "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], "shiboken6.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance], @@ -955,7 +954,6 @@ def createWidget(self, class_name, parent=None, name=""): "QtMultimedia.QSound": "QtMultimedia.QSound", }, "PySide2": { - "QtGui.QStringListModel": "QtCore.QStringListModel", "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], "shiboken2.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance], "shiboken2.getCppPointer": ["QtCompat.getCppPointer", _getcpppointer], From f8e4124a8cbef27d12a47e856f55d8af37927039 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 08:33:09 -0600 Subject: [PATCH 21/37] Reverting _misplaced_members QStringListModel as a test --- Qt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Qt.py b/Qt.py index 1b889866..6176000e 100644 --- a/Qt.py +++ b/Qt.py @@ -954,6 +954,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtMultimedia.QSound": "QtMultimedia.QSound", }, "PySide2": { + "QtGui.QStringListModel": "QtCore.QStringListModel", "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], "shiboken2.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance], "shiboken2.getCppPointer": ["QtCompat.getCppPointer", _getcpppointer], From 55a9c7bd043648b1552a8721d7064c860dee6f26 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 08:39:13 -0600 Subject: [PATCH 22/37] Reverting binding("PySide2") QStringListModel as a test --- tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests.py b/tests.py index 7ddfe234..0d4ba855 100644 --- a/tests.py +++ b/tests.py @@ -1356,13 +1356,13 @@ def test_coexistence(): """Qt.py may be use alongside the actual binding""" from Qt import QtCore - import PySide2.QtCore + import PySide2.QtGui # Qt remaps QStringListModel assert QtCore.QStringListModel # But does not delete the original - assert PySide2.QtCore.QStringListModel + assert PySide2.QtGui.QStringListModel if binding("PySide6"): From 0cea9152eb6af7fe0c583c22076fc676b8bbfe2e Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 08:44:19 -0600 Subject: [PATCH 23/37] Updated _common_members for PySide2 removed: ['QSslCertificate', 'QSslCipher', 'QSslConfiguration', 'QSslError', 'QSslKey', 'QSslSocket', 'QUuid'] --- Qt.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Qt.py b/Qt.py index 6176000e..26f6d383 100644 --- a/Qt.py +++ b/Qt.py @@ -167,7 +167,6 @@ "QTimerEvent", "QTranslator", "QUrl", - "QUuid", "QVariantAnimation", "QWaitCondition", "QWriteLocker", @@ -356,12 +355,6 @@ "QNetworkReply", "QNetworkRequest", "QSsl", - "QSslCertificate", - "QSslCipher", - "QSslConfiguration", - "QSslError", - "QSslKey", - "QSslSocket", "QTcpServer", "QTcpSocket", "QUdpSocket" From 7ca02247ebdb23d84c003b82ae24cdae429d1c2a Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 09:01:29 -0600 Subject: [PATCH 24/37] Updated _common_members for test_caveats.py --- Qt.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Qt.py b/Qt.py index 26f6d383..368c3027 100644 --- a/Qt.py +++ b/Qt.py @@ -111,6 +111,9 @@ "QFileSystemWatcher", "QGenericArgument", "QGenericReturnArgument", + "QItemSelection", + "QItemSelectionModel", + "QItemSelectionRange", "QIODevice", "QLibraryInfo", "QLine", @@ -194,7 +197,8 @@ "qUnregisterResourceData", "qVersion", "qWarning", - "Signal" + "Signal", + "Slot" ], "QtGui": [ "QAbstractTextDocumentLayout", @@ -267,6 +271,7 @@ "QQuaternion", "QRadialGradient", "QRegion", + "QRegExpValidator", "QResizeEvent", "QSessionManager", "QShortcutEvent", @@ -384,6 +389,7 @@ "QAbstractScrollArea", "QAbstractSlider", "QAbstractSpinBox", + "QAction", "QApplication", "QBoxLayout", "QButtonGroup", From af8af755216c53ac1b4645718268c96242a6a1c5 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 09:52:59 -0600 Subject: [PATCH 25/37] Update pyside6.yml - added Install EGL mesa step --- .github/workflows/pyside6.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 806ff056..6e8ce549 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -20,6 +20,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install EGL mesa + run: | + sudo apt-get update -y -qq + sudo apt-get install -y -qq libegl1-mesa libegl1-mesa-dev libgl1-mesa-glx libgl1-mesa-dev + - name: Pip install . run: | python3.10 -m pip install . From 73a6ba4308b9a295302b7cb160d03f7c5ae27834 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 10:03:43 -0600 Subject: [PATCH 26/37] Update pyside6.yml - Added Install GUI Libs step, Removed Install EGL mesa step --- .github/workflows/pyside6.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 6e8ce549..186dc976 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -20,10 +20,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Install EGL mesa + - name: Install GUI libs run: | - sudo apt-get update -y -qq - sudo apt-get install -y -qq libegl1-mesa libegl1-mesa-dev libgl1-mesa-glx libgl1-mesa-dev + sudo apt-get install -y -qq libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 + sudo apt-get install -y -qq libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libegl1 libglib2.0-0 l + sudo apt-get install -y -qq ibxkbcommon-x11-0 libdbus-1-3 libpulse0 libxcb-cursor0 libxcb-shape0 - name: Pip install . run: | From 42395b649f3d2c266507121332f986ba60f18040 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 10:07:51 -0600 Subject: [PATCH 27/37] Update pyside6.yml - Reverting back to Install EGL Mesa step, adding gui libs incrementally --- .github/workflows/pyside6.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 186dc976..a1f262d9 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -20,11 +20,14 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install EGL mesa + run: | + sudo apt-get update -y -qq + sudo apt-get install -y -qq libegl1-mesa libegl1-mesa-dev libgl1-mesa-glx libgl1-mesa-dev + - name: Install GUI libs run: | - sudo apt-get install -y -qq libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 - sudo apt-get install -y -qq libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libegl1 libglib2.0-0 l - sudo apt-get install -y -qq ibxkbcommon-x11-0 libdbus-1-3 libpulse0 libxcb-cursor0 libxcb-shape0 + sudo apt-get install -y -qq libxcb-cursor0 - name: Pip install . run: | From 5493aa00cd8c11bea29262702b8ac46fdce4c5ab Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 10:20:18 -0600 Subject: [PATCH 28/37] Update pyside6.yml - Updated Install GUI libs step --- .github/workflows/pyside6.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index a1f262d9..e8f281c6 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -27,7 +27,8 @@ jobs: - name: Install GUI libs run: | - sudo apt-get install -y -qq libxcb-cursor0 + sudo apt-get install -y -qq libxcb-xinerama0 + sudo apt-get install -y -qq libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xfixes0 libxcb-cursor0 - name: Pip install . run: | From 93ab974d763f3b7d77c0a0683b25943382ac27f9 Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 10:25:55 -0600 Subject: [PATCH 29/37] Update pyside6.yml - Testing QT_QPA_PLATFORM=minimal env variable --- .github/workflows/pyside6.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index e8f281c6..64666d13 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -14,6 +14,7 @@ jobs: env: QT_PREFERRED_BINDING: PySide6 + QT_QPA_PLATFORM: minimal PYTHONPATH: "${{ github.workspace }}" steps: From 7351971fe6a309bdb30d3e35676eef13a57eb0fa Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 5 Apr 2024 10:28:59 -0600 Subject: [PATCH 30/37] Update pyside6.yml - Added QT_VERBOSE=1 env variable --- .github/workflows/pyside6.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 64666d13..68906e4a 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -15,6 +15,7 @@ jobs: env: QT_PREFERRED_BINDING: PySide6 QT_QPA_PLATFORM: minimal + QT_VERBOSE: 1 PYTHONPATH: "${{ github.workspace }}" steps: From d65eaf95c987b79774177e05107bc095b0d0da39 Mon Sep 17 00:00:00 2001 From: zoshua Date: Sat, 6 Apr 2024 09:10:50 -0600 Subject: [PATCH 31/37] Updated _misplaced_members PySide6 added QRegularExpressionValidator remap --- Qt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Qt.py b/Qt.py index 368c3027..09e973ef 100644 --- a/Qt.py +++ b/Qt.py @@ -933,6 +933,7 @@ def createWidget(self, class_name, parent=None, name=""): """ _misplaced_members = { "PySide6": { + "QtGui.QRegularExpressionValidator": "QtGui.QRegExpValidator", "QtGui.QShortcut": "QtWidgets.QShortcut", "QtGui.QAction": "QtWidgets.QAction", "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], From fed48360d171774c3f72c506cf0384693366edcb Mon Sep 17 00:00:00 2001 From: zoshua Date: Sat, 6 Apr 2024 10:34:55 -0600 Subject: [PATCH 32/37] Updated test_vendoring() to include PySide6 in QT_PREFERRED_BINDING_JSON testing --- tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests.py b/tests.py index 0d4ba855..fef4ea51 100644 --- a/tests.py +++ b/tests.py @@ -815,7 +815,7 @@ def test_vendoring(): env = os.environ.copy() env["QT_PREFERRED_BINDING_JSON"] = json.dumps( { - "Qt": ["PyQt5", "PyQt4"], + "Qt": ["PySide6", "PyQt5", "PyQt4"], "default": ["None"] } ) @@ -828,7 +828,7 @@ def test_vendoring(): ) == 0 print("Testing QT_PREFERRED_BINDING_JSON and QT_PREFERRED_BINDING work..") - env["QT_PREFERRED_BINDING_JSON"] = '{"Qt":["PyQt5","PyQt4"]}' + env["QT_PREFERRED_BINDING_JSON"] = '{"Qt":["PySide6","PyQt5","PyQt4"]}' env["QT_PREFERRED_BINDING"] = "None" assert subprocess.call( [sys.executable, "-c", cmd], From c4b202d7e33b770887818d01155f1cd884c09351 Mon Sep 17 00:00:00 2001 From: zoshua Date: Sat, 6 Apr 2024 10:48:34 -0600 Subject: [PATCH 33/37] Updated pyside6.yml - Testing examples.. --- .github/workflows/pyside6.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 68906e4a..2a37934e 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -54,8 +54,6 @@ jobs: - name: Testing examples.. run: | - cd examples - python3.10 -m nose2 --verbose loadUi.baseinstance1 - python3.10 -m nose2 --verbose loadUi.baseinstance2 - python3.10 -m nose2 --verbose QtSiteConfig.main - cd .. + python3.10 -m nose2 --verbose examples.loadUi.baseinstance1 + python3.10 -m nose2 --verbose examples.loadUi.baseinstance2 + python3.10 -m nose2 --verbose examples.QtSiteConfig.main From e6edaa8903983469ba01c7346d25c5b57493151c Mon Sep 17 00:00:00 2001 From: zoshua Date: Sat, 6 Apr 2024 11:02:31 -0600 Subject: [PATCH 34/37] Added PySide6 to QT_PREFERRED_BINDING --- examples/loadUi/baseinstance1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/loadUi/baseinstance1.py b/examples/loadUi/baseinstance1.py index eac1643c..eb8e896b 100644 --- a/examples/loadUi/baseinstance1.py +++ b/examples/loadUi/baseinstance1.py @@ -2,7 +2,7 @@ import os # Set preferred binding -os.environ['QT_PREFERRED_BINDING'] = os.pathsep.join(['PySide', 'PyQt4']) +os.environ['QT_PREFERRED_BINDING'] = os.pathsep.join(['PySide', 'PyQt4', 'PySide6']) from Qt import QtWidgets, QtCompat From 3967fe46cd257002b8ec63378732798940d58a49 Mon Sep 17 00:00:00 2001 From: zoshua Date: Sat, 6 Apr 2024 11:19:24 -0600 Subject: [PATCH 35/37] added PySide6 to update_misplaced_members() and update_compatibility_members() --- examples/QtSiteConfig/QtSiteConfig.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/QtSiteConfig/QtSiteConfig.py b/examples/QtSiteConfig/QtSiteConfig.py index e70930e4..8c689e9c 100644 --- a/examples/QtSiteConfig/QtSiteConfig.py +++ b/examples/QtSiteConfig/QtSiteConfig.py @@ -22,6 +22,7 @@ def update_misplaced_members(members): members (dict): The members considered by Qt.py """ # Create Qt.QtGui.QColorTest that points to Qtgui.QColor for unit testing. + members["PySide6"]["QtGui.QColor"] = "QtGui.QColorTest" members["PySide2"]["QtGui.QColor"] = "QtGui.QColorTest" members["PyQt5"]["QtGui.QColor"] = "QtGui.QColorTest" members["PySide"]["QtGui.QColor"] = "QtGui.QColorTest" @@ -37,7 +38,7 @@ def update_compatibility_members(members): """ # Create a QtCompat.QWidget compatibility class. This example is # is used to provide a testable unittest - for binding in ("PySide2", "PyQt5", "PySide", "PyQt4"): + for binding in ("PySide6", "PySide2", "PyQt5", "PySide", "PyQt4"): members[binding]["QWidget"] = { # Simple remapping of QWidget.windowTitle "windowTitleTest": "QtWidgets.QWidget.windowTitle", From 66e379b13ba3904bf5f76901eb7f1c4a80636fa4 Mon Sep 17 00:00:00 2001 From: zoshua Date: Sun, 7 Apr 2024 10:11:46 -0600 Subject: [PATCH 36/37] Update pyside6.yml - Testing examples.. Step Removed python3.10 -m nose2 --verbose examples.loadUi.baseinstance2 --- .github/workflows/pyside6.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pyside6.yml b/.github/workflows/pyside6.yml index 2a37934e..0762d2b2 100644 --- a/.github/workflows/pyside6.yml +++ b/.github/workflows/pyside6.yml @@ -55,5 +55,4 @@ jobs: - name: Testing examples.. run: | python3.10 -m nose2 --verbose examples.loadUi.baseinstance1 - python3.10 -m nose2 --verbose examples.loadUi.baseinstance2 python3.10 -m nose2 --verbose examples.QtSiteConfig.main From 25e117d51c1f5c3e0268a765357021c122723bd4 Mon Sep 17 00:00:00 2001 From: zoshua Date: Wed, 1 May 2024 10:37:04 -0600 Subject: [PATCH 37/37] updated _compatibility_members - added QFont.setWeight, Qt.MidButton updated _pyside6() - added QtCompat.QFont.setWeight functionality updated _misplaced_members PySide2 to restore parity with current release. updated _misplaced_members PySide6 to be consistent with PySide2. --- Qt.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Qt.py b/Qt.py index 09e973ef..4aadc9ac 100644 --- a/Qt.py +++ b/Qt.py @@ -933,6 +933,16 @@ def createWidget(self, class_name, parent=None, name=""): """ _misplaced_members = { "PySide6": { + "QtCore.QStringListModel": "QtCore.QStringListModel", + "QtGui.QStringListModel": "QtCore.QStringListModel", + "QtCore.Property": "QtCore.Property", + "QtCore.Signal": "QtCore.Signal", + "QtCore.Slot": "QtCore.Slot", + "QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel", + "QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", + "QtCore.QItemSelection": "QtCore.QItemSelection", + "QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel", + "QtCore.QItemSelectionRange": "QtCore.QItemSelectionRange", "QtGui.QRegularExpressionValidator": "QtGui.QRegExpValidator", "QtGui.QShortcut": "QtWidgets.QShortcut", "QtGui.QAction": "QtWidgets.QAction", @@ -955,6 +965,15 @@ def createWidget(self, class_name, parent=None, name=""): }, "PySide2": { "QtGui.QStringListModel": "QtCore.QStringListModel", + "QtGui.QStringListModel": "QtCore.QStringListModel", + "QtCore.Property": "QtCore.Property", + "QtCore.Signal": "QtCore.Signal", + "QtCore.Slot": "QtCore.Slot", + "QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel", + "QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", + "QtCore.QItemSelection": "QtCore.QItemSelection", + "QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel", + "QtCore.QItemSelectionRange": "QtCore.QItemSelectionRange", "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], "shiboken2.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance], "shiboken2.getCppPointer": ["QtCompat.getCppPointer", _getcpppointer], @@ -1096,6 +1115,12 @@ def createWidget(self, class_name, parent=None, name=""): "getOpenFileNames": "QtWidgets.QFileDialog.getOpenFileNames", "getSaveFileName": "QtWidgets.QFileDialog.getSaveFileName", }, + "QFont":{ + "setWeight": "QtGui.QFont.setWeight", + }, + "Qt": { + "MidButton": "QtCore.Qt.MiddleButton", + }, }, "PySide2": { "QWidget": { @@ -1414,9 +1439,38 @@ def _pyside6(): if hasattr(Qt, "_QtWidgets"): Qt.QtCompat.setSectionResizeMode = \ Qt._QtWidgets.QHeaderView.setSectionResizeMode + + def setWeight(func): + def wrapper(self, weight): + weight = { + 100: Qt._QtGui.QFont.Thin, + 200: Qt._QtGui.QFont.ExtraLight, + 300: Qt._QtGui.QFont.Light, + 400: Qt._QtGui.QFont.Normal, + 500: Qt._QtGui.QFont.Medium, + 600: Qt._QtGui.QFont.DemiBold, + 700: Qt._QtGui.QFont.Bold, + 800: Qt._QtGui.QFont.ExtraBold, + 900: Qt._QtGui.QFont.Black, + }.get(weight, Qt._QtGui.QFont.Normal) + + return func(self, weight) + + wrapper.__doc__ = func.__doc__ + wrapper.__name__ = func.__name__ + + return wrapper + + + decorators = { + "QFont": { + "setWeight": setWeight, + } + } _reassign_misplaced_members("PySide6") _build_compatibility_members("PySide6") + _build_compatibility_members("PySide6", decorators) def _pyside2():