diff options
Diffstat (limited to 'qutebrowser/utils')
-rw-r--r-- | qutebrowser/utils/debug.py | 1 | ||||
-rw-r--r-- | qutebrowser/utils/log.py | 18 | ||||
-rw-r--r-- | qutebrowser/utils/qtutils.py | 65 | ||||
-rw-r--r-- | qutebrowser/utils/standarddir.py | 4 | ||||
-rw-r--r-- | qutebrowser/utils/urlutils.py | 6 | ||||
-rw-r--r-- | qutebrowser/utils/utils.py | 13 | ||||
-rw-r--r-- | qutebrowser/utils/version.py | 7 |
7 files changed, 98 insertions, 16 deletions
diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py index a8b436d79..82de30702 100644 --- a/qutebrowser/utils/debug.py +++ b/qutebrowser/utils/debug.py @@ -68,6 +68,7 @@ def log_signals(obj: QObject) -> QObject: def connect_log_slot(obj: QObject) -> None: """Helper function to connect all signals to a logging slot.""" metaobj = obj.metaObject() + assert metaobj is not None for i in range(metaobj.methodCount()): meta_method = metaobj.method(i) qtutils.ensure_valid(meta_method) diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py index 521f52b5b..5ac150702 100644 --- a/qutebrowser/utils/log.py +++ b/qutebrowser/utils/log.py @@ -31,9 +31,10 @@ import json import inspect import argparse from typing import (TYPE_CHECKING, Any, Iterator, Mapping, MutableSequence, - Optional, Set, Tuple, Union, TextIO, Literal, cast) + Optional, Set, Tuple, Union, TextIO, Literal, cast, Callable) from qutebrowser.qt import core as qtcore +from qutebrowser.qt import machinery # Optional imports try: import colorama @@ -234,6 +235,19 @@ def _init_py_warnings() -> None: def disable_qt_msghandler() -> Iterator[None]: """Contextmanager which temporarily disables the Qt message handler.""" old_handler = qtcore.qInstallMessageHandler(None) + if machinery.IS_QT6: + # cast str to Optional[str] to be compatible with PyQt6 type hints for + # qInstallMessageHandler + old_handler = cast( + Optional[ + Callable[ + [qtcore.QtMsgType, qtcore.QMessageLogContext, Optional[str]], + None + ] + ], + old_handler, + ) + try: yield finally: @@ -379,7 +393,7 @@ def change_console_formatter(level: int) -> None: def qt_message_handler(msg_type: qtcore.QtMsgType, context: qtcore.QMessageLogContext, - msg: str) -> None: + msg: Optional[str]) -> None: """Qt message handler to redirect qWarning etc. to the logging system. Args: diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index cc34057ef..781e43f08 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -32,7 +32,7 @@ import pathlib import operator import contextlib from typing import (Any, AnyStr, TYPE_CHECKING, BinaryIO, IO, Iterator, - Optional, Union, Tuple, Protocol, cast) + Optional, Union, Tuple, Protocol, cast, TypeVar) from qutebrowser.qt import machinery, sip from qutebrowser.qt.core import (qVersion, QEventLoop, QDataStream, QByteArray, @@ -46,6 +46,7 @@ except ImportError: # pragma: no cover if TYPE_CHECKING: from qutebrowser.qt.webkit import QWebHistory from qutebrowser.qt.webenginecore import QWebEngineHistory + from typing_extensions import TypeGuard # added in Python 3.10 from qutebrowser.misc import objects from qutebrowser.utils import usertypes, utils @@ -102,7 +103,11 @@ def version_check(version: str, parsed = utils.VersionNumber.parse(version) op = operator.eq if exact else operator.ge - result = op(utils.VersionNumber.parse(qVersion()), parsed) + + qversion = qVersion() + assert qversion is not None + result = op(utils.VersionNumber.parse(qversion), parsed) + if compiled and result: # qVersion() ==/>= parsed, now check if QT_VERSION_STR ==/>= parsed. result = op(utils.VersionNumber.parse(QT_VERSION_STR), parsed) @@ -535,24 +540,58 @@ def interpolate_color( if colorspace is None: if percent == 100: - return QColor(*end.getRgb()) + r, g, b, a = end.getRgb() + assert r is not None + assert g is not None + assert b is not None + assert a is not None + return QColor(r, g, b, a) else: - return QColor(*start.getRgb()) + r, g, b, a = start.getRgb() + assert r is not None + assert g is not None + assert b is not None + assert a is not None + return QColor(r, g, b, a) out = QColor() if colorspace == QColor.Spec.Rgb: r1, g1, b1, a1 = start.getRgb() r2, g2, b2, a2 = end.getRgb() + assert r1 is not None + assert g1 is not None + assert b1 is not None + assert a1 is not None + assert r2 is not None + assert g2 is not None + assert b2 is not None + assert a2 is not None components = _get_color_percentage(r1, g1, b1, a1, r2, g2, b2, a2, percent) out.setRgb(*components) elif colorspace == QColor.Spec.Hsv: h1, s1, v1, a1 = start.getHsv() h2, s2, v2, a2 = end.getHsv() + assert h1 is not None + assert s1 is not None + assert v1 is not None + assert a1 is not None + assert h2 is not None + assert s2 is not None + assert v2 is not None + assert a2 is not None components = _get_color_percentage(h1, s1, v1, a1, h2, s2, v2, a2, percent) out.setHsv(*components) elif colorspace == QColor.Spec.Hsl: h1, s1, l1, a1 = start.getHsl() h2, s2, l2, a2 = end.getHsl() + assert h1 is not None + assert s1 is not None + assert l1 is not None + assert a1 is not None + assert h2 is not None + assert s2 is not None + assert l2 is not None + assert a2 is not None components = _get_color_percentage(h1, s1, l1, a1, h2, s2, l2, a2, percent) out.setHsl(*components) else: @@ -611,3 +650,21 @@ def extract_enum_val(val: Union[sip.simplewrapper, int, enum.Enum]) -> int: elif isinstance(val, sip.simplewrapper): return int(val) # type: ignore[call-overload] return val + +T = TypeVar("T") + +def is_not_none(obj: Optional[T]) -> "TypeGuard[T]": + """Check if a Qt object is None. + + PyQt6 marks things as Optional[...], but PyQt5 doesn't. + By using this function, we can use the same type hints for both. + """ + return obj is not None + + +if machinery.IS_QT5: + def allow_none(obj: Optional[T]) -> T: + return cast(T, obj) +else: + def allow_none(obj: Optional[T]) -> Optional[T]: + return obj diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py index 884a26376..762125c11 100644 --- a/qutebrowser/utils/standarddir.py +++ b/qutebrowser/utils/standarddir.py @@ -28,7 +28,7 @@ from typing import Iterator, Optional from qutebrowser.qt.core import QStandardPaths from qutebrowser.qt.widgets import QApplication -from qutebrowser.utils import log, debug, utils, version +from qutebrowser.utils import log, debug, utils, version, qtutils # The cached locations _locations = {} @@ -65,7 +65,7 @@ def _unset_organization() -> Iterator[None]: qapp = QApplication.instance() if qapp is not None: orgname = qapp.organizationName() - qapp.setOrganizationName(None) # type: ignore[arg-type] + qapp.setOrganizationName(qtutils.allow_none(None)) try: yield finally: diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py index e00c9dab2..b3f03b256 100644 --- a/qutebrowser/utils/urlutils.py +++ b/qutebrowser/utils/urlutils.py @@ -179,9 +179,9 @@ def _get_search_url(txt: str) -> QUrl: url = QUrl.fromUserInput(evaluated) else: url = QUrl.fromUserInput(config.val.url.searchengines[engine]) - url.setPath(None) # type: ignore[arg-type] - url.setFragment(None) # type: ignore[arg-type] - url.setQuery(None) # type: ignore[call-overload] + url.setPath(qtutils.allow_none(None)) + url.setFragment(qtutils.allow_none(None)) + url.setQuery(qtutils.allow_none(None)) qtutils.ensure_valid(url) return url diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py index 6b450aa29..dd3cf6ac3 100644 --- a/qutebrowser/utils/utils.py +++ b/qutebrowser/utils/utils.py @@ -519,6 +519,13 @@ def sanitize_filename(name: str, return name +def _clipboard() -> QClipboard: + """Get the QClipboard and make sure it's not None.""" + clipboard = QApplication.clipboard() + assert clipboard is not None + return clipboard + + def set_clipboard(data: str, selection: bool = False) -> None: """Set the clipboard to some given data.""" global fake_clipboard @@ -530,7 +537,7 @@ def set_clipboard(data: str, selection: bool = False) -> None: fake_clipboard = data else: mode = QClipboard.Mode.Selection if selection else QClipboard.Mode.Clipboard - QApplication.clipboard().setText(data, mode=mode) + _clipboard().setText(data, mode=mode) def get_clipboard(selection: bool = False, fallback: bool = False) -> str: @@ -556,7 +563,7 @@ def get_clipboard(selection: bool = False, fallback: bool = False) -> str: fake_clipboard = None else: mode = QClipboard.Mode.Selection if selection else QClipboard.Mode.Clipboard - data = QApplication.clipboard().text(mode=mode) + data = _clipboard().text(mode=mode) target = "Primary selection" if selection else "Clipboard" if not data.strip(): @@ -568,7 +575,7 @@ def get_clipboard(selection: bool = False, fallback: bool = False) -> str: def supports_selection() -> bool: """Check if the OS supports primary selection.""" - return QApplication.clipboard().supportsSelection() + return _clipboard().supportsSelection() def open_file(filename: str, cmdline: str = None) -> None: diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py index 782261745..358e8e19b 100644 --- a/qutebrowser/utils/version.py +++ b/qutebrowser/utils/version.py @@ -886,7 +886,10 @@ def version_info() -> str: if objects.qapp: style = objects.qapp.style() - lines.append('Style: {}'.format(style.metaObject().className())) + assert style is not None + metaobj = style.metaObject() + assert metaobj is not None + lines.append('Style: {}'.format(metaobj.className())) lines.append('Platform plugin: {}'.format(objects.qapp.platformName())) lines.append('OpenGL: {}'.format(opengl_info())) @@ -1005,7 +1008,7 @@ def opengl_info() -> Optional[OpenGLInfo]: # pragma: no cover vendor, version = override.split(', ', maxsplit=1) return OpenGLInfo.parse(vendor=vendor, version=version) - old_context = cast(Optional[QOpenGLContext], QOpenGLContext.currentContext()) + old_context: Optional[QOpenGLContext] = QOpenGLContext.currentContext() old_surface = None if old_context is None else old_context.surface() surface = QOffscreenSurface() |