From dfcefaebe351413f264c5b661e2131b3ed32f897 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 7 Oct 2021 15:36:50 +1000 Subject: [PATCH] miscellaneous pyqt6 compat fixes - add a few gates for qt5-specific behaviour - prepare for some changes to the typings in qt6 - map pickled Qt5 ByteArrays to Qt6 when running Qt6 --- qt/aqt/__init__.py | 2 -- qt/aqt/main.py | 2 +- qt/aqt/profiles.py | 41 ++++++++++++++++++++++++----------------- qt/aqt/qt.py | 7 +++++-- qt/aqt/qt5.py | 6 +++++- qt/aqt/switch.py | 3 ++- qt/aqt/tagedit.py | 2 +- qt/aqt/utils.py | 6 ++++-- qt/aqt/webview.py | 4 ++-- 9 files changed, 44 insertions(+), 29 deletions(-) diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index 4e29129ac..f910bbc1f 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -372,8 +372,6 @@ def setupGL(pm: aqt.profiles.ProfileManager) -> None: category = "debug" elif category == QtFatalMsg: category = "fatal" - elif category == QtSystemMsg: - category = "system" else: category = "unknown" context = "" diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 344186cc1..967819ff8 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1032,7 +1032,7 @@ title="{}" {}>{}""".format( def clearStateShortcuts(self) -> None: for qs in self.stateShortcuts: - sip.delete(qs) + sip.delete(qs) # type: ignore self.stateShortcuts = [] def onStudyKey(self) -> None: diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index 0016db4e1..3832dca5f 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -163,25 +163,32 @@ class ProfileManager: def _unpickle(self, data: bytes) -> Any: class Unpickler(pickle.Unpickler): - def find_class(self, module: str, name: str) -> Any: - if module == "PyQt5.sip": - try: - import PyQt5.sip # pylint: disable=unused-import - except: - # use old sip location - module = "sip" - fn = super().find_class(module, name) - if module == "sip" and name == "_unpickle_type": + def find_class(self, class_module: str, name: str) -> Any: + # handle sip lookup ourselves, mapping to current Qt version + if class_module == "sip" or class_module.endswith(".sip"): - def wrapper(mod, obj, args) -> Any: # type: ignore - if mod.startswith("PyQt4") and obj == "QByteArray": - # can't trust str objects from python 2 - return QByteArray() - return fn(mod, obj, args) + def unpickle_type(module: str, klass: str, args: Any) -> Any: + if qtmajor > 5: + module = module.replace("Qt5", "Qt6") + else: + module = module.replace("Qt6", "Qt5") + if klass == "QByteArray": + if module.startswith("PyQt4"): + # can't trust str objects from python 2 + return QByteArray() + else: + # return the bytes directly + return args[0] + elif name == "_unpickle_enum": + if qtmajor == 5: + return sip._unpickle_enum(module, klass, args) # type: ignore + else: + # old style enums can't be unpickled + return None + else: + return sip._unpickle_type(module, klass, args) # type: ignore - return wrapper - else: - return fn + return unpickle_type up = Unpickler(io.BytesIO(data), errors="ignore") return up.load() diff --git a/qt/aqt/qt.py b/qt/aqt/qt.py index 46cf9f6e7..1d53b9fcf 100644 --- a/qt/aqt/qt.py +++ b/qt/aqt/qt.py @@ -57,6 +57,9 @@ if qtmajor < 5 or (qtmajor == 5 and qtminor < 14): raise Exception("Anki does not support your Qt version.") -def qconnect(signal: Union[Callable, pyqtSignal], func: Callable) -> None: - "Helper to work around type checking not working with signal.connect(func)." +def qconnect( + signal: Union[Callable, pyqtSignal, pyqtBoundSignal], func: Callable +) -> None: + """Helper to work around type checking not working with signal.connect(func). + Not needed in PyQt6""" signal.connect(func) # type: ignore diff --git a/qt/aqt/qt5.py b/qt/aqt/qt5.py index 8cdf3aa72..401c1fc1a 100644 --- a/qt/aqt/qt5.py +++ b/qt/aqt/qt5.py @@ -23,7 +23,11 @@ class QtAudioInputRecorder(Recorder): self.mw = mw self._parent = parent - from PyQt5.QtMultimedia import QAudioDeviceInfo, QAudioFormat, QAudioInput + from PyQt5.QtMultimedia import ( # type: ignore + QAudioDeviceInfo, + QAudioFormat, + QAudioInput, + ) format = QAudioFormat() format.setChannelCount(1) diff --git a/qt/aqt/switch.py b/qt/aqt/switch.py index bc97b44fd..f9ad05343 100644 --- a/qt/aqt/switch.py +++ b/qt/aqt/switch.py @@ -1,5 +1,6 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +from typing import cast from aqt import colors from aqt.qt import * @@ -128,7 +129,7 @@ class Switch(QAbstractButton): self._animate_toggle() def _animate_toggle(self) -> None: - animation = QPropertyAnimation(self, b"position", self) + animation = QPropertyAnimation(self, cast(QByteArray, b"position"), self) animation.setDuration(100) animation.setStartValue(self.start_position) animation.setEndValue(self.end_position) diff --git a/qt/aqt/tagedit.py b/qt/aqt/tagedit.py index b616b1737..69c31d320 100644 --- a/qt/aqt/tagedit.py +++ b/qt/aqt/tagedit.py @@ -99,7 +99,7 @@ class TagEdit(QLineEdit): self._completer.popup().hide() def hideCompleter(self) -> None: - if sip.isdeleted(self._completer): + if sip.isdeleted(self._completer): # type: ignore return self._completer.popup().hide() diff --git a/qt/aqt/utils.py b/qt/aqt/utils.py index e4b80f594..1aa282820 100644 --- a/qt/aqt/utils.py +++ b/qt/aqt/utils.py @@ -866,6 +866,8 @@ Add-ons, last update check: {} # adapted from version detection in qutebrowser def opengl_vendor() -> str | None: + if qtmajor != 5: + return "unknown" old_context = QOpenGLContext.currentContext() old_surface = None if old_context is None else old_context.surface() @@ -886,11 +888,11 @@ def opengl_vendor() -> str | None: # Can't use versionFunctions there return None - vp = QOpenGLVersionProfile() + vp = QOpenGLVersionProfile() # type: ignore vp.setVersion(2, 0) try: - vf = ctx.versionFunctions(vp) + vf = ctx.versionFunctions(vp) # type: ignore except ImportError as e: return None diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index a05e4d1ba..9b7399489 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -350,9 +350,9 @@ class AnkiWebView(QWebEngineView): if webscale: return float(webscale) - if isMac: + if qtmajor > 5 or isMac: return 1 - screen = QApplication.desktop().screen() + screen = QApplication.desktop().screen() # type: ignore if screen is None: return 1