From d20a58c26bf741846abeb5a2f3498a57ff6c6a4f Mon Sep 17 00:00:00 2001 From: toofar Date: Thu, 25 Aug 2022 08:41:16 +1200 Subject: Some Qt6 mypy fixes I'm running mypy like so: mypy --always-true=USE_PYQT6 --always-false=USE_PYQT5 --always-false=USE_PYSIDE2 --always-false=USE_PYSIDE6 --always-false=IS_QT5 --always-true=IS_QT6 qutebrowser/ And I just went down the output fixing easy stuff. Currently I'm getting 61 errors on Qt5 and 207 errors on Qt6 (down from 230 or so). I think the comparison ignores I removed are still needed on Qt5. I'm not sure how best to deal with situations that need to be ignored on one implementation and not on another. One way to do it would be to have alternate implementations per backend, but that could become a bit or a maintenance burden, see https://github.com/python/mypy/issues/8823 I'm also seeing some "Statement is unreachable" errors popping up which might be due to the same scenario. Many of the errors are related to there being no webkit on Qt6 so the webkit modules get resolved as ANY which makes all the # type: ignore messages be complained about. Not sure what we can do about that, possibly something from https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-exclude I see that Phil said we shouldn't need separate stubs for PyQt6. I'm still using them and haven't tried without yet. --- qutebrowser/browser/network/pac.py | 4 ++-- qutebrowser/keyinput/keyutils.py | 12 +++++++----- qutebrowser/misc/earlyinit.py | 2 +- qutebrowser/misc/sql.py | 6 +++--- qutebrowser/qt/sip.py | 2 +- qutebrowser/utils/debug.py | 14 ++++++++++---- qutebrowser/utils/qtutils.py | 27 ++++++++++++++++++--------- qutebrowser/utils/usertypes.py | 4 ++-- qutebrowser/utils/utils.py | 8 ++++---- 9 files changed, 48 insertions(+), 31 deletions(-) diff --git a/qutebrowser/browser/network/pac.py b/qutebrowser/browser/network/pac.py index be25a2a41..cce6ea94e 100644 --- a/qutebrowser/browser/network/pac.py +++ b/qutebrowser/browser/network/pac.py @@ -219,8 +219,8 @@ class PACResolver: else: string_flags = QUrl.UrlFormattingOption.RemoveUserInfo # type: ignore[assignment] if query.url().scheme() == 'https': - string_flags |= QUrl.UrlFormattingOption.RemovePath # type: ignore[assignment] - string_flags |= QUrl.UrlFormattingOption.RemoveQuery # type: ignore[assignment] + string_flags |= QUrl.UrlFormattingOption.RemovePath + string_flags |= QUrl.UrlFormattingOption.RemoveQuery result = self._resolver.call([query.url().toString(string_flags), query.peerHostName()]) diff --git a/qutebrowser/keyinput/keyutils.py b/qutebrowser/keyinput/keyutils.py index f91936257..fdf5340f7 100644 --- a/qutebrowser/keyinput/keyutils.py +++ b/qutebrowser/keyinput/keyutils.py @@ -37,10 +37,11 @@ from typing import Iterator, List, Mapping, Optional, Union, overload from qutebrowser.qt.core import Qt, QEvent from qutebrowser.qt.gui import QKeySequence, QKeyEvent -try: - from qutebrowser.qt.core import QKeyCombination -except ImportError: +from qutebrowser.qt import machinery +if machinery.IS_QT5: QKeyCombination = None # Qt 6 only +else: + from qutebrowser.qt.core import QKeyCombination from qutebrowser.utils import utils, qtutils, debug @@ -69,7 +70,7 @@ try: except ValueError: # WORKAROUND for # https://www.riverbankcomputing.com/pipermail/pyqt/2022-April/044607.html - _NIL_KEY = 0 + _NIL_KEY = 0 # type: ignore[assignment] _ModifierType = Qt.KeyboardModifier @@ -541,6 +542,7 @@ class KeySequence: def __iter__(self) -> Iterator[KeyInfo]: """Iterate over KeyInfo objects.""" + combination: QKeySequence for combination in itertools.chain.from_iterable(self._sequences): yield KeyInfo.from_qt(combination) @@ -712,7 +714,7 @@ class KeySequence: mappings: Mapping['KeySequence', 'KeySequence'] ) -> 'KeySequence': """Get a new KeySequence with the given mappings applied.""" - infos = [] + infos: List[KeyInfo] = [] for info in self: key_seq = KeySequence(info) if key_seq in mappings: diff --git a/qutebrowser/misc/earlyinit.py b/qutebrowser/misc/earlyinit.py index 39db7b710..690578188 100644 --- a/qutebrowser/misc/earlyinit.py +++ b/qutebrowser/misc/earlyinit.py @@ -183,7 +183,7 @@ def check_qt_version(): try: from qutebrowser.qt.core import QVersionNumber, QLibraryInfo qt_ver = QLibraryInfo.version().normalized() - recent_qt_runtime = qt_ver >= QVersionNumber(5, 15) # type: ignore[operator] + recent_qt_runtime = qt_ver >= QVersionNumber(5, 15) except (ImportError, AttributeError): # QVersionNumber was added in Qt 5.6, QLibraryInfo.version() in 5.8 recent_qt_runtime = False diff --git a/qutebrowser/misc/sql.py b/qutebrowser/misc/sql.py index d7b3dda0d..4c182e351 100644 --- a/qutebrowser/misc/sql.py +++ b/qutebrowser/misc/sql.py @@ -28,7 +28,7 @@ from typing import Any, Dict, Iterator, List, Mapping, MutableSequence, Optional from qutebrowser.qt.core import QObject, pyqtSignal from qutebrowser.qt.sql import QSqlDatabase, QSqlError, QSqlQuery -from qutebrowser.qt import sip +from qutebrowser.qt import sip, machinery from qutebrowser.utils import debug, log @@ -323,10 +323,10 @@ class Query: def _validate_bound_values(self): """Make sure all placeholders are bound.""" qt_bound_values = self.query.boundValues() - try: + if machinery.IS_QT5: # Qt 5: Returns a dict values = qt_bound_values.values() - except AttributeError: + else: # Qt 6: Returns a list values = qt_bound_values diff --git a/qutebrowser/qt/sip.py b/qutebrowser/qt/sip.py index 07682f24e..e24ad4826 100644 --- a/qutebrowser/qt/sip.py +++ b/qutebrowser/qt/sip.py @@ -17,7 +17,7 @@ elif machinery.USE_PYQT6: try: from PyQt6.sip import * except ImportError: - from sip import * + from sip import * # type: ignore[import] elif machinery.USE_PYSIDE2: raise machinery.Unavailable() elif machinery.USE_PYSIDE6: diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py index ff6c3b9c2..f4f73dfc7 100644 --- a/qutebrowser/utils/debug.py +++ b/qutebrowser/utils/debug.py @@ -33,7 +33,7 @@ from qutebrowser.qt.core import Qt, QEvent, QMetaMethod, QObject, pyqtBoundSigna from qutebrowser.utils import log, utils, qtutils, objreg from qutebrowser.misc import objects -from qutebrowser.qt import sip +from qutebrowser.qt import sip, machinery def log_events(klass: Type[QObject]) -> Type[QObject]: @@ -99,7 +99,10 @@ def log_signals(obj: QObject) -> QObject: return obj -_EnumValueType = Union[sip.simplewrapper, int] +if machinery.IS_QT5: + _EnumValueType = Union[sip.simplewrapper, int] +else: + _EnumValueType = Union[sip.wrapper ,int] def _qenum_key_python( @@ -109,8 +112,10 @@ def _qenum_key_python( """New-style PyQt6: Try getting value from Python enum.""" if isinstance(value, enum.Enum) and value.name: return value.name + assert isinstance(value, int) # We got an int with klass passed: Try asking Python enum for member + assert klass if issubclass(klass, enum.Enum): try: name = klass(value).name @@ -131,7 +136,7 @@ def _qenum_key_qt( # However, not every Qt enum value has a staticMetaObject try: meta_obj = base.staticMetaObject # type: ignore[union-attr] - idx = meta_obj.indexOfEnumerator(klass.__name__) + idx = meta_obj.indexOfEnumerator(klass.__name__) # type: ignore[union-attr] meta_enum = meta_obj.enumerator(idx) key = meta_enum.valueToKey(int(value)) # type: ignore[arg-type] if key is not None: @@ -140,6 +145,7 @@ def _qenum_key_qt( pass # PyQt5: Try finding value match in class + assert klass for name, obj in vars(base).items(): if isinstance(obj, klass) and obj == value: return name @@ -222,7 +228,7 @@ def qflags_key(base: Type[_EnumValueType], for bit in bits: # We have to re-convert to an enum type here or we'll sometimes get an # empty string back. - enum_value = klass(bit) # type: ignore[call-arg] + enum_value = klass(bit) names.append(qenum_key(base, enum_value, klass)) return '|'.join(names) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 0bd9c94e8..66a4f679f 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -40,13 +40,14 @@ from qutebrowser.qt.core import (qVersion, QEventLoop, QDataStream, QByteArray, QIODevice, QFileDevice, QSaveFile, QT_VERSION_STR, PYQT_VERSION_STR, QObject, QUrl, QLibraryInfo) from qutebrowser.qt.gui import QColor +from qutebrowser.qt import machinery try: from qutebrowser.qt.webkit import qWebKitVersion except ImportError: # pragma: no cover qWebKitVersion = None # type: ignore[assignment] # noqa: N816 if TYPE_CHECKING: from qutebrowser.qt.webkit import QWebHistory - from qutebrowser.qt.webenginewidgets import QWebEngineHistory + from qutebrowser.qt.webenginecore import QWebEngineHistory from qutebrowser.misc import objects from qutebrowser.utils import usertypes, utils @@ -186,13 +187,21 @@ def check_qdatastream(stream: QDataStream) -> None: raise OSError(status_to_str[stream.status()]) -_QtSerializableType = Union[ - QObject, - QByteArray, - QUrl, - 'QWebEngineHistory', - 'QWebHistory' -] +if machinery.IS_QT5: + _QtSerializableType = Union[ + QObject, + QByteArray, + QUrl, + 'QWebEngineHistory', + 'QWebHistory' + ] +else: + _QtSerializableType = Union[ + QObject, + QByteArray, + QUrl, + 'QWebEngineHistory', + ] def serialize(obj: _QtSerializableType) -> QByteArray: @@ -581,7 +590,7 @@ class LibraryPath(enum.Enum): def library_path(which: LibraryPath) -> pathlib.Path: """Wrapper around QLibraryInfo.path / .location.""" - if hasattr(QLibraryInfo, "path"): + if machinery.IS_QT6: # Qt 6 val = getattr(QLibraryInfo.LibraryPath, which.value) ret = QLibraryInfo.path(val) diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py index b84af4524..aadda000b 100644 --- a/qutebrowser/utils/usertypes.py +++ b/qutebrowser/utils/usertypes.py @@ -491,7 +491,7 @@ class AbstractCertificateErrorWrapper: """A wrapper over an SSL/certificate error.""" def __init__(self) -> None: - self._certificate_accepted = None + self._certificate_accepted: Optional[bool] = None def __str__(self) -> str: raise NotImplementedError @@ -514,7 +514,7 @@ class AbstractCertificateErrorWrapper: def defer(self) -> None: raise NotImplementedError - def certificate_was_accepted(self) -> None: + def certificate_was_accepted(self) -> bool: """Check whether the certificate was accepted by the user.""" if not self.is_overridable(): return False diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py index 29c4be1d9..0817d4c56 100644 --- a/qutebrowser/utils/utils.py +++ b/qutebrowser/utils/utils.py @@ -138,16 +138,16 @@ class VersionNumber: return self._ver != other._ver def __ge__(self, other: 'VersionNumber') -> bool: - return self._ver >= other._ver # type: ignore[operator] + return self._ver >= other._ver def __gt__(self, other: 'VersionNumber') -> bool: - return self._ver > other._ver # type: ignore[operator] + return self._ver > other._ver def __le__(self, other: 'VersionNumber') -> bool: - return self._ver <= other._ver # type: ignore[operator] + return self._ver <= other._ver def __lt__(self, other: 'VersionNumber') -> bool: - return self._ver < other._ver # type: ignore[operator] + return self._ver < other._ver class Unreachable(Exception): -- cgit v1.2.3-54-g00ecf