From d8a725360a65c09da2ad6b4b74b8bd6fec8a24ac Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 13 Oct 2022 19:44:05 -0400 Subject: [PATCH 1/2] Pin all Qt bindings for minimum version CI --- .github/workflows/tests.yml | 9 ++++++--- lib/matplotlib/backends/qt_compat.py | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fd6eac7ce279..020f09df4010 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,6 +37,9 @@ jobs: python-version: 3.8 extra-requirements: '-c requirements/testing/minver.txt' pyqt5-ver: '==5.11.2 sip==5.0.0' # oldest versions with a Py3.8 wheel. + pyqt6-ver: '==6.1.0 PyQt6-Qt6==6.1.0' + pyside2-ver: '==5.14.0' # oldest version with working Py3.8 wheel. + pyside6-ver: '==6.0.0' delete-font-cache: true - os: ubuntu-20.04 python-version: 3.8 @@ -189,17 +192,17 @@ jobs: echo 'PyQt5 is available' || echo 'PyQt5 is not available' if [[ "${{ runner.os }}" != 'macOS' ]]; then - python -mpip install --upgrade pyside2 && + python -mpip install --upgrade pyside2${{ matrix.pyside2-ver }} && python -c 'import PySide2.QtCore' && echo 'PySide2 is available' || echo 'PySide2 is not available' fi if [[ "${{ matrix.os }}" = ubuntu-20.04 ]]; then - python -mpip install --upgrade pyqt6 && + python -mpip install --upgrade pyqt6${{ matrix.pyqt6-ver }} && python -c 'import PyQt6.QtCore' && echo 'PyQt6 is available' || echo 'PyQt6 is not available' - python -mpip install --upgrade pyside6 && + python -mpip install --upgrade pyside6${{ matrix.pyside6-ver }} && python -c 'import PySide6.QtCore' && echo 'PySide6 is available' || echo 'PySide6 is not available' diff --git a/lib/matplotlib/backends/qt_compat.py b/lib/matplotlib/backends/qt_compat.py index 6d1fc2f9ad2c..af83abf783af 100644 --- a/lib/matplotlib/backends/qt_compat.py +++ b/lib/matplotlib/backends/qt_compat.py @@ -92,7 +92,10 @@ def _isdeleted(obj): return not shiboken6.isValid(obj) _isdeleted = sip.isdeleted elif QT_API == QT_API_PYSIDE2: from PySide2 import QtCore, QtGui, QtWidgets, __version__ - import shiboken2 + try: + from PySide2 import shiboken2 + except ImportError: + import shiboken2 def _isdeleted(obj): return not shiboken2.isValid(obj) else: From 7a3ab3012ea6747a14e818c337e8f07a86af72ac Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 14 Oct 2022 01:12:39 -0400 Subject: [PATCH 2/2] Fix compatibility with PySide6 6.4.0 --- lib/matplotlib/backends/qt_compat.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/qt_compat.py b/lib/matplotlib/backends/qt_compat.py index af83abf783af..06db924feea3 100644 --- a/lib/matplotlib/backends/qt_compat.py +++ b/lib/matplotlib/backends/qt_compat.py @@ -69,7 +69,8 @@ def _setup_pyqt5plus(): - global QtCore, QtGui, QtWidgets, __version__, _isdeleted, _getSaveFileName + global QtCore, QtGui, QtWidgets, __version__ + global _getSaveFileName, _isdeleted, _to_int if QT_API == QT_API_PYQT6: from PyQt6 import QtCore, QtGui, QtWidgets, sip @@ -78,10 +79,15 @@ def _setup_pyqt5plus(): QtCore.Slot = QtCore.pyqtSlot QtCore.Property = QtCore.pyqtProperty _isdeleted = sip.isdeleted + _to_int = operator.attrgetter('value') elif QT_API == QT_API_PYSIDE6: from PySide6 import QtCore, QtGui, QtWidgets, __version__ import shiboken6 def _isdeleted(obj): return not shiboken6.isValid(obj) + if parse_version(__version__) >= parse_version('6.4'): + _to_int = operator.attrgetter('value') + else: + _to_int = int elif QT_API == QT_API_PYQT5: from PyQt5 import QtCore, QtGui, QtWidgets import sip @@ -90,6 +96,7 @@ def _isdeleted(obj): return not shiboken6.isValid(obj) QtCore.Slot = QtCore.pyqtSlot QtCore.Property = QtCore.pyqtProperty _isdeleted = sip.isdeleted + _to_int = int elif QT_API == QT_API_PYSIDE2: from PySide2 import QtCore, QtGui, QtWidgets, __version__ try: @@ -98,6 +105,7 @@ def _isdeleted(obj): return not shiboken6.isValid(obj) import shiboken2 def _isdeleted(obj): return not shiboken2.isValid(obj) + _to_int = int else: raise AssertionError(f"Unexpected QT_API: {QT_API}") _getSaveFileName = QtWidgets.QFileDialog.getSaveFileName @@ -144,9 +152,6 @@ def _isdeleted(obj): # PyQt6 enum compat helpers. -_to_int = operator.attrgetter("value") if QT_API == "PyQt6" else int - - @functools.lru_cache(None) def _enum(name): # foo.bar.Enum.Entry (PyQt6) <=> foo.bar.Entry (non-PyQt6).