This commit is contained in:
killiandesse 2026-01-07 10:56:52 +01:00 committed by GitHub
commit d2005563e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
97 changed files with 484 additions and 532 deletions

View File

@ -35,7 +35,7 @@ Possible values:
import inspect
from typing import Any, Protocol, Optional, cast
from typing import Any, Protocol, cast
from collections.abc import Iterable, Callable
from qutebrowser.utils import qtutils
@ -102,7 +102,7 @@ class _CmdHandlerType(Protocol):
Below, we cast the decorated function to _CmdHandlerType to make mypy aware of this.
"""
qute_args: Optional[dict[str, 'command.ArgInfo']]
qute_args: dict[str, 'command.ArgInfo'] | None
def __call__(self, *args: Any, **kwargs: Any) -> Any:
...

View File

@ -29,7 +29,6 @@ import tempfile
import pathlib
import datetime
import argparse
from typing import Optional
from collections.abc import Iterable
from qutebrowser.qt import machinery
@ -234,7 +233,7 @@ def process_pos_args(args, via_ipc=False, cwd=None, target_arg=None):
if command_target in {'window', 'private-window'}:
command_target = 'tab-silent'
window: Optional[mainwindow.MainWindow] = None
window: mainwindow.MainWindow | None = None
if via_ipc and (not args or args == ['']):
window = mainwindow.get_window(via_ipc=via_ipc, target=new_window_target)
@ -296,7 +295,7 @@ def open_url(url, target=None, no_raise=False, via_ipc=True):
return window
def _open_startpage(window: Optional[mainwindow.MainWindow] = None) -> None:
def _open_startpage(window: mainwindow.MainWindow | None = None) -> None:
"""Open startpage.
The startpage is never opened if the given windows are not empty.

View File

@ -9,7 +9,7 @@ import pathlib
import itertools
import functools
import dataclasses
from typing import (cast, TYPE_CHECKING, Any, Optional, Union)
from typing import (cast, TYPE_CHECKING, Any, Optional, Union, TypeAlias)
from collections.abc import Iterable, Sequence, Callable
from qutebrowser.qt import machinery
@ -42,7 +42,7 @@ if TYPE_CHECKING:
tab_id_gen = itertools.count(0)
_WidgetType = Union["WebView", "WebEngineView"]
_WidgetType: TypeAlias = Union["WebView", "WebEngineView"]
def create(win_id: int,
@ -125,13 +125,13 @@ class TabData:
viewing_source: bool = False
inspector: Optional['AbstractWebInspector'] = None
open_target: usertypes.ClickTarget = usertypes.ClickTarget.normal
override_target: Optional[usertypes.ClickTarget] = None
override_target: usertypes.ClickTarget | None = None
pinned: bool = False
fullscreen: bool = False
netrc_used: bool = False
input_mode: usertypes.KeyMode = usertypes.KeyMode.normal
last_navigation: Optional[usertypes.NavigationRequest] = None
splitter: Optional[miscwidgets.InspectorSplitter] = None
last_navigation: usertypes.NavigationRequest | None = None
splitter: miscwidgets.InspectorSplitter | None = None
def should_show_icon(self) -> bool:
return (config.val.tabs.favicons.show == 'always' or
@ -225,7 +225,7 @@ class AbstractPrinting(QObject):
super().__init__(parent)
self._widget = cast(_WidgetType, None)
self._tab = tab
self._dialog: Optional[QPrintDialog] = None
self._dialog: QPrintDialog | None = None
self.printing_finished.connect(self._on_printing_finished)
self.pdf_printing_finished.connect(self._on_pdf_printing_finished)
@ -373,7 +373,7 @@ class AbstractSearch(QObject):
super().__init__(parent)
self._tab = tab
self._widget = cast(_WidgetType, None)
self.text: Optional[str] = None
self.text: str | None = None
self.search_displayed = False
self.match = SearchMatch()
@ -878,7 +878,7 @@ class AbstractTabPrivate:
self._tab = tab
self._mode_manager = mode_manager
def event_target(self) -> Optional[QWidget]:
def event_target(self) -> QWidget | None:
"""Return the widget events should be sent to."""
raise NotImplementedError
@ -913,7 +913,7 @@ class AbstractTabPrivate:
def clear_ssl_errors(self) -> None:
raise NotImplementedError
def networkaccessmanager(self) -> Optional[QNetworkAccessManager]:
def networkaccessmanager(self) -> QNetworkAccessManager | None:
"""Get the QNetworkAccessManager for this tab.
This is only implemented for QtWebKit.
@ -943,7 +943,7 @@ class AbstractTabPrivate:
self._tab.data.inspector = None
self.toggle_inspector(inspector.Position.window)
def toggle_inspector(self, position: Optional[inspector.Position]) -> None:
def toggle_inspector(self, position: inspector.Position | None) -> None:
"""Show/hide (and if needed, create) the web inspector for this tab."""
tabdata = self._tab.data
if tabdata.inspector is None:
@ -1056,7 +1056,7 @@ class AbstractTab(QWidget):
self._load_status = usertypes.LoadStatus.none
self._tab_event_filter = eventfilter.TabEventFilter(
self, parent=self)
self.backend: Optional[usertypes.Backend] = None
self.backend: usertypes.Backend | None = None
# If true, this tab has been requested to be removed (or is removed).
self.pending_removal = False
@ -1270,7 +1270,7 @@ class AbstractTab(QWidget):
self,
code: str,
callback: Callable[[Any], None] = None, *,
world: Union[usertypes.JsWorld, int] = None
world: usertypes.JsWorld | int = None
) -> None:
"""Run javascript async.
@ -1298,7 +1298,7 @@ class AbstractTab(QWidget):
self.data.pinned = pinned
self.pinned_changed.emit(pinned)
def renderer_process_pid(self) -> Optional[int]:
def renderer_process_pid(self) -> int | None:
"""Get the PID of the underlying renderer process.
Returns None if the PID can't be determined or if getting the PID isn't
@ -1306,7 +1306,7 @@ class AbstractTab(QWidget):
"""
raise NotImplementedError
def grab_pixmap(self, rect: QRect = None) -> Optional[QPixmap]:
def grab_pixmap(self, rect: QRect = None) -> QPixmap | None:
"""Grab a QPixmap of the displayed page.
Returns None if we got a null pixmap from Qt.

View File

@ -9,7 +9,7 @@
import os.path
import shlex
import functools
from typing import cast, Union, Optional
from typing import cast
from collections.abc import Callable
from qutebrowser.qt.widgets import QApplication, QTabBar
@ -105,7 +105,7 @@ class CommandDispatcher:
background: bool = False,
window: bool = False,
related: bool = False,
private: Optional[bool] = None,
private: bool | None = None,
) -> None:
"""Helper function to open a page.
@ -511,10 +511,10 @@ class CommandDispatcher:
tab: bool,
bg: bool,
window: bool,
count: Optional[int],
count: int | None,
forward: bool,
quiet: bool,
index: Optional[int],
index: int | None,
) -> None:
"""Helper function for :back/:forward."""
history = self._current_widget().history
@ -975,7 +975,7 @@ class CommandDispatcher:
@cmdutils.argument('index', choices=['last', 'stack-next', 'stack-prev'],
completion=miscmodels.tab_focus)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_focus(self, index: Union[str, int] = None,
def tab_focus(self, index: str | int = None,
count: int = None, no_last: bool = False) -> None:
"""Select the tab given as argument/[count].
@ -1022,7 +1022,7 @@ class CommandDispatcher:
@cmdutils.register(instance="command-dispatcher", scope="window")
@cmdutils.argument("index", choices=["+", "-", "start", "end"])
@cmdutils.argument("count", value=cmdutils.Value.count)
def tab_move(self, index: Union[str, int] = None, count: int = None) -> None:
def tab_move(self, index: str | int = None, count: int = None) -> None:
"""Move the current tab according to the argument and [count].
If neither is given, move it to the first position.
@ -1702,7 +1702,7 @@ class CommandDispatcher:
url: bool = False,
quiet: bool = False,
*,
world: Union[usertypes.JsWorld, int] = None) -> None:
world: usertypes.JsWorld | int = None) -> None:
"""Evaluate a JavaScript string.
Args:

View File

@ -13,7 +13,7 @@ import functools
import pathlib
import tempfile
import enum
from typing import Any, IO, Optional, Union
from typing import Any, IO
from collections.abc import MutableSequence
from qutebrowser.qt.core import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
@ -35,7 +35,7 @@ class ModelRole(enum.IntEnum):
# Remember the last used directory
last_used_directory: Optional[str] = None
last_used_directory: str | None = None
# All REFRESH_INTERVAL milliseconds, speeds will be recalculated and downloads
# redrawn.
@ -221,7 +221,7 @@ def suggested_fn_from_title(url_path, title=None):
ext_whitelist = [".html", ".htm", ".php", ""]
_, ext = os.path.splitext(url_path)
suggested_fn: Optional[str] = None
suggested_fn: str | None = None
if ext.lower() in ext_whitelist and title:
suggested_fn = utils.sanitize_filename(title, shorten=True)
if not suggested_fn.lower().endswith((".html", ".htm")):
@ -451,14 +451,10 @@ class AbstractDownloadItem(QObject):
self.basename = '???'
self.successful = False
self.fileobj: Union[
UnsupportedAttribute, IO[bytes], None
] = UnsupportedAttribute()
self.raw_headers: Union[
UnsupportedAttribute, dict[bytes, bytes]
] = UnsupportedAttribute()
self.fileobj: UnsupportedAttribute | IO[bytes] | None = UnsupportedAttribute()
self.raw_headers: UnsupportedAttribute | dict[bytes, bytes] = UnsupportedAttribute()
self._filename: Optional[str] = None
self._filename: str | None = None
self._dead = False
def __repr__(self):

View File

@ -5,7 +5,6 @@
"""The ListView to display downloads in."""
import functools
from typing import Union
from collections.abc import MutableSequence, Callable
from qutebrowser.qt.core import pyqtSlot, QSize, Qt
@ -17,10 +16,7 @@ from qutebrowser.utils import qtutils, utils
_ActionListType = MutableSequence[
Union[
tuple[None, None], # separator
tuple[str, Callable[[], None]],
]
tuple[None, None] | tuple[str, Callable[[], None]]
]
@ -67,7 +63,7 @@ class DownloadView(QListView):
def __repr__(self):
model = qtutils.add_optional(self.model())
count: Union[int, str]
count: int | str
if model is None:
count = 'None'
else:

View File

@ -12,7 +12,7 @@ import functools
import glob
import textwrap
import dataclasses
from typing import cast, Optional
from typing import cast
from collections.abc import Sequence
from qutebrowser.qt.core import pyqtSignal, QObject, QUrl
@ -232,7 +232,7 @@ class LoadResults:
names = '\n'.join(str(script) for script in sorted(self.successful, key=str))
return f"Loaded Greasemonkey scripts:\n\n{names}"
def error_str(self) -> Optional[str]:
def error_str(self) -> str | None:
"""Get a string with all errors during script loading.
This can be used e.g. for a message.error() call.

View File

@ -12,7 +12,7 @@ import html
import enum
import dataclasses
from string import ascii_lowercase
from typing import (TYPE_CHECKING, Optional)
from typing import TYPE_CHECKING
from collections.abc import (
Iterable,
Iterator,
@ -187,9 +187,9 @@ class HintContext:
all_labels: list[HintLabel] = dataclasses.field(default_factory=list)
labels: dict[str, HintLabel] = dataclasses.field(default_factory=dict)
to_follow: Optional[str] = None
to_follow: str | None = None
first_run: bool = True
filterstr: Optional[str] = None
filterstr: str | None = None
def get_args(self, urlstr: str) -> Sequence[str]:
"""Get the arguments, with {hint-url} replaced by the given URL."""
@ -394,7 +394,7 @@ class HintManager(QObject):
"""Constructor."""
super().__init__(parent)
self._win_id = win_id
self._context: Optional[HintContext] = None
self._context: HintContext | None = None
self._word_hinter = WordHinter()
self._actions = HintActions(win_id)
@ -587,7 +587,7 @@ class HintManager(QObject):
raise cmdutils.CommandError(
"'args' is only allowed with target userscript/spawn.")
def _filter_matches(self, filterstr: Optional[str], elemstr: str) -> bool:
def _filter_matches(self, filterstr: str | None, elemstr: str) -> bool:
"""Return True if `filterstr` matches `elemstr`."""
# Empty string and None always match
if not filterstr:
@ -783,7 +783,7 @@ class HintManager(QObject):
error_cb=lambda err: message.error(str(err)),
only_visible=True)
def _get_hint_mode(self, mode: Optional[str]) -> str:
def _get_hint_mode(self, mode: str | None) -> str:
"""Get the hinting mode to use based on a mode argument."""
if mode is None:
return config.val.hints.mode
@ -795,7 +795,7 @@ class HintManager(QObject):
raise cmdutils.CommandError("Invalid mode: {}".format(e))
return mode
def current_mode(self) -> Optional[str]:
def current_mode(self) -> str | None:
"""Return the currently active hinting mode (or None otherwise)."""
if self._context is None:
return None
@ -868,7 +868,7 @@ class HintManager(QObject):
pass
self._handle_auto_follow(keystr=keystr)
def filter_hints(self, filterstr: Optional[str]) -> None:
def filter_hints(self, filterstr: str | None) -> None:
"""Filter displayed hints according to a text.
Args:
@ -1127,7 +1127,7 @@ class WordHinter:
def new_hint_for(self, elem: webelem.AbstractWebElement,
existing: Iterable[str],
fallback: Iterable[str]) -> Optional[str]:
fallback: Iterable[str]) -> str | None:
"""Return a hint for elem, not conflicting with the existing."""
new = self.tag_words_to_hints(self.extract_tag_words(elem))
new_no_prefixes = self.filter_prefixes(new, existing)

View File

@ -8,7 +8,7 @@ import os
import time
import contextlib
import pathlib
from typing import cast, Optional
from typing import cast
from collections.abc import Mapping, MutableSequence
from qutebrowser.qt import machinery
@ -86,7 +86,7 @@ class CompletionMetaInfo(sql.SqlTable):
}
def __init__(self, database: sql.Database,
parent: Optional[QObject] = None) -> None:
parent: QObject | None = None) -> None:
self._fields = ['key', 'value']
self._constraints = {'key': 'PRIMARY KEY'}
super().__init__(database, "CompletionMetaInfo", self._fields,
@ -134,7 +134,7 @@ class CompletionHistory(sql.SqlTable):
"""History which only has the newest entry for each URL."""
def __init__(self, database: sql.Database,
parent: Optional[QObject] = None) -> None:
parent: QObject | None = None) -> None:
super().__init__(database, "CompletionHistory", ['url', 'title', 'last_atime'],
constraints={'url': 'PRIMARY KEY',
'title': 'NOT NULL',
@ -159,7 +159,7 @@ class WebHistory(sql.SqlTable):
url_cleared = pyqtSignal(QUrl)
def __init__(self, database: sql.Database, progress: HistoryProgress,
parent: Optional[QObject] = None) -> None:
parent: QObject | None = None) -> None:
super().__init__(database, "History", ['url', 'title', 'atime', 'redirect'],
constraints={'url': 'NOT NULL',
'title': 'NOT NULL',
@ -472,7 +472,7 @@ def debug_dump_history(dest):
raise cmdutils.CommandError(f'Could not write history: {e}')
def init(db_path: pathlib.Path, parent: Optional[QObject] = None) -> None:
def init(db_path: pathlib.Path, parent: QObject | None = None) -> None:
"""Initialize the web history.
Args:

View File

@ -7,7 +7,7 @@
import base64
import binascii
import enum
from typing import cast, Optional, Any
from typing import cast, Any
from qutebrowser.qt.widgets import QWidget
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, QEvent
@ -57,7 +57,7 @@ class _EventFilter(QObject):
clicked = pyqtSignal()
def eventFilter(self, _obj: Optional[QObject], event: Optional[QEvent]) -> bool:
def eventFilter(self, _obj: QObject | None, event: QEvent | None) -> bool:
"""Translate mouse presses to a clicked signal."""
assert event is not None
if event.type() == QEvent.Type.MouseButtonPress:
@ -86,7 +86,7 @@ class AbstractWebInspector(QWidget):
self._widget = cast(_WidgetType, None)
self._layout = miscwidgets.WrapperLayout(self)
self._splitter = splitter
self._position: Optional[Position] = None
self._position: Position | None = None
self._win_id = win_id
self._event_filter = _EventFilter(parent=self)
@ -128,7 +128,7 @@ class AbstractWebInspector(QWidget):
modeman.enter(self._win_id, usertypes.KeyMode.insert,
reason='Inspector clicked', only_if_normal=True)
def set_position(self, position: Optional[Position]) -> None:
def set_position(self, position: Position | None) -> None:
"""Set the position of the inspector.
If the position is None, the last known position is used.
@ -183,7 +183,7 @@ class AbstractWebInspector(QWidget):
if not ok:
log.init.warning("Error while loading geometry.")
def closeEvent(self, _e: Optional[QCloseEvent]) -> None:
def closeEvent(self, _e: QCloseEvent | None) -> None:
"""Save the geometry when closed."""
data = self._widget.saveGeometry().data()
geom = base64.b64encode(data).decode('ASCII')

View File

@ -6,7 +6,6 @@
import re
import posixpath
from typing import Optional
from qutebrowser.qt.core import QUrl
@ -79,7 +78,7 @@ def incdec(url, count, inc_or_dec):
inc_or_dec: Either 'increment' or 'decrement'.
"""
urlutils.ensure_valid(url)
segments: Optional[set[str]] = (
segments: set[str] | None = (
set(config.val.url.incdec_segments)
)

View File

@ -6,7 +6,7 @@
import sys
import functools
from typing import Optional, cast
from typing import cast
from qutebrowser.qt import machinery
from qutebrowser.qt.core import QObject, pyqtSignal, pyqtSlot, QUrl
@ -248,7 +248,7 @@ class PACFetcher(QObject):
with qtlog.disable_qt_msghandler():
# WORKAROUND for a hang when messages are printed, see our
# NetworkAccessManager subclass for details.
self._manager: Optional[QNetworkAccessManager] = QNetworkAccessManager()
self._manager: QNetworkAccessManager | None = QNetworkAccessManager()
self._manager.setProxy(QNetworkProxy(QNetworkProxy.ProxyType.NoProxy))
self._pac = None
self._error_message = None

View File

@ -9,7 +9,7 @@ import os.path
import shutil
import functools
import dataclasses
from typing import IO, Optional
from typing import IO
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, QTimer, QUrl
from qutebrowser.qt.widgets import QApplication
@ -72,7 +72,7 @@ class DownloadItem(downloads.AbstractDownloadItem):
reply: The QNetworkReply to download.
"""
super().__init__(manager=manager, parent=manager)
self.fileobj: Optional[IO[bytes]] = None
self.fileobj: IO[bytes] | None = None
self.raw_headers: dict[bytes, bytes] = {}
self._autoclose = True

View File

@ -18,7 +18,7 @@ import textwrap
import urllib
import collections
import secrets
from typing import TypeVar, Optional, Union
from typing import TypeVar
from collections.abc import Sequence, Callable
from qutebrowser.qt.core import QUrlQuery, QUrl
@ -33,7 +33,7 @@ from qutebrowser.qt import sip
pyeval_output = ":pyeval was never called"
csrf_token: Optional[str] = None
csrf_token: str | None = None
_HANDLERS: dict[str, "_HandlerCallable"] = {}
@ -78,7 +78,7 @@ class Redirect(Exception):
# Return value: (mimetype, data) (encoded as utf-8 if a str is returned)
_HandlerRet = tuple[str, Union[str, bytes]]
_HandlerRet = tuple[str, str | bytes]
_HandlerCallable = Callable[[QUrl], _HandlerRet]
_Handler = TypeVar('_Handler', bound=_HandlerCallable)
@ -93,7 +93,7 @@ class add_handler: # noqa: N801,N806 pylint: disable=invalid-name
def __init__(self, name: str) -> None:
self._name = name
self._function: Optional[_HandlerCallable] = None
self._function: _HandlerCallable | None = None
def __call__(self, function: _Handler) -> _Handler:
self._function = function
@ -201,7 +201,7 @@ def qute_tabs(_url: QUrl) -> _HandlerRet:
def history_data(
start_time: float,
offset: int = None
) -> Sequence[dict[str, Union[str, int]]]:
) -> Sequence[dict[str, str | int]]:
"""Return history data.
Arguments:
@ -349,7 +349,7 @@ def qute_gpl(_url: QUrl) -> _HandlerRet:
return 'text/html', resources.read_file('html/license.html')
def _asciidoc_fallback_path(html_path: str) -> Optional[str]:
def _asciidoc_fallback_path(html_path: str) -> str | None:
"""Fall back to plaintext asciidoc if the HTML is unavailable."""
path = html_path.replace('.html', '.asciidoc')
try:

View File

@ -10,7 +10,6 @@ import html
import enum
import netrc
import tempfile
from typing import Optional
from collections.abc import Mapping, Iterable, Iterator, Callable
from qutebrowser.qt.core import QUrl, pyqtBoundSignal
@ -513,7 +512,7 @@ def choose_file(qb_mode: FileSelectionMode) -> list[str]:
def _execute_fileselect_command(
command: list[str],
qb_mode: FileSelectionMode,
tmpfilename: Optional[str] = None
tmpfilename: str | None = None
) -> list[str]:
"""Execute external command to choose file.

View File

@ -4,7 +4,7 @@
"""Generic web element related code."""
from typing import Optional, TYPE_CHECKING, Union
from typing import TYPE_CHECKING, TypeAlias
from collections.abc import Iterator
import collections.abc
@ -20,12 +20,12 @@ if TYPE_CHECKING:
from qutebrowser.browser import browsertab
JsValueType = Union[int, float, str, None]
JsValueType: TypeAlias = int | float | str | None
if machinery.IS_QT6:
KeyboardModifierType = Qt.KeyboardModifier
else:
KeyboardModifierType = Union[Qt.KeyboardModifiers, Qt.KeyboardModifier]
KeyboardModifierType: TypeAlias = Qt.KeyboardModifiers | Qt.KeyboardModifier
class Error(Exception):
@ -81,7 +81,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a
def __repr__(self) -> str:
try:
html: Optional[str] = utils.compact_text(self.outer_xml(), 500)
html: str | None = utils.compact_text(self.outer_xml(), 500)
except Error:
html = None
return utils.get_repr(self, html=html)
@ -273,7 +273,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a
"""Remove target from link."""
raise NotImplementedError
def resolve_url(self, baseurl: QUrl) -> Optional[QUrl]:
def resolve_url(self, baseurl: QUrl) -> QUrl | None:
"""Resolve the URL in the element's src/href attribute.
Args:

View File

@ -125,7 +125,7 @@ import copy
import enum
import dataclasses
import collections
from typing import (Any, Optional, Union)
from typing import (Any, TypeAlias)
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
from qutebrowser.config import config
@ -205,14 +205,14 @@ class _Setting:
option: str
chromium_key: str
mapping: Optional[Mapping[Any, Union[str, int, None]]] = None
mapping: Mapping[Any, str | int | None] | None = None
def _value_str(self, value: Any) -> str:
if self.mapping is None:
return str(value)
return str(self.mapping[value])
def chromium_tuple(self, value: Any) -> Optional[tuple[str, str]]:
def chromium_tuple(self, value: Any) -> tuple[str, str] | None:
"""Get the Chromium key and value, or None if no value should be set."""
if self.mapping is not None and self.mapping[value] is None:
return None
@ -244,7 +244,7 @@ class _Definition:
*args: _Setting,
mandatory: set[str],
prefix: str,
switch_names: Mapping[Optional[str], str] = None,
switch_names: Mapping[str | None, str] = None,
) -> None:
self._settings = args
self.mandatory = mandatory
@ -340,7 +340,7 @@ _DEFINITIONS[Variant.qt_66] = _DEFINITIONS[Variant.qt_64].copy_add_setting(
_DEFINITIONS[Variant.qt_67] = _DEFINITIONS[Variant.qt_66].copy_remove_setting('enabled')
_SettingValType = Union[str, usertypes.Unset]
_SettingValType: TypeAlias = str | usertypes.Unset
_PREFERRED_COLOR_SCHEME_DEFINITIONS: MutableMapping[Variant, Mapping[_SettingValType, str]] = {
Variant.qt_515_2: {
# 0: no-preference (not exposed)

View File

@ -154,7 +154,7 @@ class AbstractNotificationAdapter(QObject):
self,
qt_notification: "QWebEngineNotification",
*,
replaces_id: Optional[int],
replaces_id: int | None,
) -> int:
"""Show the given notification.
@ -197,7 +197,7 @@ class NotificationBridgePresenter(QObject):
super().__init__(parent)
self._active_notifications: dict[int, 'QWebEngineNotification'] = {}
self._adapter: Optional[AbstractNotificationAdapter] = None
self._adapter: AbstractNotificationAdapter | None = None
config.instance.changed.connect(self._init_adapter)
@ -300,7 +300,7 @@ class NotificationBridgePresenter(QObject):
def _find_replaces_id(
self,
new_notification: "QWebEngineNotification",
) -> Optional[int]:
) -> int | None:
"""Find an existing notification to replace.
If no notification should be replaced or the notification to be replaced was not
@ -441,7 +441,7 @@ class SystrayNotificationAdapter(AbstractNotificationAdapter):
self,
qt_notification: "QWebEngineNotification",
*,
replaces_id: Optional[int],
replaces_id: int | None,
) -> int:
utils.unused(replaces_id) # QSystemTray can only show one message
self.close_id.emit(self.NOTIFICATION_ID)
@ -503,7 +503,7 @@ class MessagesNotificationAdapter(AbstractNotificationAdapter):
self,
qt_notification: "QWebEngineNotification",
*,
replaces_id: Optional[int],
replaces_id: int | None,
) -> int:
markup = self._format_message(qt_notification)
new_id = replaces_id if replaces_id is not None else next(self._id_gen)
@ -563,7 +563,7 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter):
self,
qt_notification: "QWebEngineNotification",
*,
replaces_id: Optional[int],
replaces_id: int | None,
) -> int:
if replaces_id is not None:
self.on_web_closed(replaces_id)
@ -647,11 +647,11 @@ class _ServerQuirks:
"""Quirks for certain DBus notification servers."""
spec_version: Optional[str] = None
spec_version: str | None = None
avoid_actions: bool = False
avoid_body_hyperlinks: bool = False
escape_title: bool = False
icon_key: Optional[str] = None
icon_key: str | None = None
skip_capabilities: bool = False
wrong_replaces_id: bool = False
no_padded_images: bool = False
@ -778,7 +778,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
name: str,
vendor: str,
ver: str,
) -> Optional[_ServerQuirks]:
) -> _ServerQuirks | None:
"""Find quirks to use based on the server information."""
if (name, vendor) == ("notify-osd", "Canonical Ltd"):
# Shows a dialog box instead of a notification bubble as soon as a
@ -1009,7 +1009,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
self,
qt_notification: "QWebEngineNotification",
*,
replaces_id: Optional[int],
replaces_id: int | None,
) -> int:
"""Shows a notification over DBus."""
if replaces_id is None:
@ -1045,7 +1045,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
self._verify_notification_id(notification_id, replaces_id=replaces_id)
return notification_id
def _convert_image(self, qimage: QImage) -> Optional[QDBusArgument]:
def _convert_image(self, qimage: QImage) -> QDBusArgument | None:
"""Convert a QImage to the structure DBus expects.
https://specifications.freedesktop.org/notification-spec/latest/ar01s05.html#icons-and-images-formats

View File

@ -5,7 +5,7 @@
"""QtWebEngine specific part of the web element API."""
from typing import (
TYPE_CHECKING, Any, Optional, Union)
TYPE_CHECKING, Any)
from collections.abc import Iterator, Callable
from qutebrowser.qt.core import QRect, QEventLoop
@ -29,7 +29,7 @@ class WebEngineElement(webelem.AbstractWebElement):
tab: 'webenginetab.WebEngineTab') -> None:
super().__init__(tab)
# Do some sanity checks on the data we get from JS
js_dict_types: dict[str, Union[type, tuple[type, ...]]] = {
js_dict_types: dict[str, type | tuple[type, ...]] = {
'id': int,
'text': str,
'value': (str, int, float),
@ -138,7 +138,7 @@ class WebEngineElement(webelem.AbstractWebElement):
composed: bool = False) -> None:
self._js_call('dispatch_event', event, bubbles, cancelable, composed)
def caret_position(self) -> Optional[int]:
def caret_position(self) -> int | None:
"""Get the text caret position for the current element.
If the element is not a text element, None is returned.

View File

@ -4,7 +4,6 @@
"""Customized QWebInspector for QtWebEngine."""
from typing import Optional
from qutebrowser.qt import machinery
from qutebrowser.qt.webenginewidgets import QWebEngineView
@ -61,7 +60,7 @@ class WebEngineInspector(inspector.AbstractWebInspector):
parent: QWidget = None) -> None:
super().__init__(splitter, win_id, parent)
self._check_devtools_resources()
self._settings: Optional[webenginesettings.WebEngineSettings] = None
self._settings: webenginesettings.WebEngineSettings | None = None
def _on_window_close_requested(self) -> None:
"""Called when the 'x' was clicked in the devtools."""

View File

@ -12,7 +12,7 @@ Module attributes:
import os
import operator
import pathlib
from typing import cast, Any, Optional, Union, TYPE_CHECKING
from typing import cast, Any, TYPE_CHECKING
from qutebrowser.qt import machinery
from qutebrowser.qt.gui import QFont
@ -33,11 +33,11 @@ if TYPE_CHECKING:
# The default QWebEngineProfile
default_profile = cast(QWebEngineProfile, None)
# The QWebEngineProfile used for private (off-the-record) windows
private_profile: Optional[QWebEngineProfile] = None
private_profile: QWebEngineProfile | None = None
# The global WebEngineSettings object
_global_settings = cast('WebEngineSettings', None)
parsed_user_agent: Optional[websettings.UserAgent] = None
parsed_user_agent: websettings.UserAgent | None = None
_qute_scheme_handler = cast(webenginequtescheme.QuteSchemeHandler, None)
_req_interceptor = cast('interceptor.RequestInterceptor', None)
@ -223,7 +223,7 @@ class WebEngineSettings(websettings.AbstractSettings):
}
def set_unknown_url_scheme_policy(
self, policy: Union[str, usertypes.Unset]) -> None:
self, policy: str | usertypes.Unset) -> None:
"""Set the UnknownUrlSchemePolicy to use."""
if isinstance(policy, usertypes.Unset):
self._settings.resetUnknownUrlSchemePolicy()
@ -231,7 +231,7 @@ class WebEngineSettings(websettings.AbstractSettings):
new_value = self._UNKNOWN_URL_SCHEME_POLICY[policy]
self._settings.setUnknownUrlSchemePolicy(new_value)
def _set_js_clipboard(self, value: Union[str, usertypes.Unset]) -> None:
def _set_js_clipboard(self, value: str | usertypes.Unset) -> None:
attr_access = QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard
attr_paste = QWebEngineSettings.WebAttribute.JavascriptCanPaste

View File

@ -10,7 +10,7 @@ import functools
import dataclasses
import re
import html as html_utils
from typing import cast, Union, Optional
from typing import cast, TypeAlias
from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, Qt, QPoint, QPointF, QUrl,
QObject, QByteArray, QTimer)
@ -92,7 +92,7 @@ class WebEnginePrinting(browsertab.AbstractPrinting):
if machinery.IS_QT5:
_FindFlagType = Union[QWebEnginePage.FindFlag, QWebEnginePage.FindFlags]
_FindFlagType: TypeAlias = QWebEnginePage.FindFlag | QWebEnginePage.FindFlags
else:
_FindFlagType = QWebEnginePage.FindFlag
@ -1023,7 +1023,7 @@ class _Quirk:
QWebEngineScript.InjectionPoint.DocumentCreation)
world: QWebEngineScript.ScriptWorldId = QWebEngineScript.ScriptWorldId.MainWorld
predicate: bool = True
name: Optional[str] = None
name: str | None = None
def __post_init__(self):
if self.name is None:
@ -1379,7 +1379,7 @@ class WebEngineTab(browsertab.AbstractTab):
log.misc.debug("run_js_async called on deleted tab")
return
world_id_type = Union[QWebEngineScript.ScriptWorldId, int]
world_id_type: TypeAlias = QWebEngineScript.ScriptWorldId | int
if world is None:
world_id: world_id_type = QWebEngineScript.ScriptWorldId.ApplicationWorld
elif isinstance(world, int):

View File

@ -5,7 +5,6 @@
"""The main browser widget for QtWebEngine."""
import mimetypes
from typing import Optional
from collections.abc import Iterable
from qutebrowser.qt import machinery
@ -314,8 +313,8 @@ class WebEnginePage(QWebEnginePage):
def chooseFiles(
self,
mode: QWebEnginePage.FileSelectionMode,
old_files: Iterable[Optional[str]],
accepted_mimetypes: Iterable[Optional[str]],
old_files: Iterable[str | None],
accepted_mimetypes: Iterable[str | None],
) -> list[str]:
"""Override chooseFiles to (optionally) invoke custom file uploader."""
accepted_mimetypes_filtered = [m for m in accepted_mimetypes if m is not None]

View File

@ -4,7 +4,6 @@
"""A wrapper over a list of QSslErrors."""
from typing import Optional
from collections.abc import Sequence
from qutebrowser.qt.network import QSslError, QNetworkReply
@ -21,7 +20,7 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper):
self._reply = reply
self._errors = tuple(errors) # needs to be hashable
try:
self._host_tpl: Optional[urlutils.HostTupleType] = urlutils.host_tuple(reply.url())
self._host_tpl: urlutils.HostTupleType | None = urlutils.host_tuple(reply.url())
except ValueError:
self._host_tpl = None

View File

@ -7,7 +7,7 @@
import collections
import html
import dataclasses
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING
from collections.abc import MutableMapping
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, QUrl, QByteArray
@ -246,7 +246,7 @@ class NetworkManager(QNetworkAccessManager):
errors = certificateerror.CertificateErrorWrapper(reply, qt_errors)
log.network.debug("Certificate errors: {!r}".format(errors))
try:
host_tpl: Optional[urlutils.HostTupleType] = urlutils.host_tuple(
host_tpl: urlutils.HostTupleType | None = urlutils.host_tuple(
reply.url())
except ValueError:
host_tpl = None

View File

@ -167,13 +167,13 @@ class WebKitElement(webelem.AbstractWebElement):
def _parent(self) -> Optional['WebKitElement']:
"""Get the parent element of this element."""
self._check_vanished()
elem = cast(Optional[QWebElement], self._elem.parent())
elem = cast(QWebElement | None, self._elem.parent())
if elem is None or elem.isNull():
return None
return WebKitElement(elem, tab=self._tab)
def _rect_on_view_js(self) -> Optional[QRect]:
def _rect_on_view_js(self) -> QRect | None:
"""Javascript implementation for rect_on_view."""
# FIXME:qtwebengine maybe we can reuse this?
rects = self._elem.evaluateJavaScript("this.getClientRects()")
@ -203,7 +203,7 @@ class WebKitElement(webelem.AbstractWebElement):
rect = QRect(int(rect["left"]), int(rect["top"]),
int(width), int(height))
frame = cast(Optional[QWebFrame], self._elem.webFrame())
frame = cast(QWebFrame | None, self._elem.webFrame())
while frame is not None:
# Translate to parent frames' position (scroll position
# is taken care of inside getClientRects)
@ -214,7 +214,7 @@ class WebKitElement(webelem.AbstractWebElement):
return None
def _rect_on_view_python(self, elem_geometry: Optional[QRect]) -> QRect:
def _rect_on_view_python(self, elem_geometry: QRect | None) -> QRect:
"""Python implementation for rect_on_view."""
if elem_geometry is None:
geometry = self._elem.geometry()
@ -222,11 +222,11 @@ class WebKitElement(webelem.AbstractWebElement):
geometry = elem_geometry
rect = QRect(geometry)
frame = cast(Optional[QWebFrame], self._elem.webFrame())
frame = cast(QWebFrame | None, self._elem.webFrame())
while frame is not None:
rect.translate(frame.geometry().topLeft())
rect.translate(frame.scrollPosition() * -1)
frame = cast(Optional[QWebFrame], frame.parentFrame())
frame = cast(QWebFrame | None, frame.parentFrame())
return rect
@ -320,7 +320,7 @@ class WebKitElement(webelem.AbstractWebElement):
return all([visible_on_screen, visible_in_frame])
def remove_blank_target(self) -> None:
elem: Optional[WebKitElement] = self
elem: WebKitElement | None = self
for _ in range(5):
if elem is None:
break

View File

@ -7,7 +7,7 @@
import re
import functools
import xml.etree.ElementTree
from typing import cast, Optional
from typing import cast
from collections.abc import Iterable
from qutebrowser.qt.core import pyqtSlot, Qt, QUrl, QPoint, QTimer, QSizeF, QSize
@ -760,7 +760,7 @@ class WebKitElements(browsertab.AbstractElements):
self.find_css('#' + elem_id, find_id_cb, error_cb=lambda exc: None)
def find_focused(self, callback):
frame = cast(Optional[QWebFrame], self._widget.page().currentFrame())
frame = cast(QWebFrame | None, self._widget.page().currentFrame())
if frame is None:
callback(None)
return
@ -774,7 +774,7 @@ class WebKitElements(browsertab.AbstractElements):
def find_at_pos(self, pos, callback):
assert pos.x() >= 0
assert pos.y() >= 0
frame = cast(Optional[QWebFrame], self._widget.page().frameAt(pos))
frame = cast(QWebFrame | None, self._widget.page().frameAt(pos))
if frame is None:
# This happens when we click inside the webview, but not actually
# on the QWebPage - for example when clicking the scrollbar
@ -930,7 +930,7 @@ class WebKitTab(browsertab.AbstractTab):
def title(self):
return self._widget.title()
def renderer_process_pid(self) -> Optional[int]:
def renderer_process_pid(self) -> int | None:
return None
@pyqtSlot()

View File

@ -9,7 +9,7 @@ import collections
import traceback
import typing
import dataclasses
from typing import (Any, Union, Optional)
from typing import (Any, Union)
from collections.abc import MutableMapping, MutableSequence, Callable
from qutebrowser.api import cmdutils
@ -25,12 +25,12 @@ class ArgInfo:
"""Information about an argument."""
value: Optional[usertypes.CommandValue] = None
value: usertypes.CommandValue | None = None
hide: bool = False
metavar: Optional[str] = None
flag: Optional[str] = None
completion: Optional[Callable[..., completionmodel.CompletionModel]] = None
choices: Optional[list[str]] = None
metavar: str | None = None
flag: str | None = None
completion: Callable[..., completionmodel.CompletionModel] | None = None
choices: list[str] | None = None
class Command:

View File

@ -8,7 +8,7 @@ Defines a CompletionView which uses CompletionFilterModel and CompletionModel
subclasses to provide completions.
"""
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING
from qutebrowser.qt.widgets import QTreeView, QSizePolicy, QStyleFactory, QWidget
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize
@ -101,7 +101,7 @@ class CompletionView(QTreeView):
win_id: int,
parent: QWidget = None) -> None:
super().__init__(parent)
self.pattern: Optional[str] = None
self.pattern: str | None = None
self._win_id = win_id
self._cmd = cmd
self._active = False

View File

@ -4,7 +4,6 @@
"""Models for the command completion."""
from typing import Optional
from collections.abc import Sequence
from qutebrowser.completion.models.util import DeleteFuncType
from qutebrowser.qt.core import QAbstractItemModel
@ -21,4 +20,4 @@ class BaseCategory(QAbstractItemModel):
name: str
columns_to_filter: Sequence[int]
delete_func: Optional[DeleteFuncType] = None
delete_func: DeleteFuncType | None = None

View File

@ -4,7 +4,7 @@
"""A model that proxies access to one or more completion categories."""
from typing import overload, Optional, Any
from typing import overload, Any
from collections.abc import MutableSequence
from qutebrowser.qt import machinery
@ -39,7 +39,7 @@ class CompletionModel(QAbstractItemModel):
self.column_widths = column_widths
self._categories: MutableSequence[BaseCategory] = []
def _cat_from_idx(self, index: QModelIndex) -> Optional[BaseCategory]:
def _cat_from_idx(self, index: QModelIndex) -> BaseCategory | None:
"""Return the category pointed to by the given index.
Args:
@ -128,7 +128,7 @@ class CompletionModel(QAbstractItemModel):
else:
@overload
def parent(self) -> Optional[QObject]:
def parent(self) -> QObject | None:
...
def parent(self, index=None):

View File

@ -14,7 +14,6 @@ is harder to achieve via pathlib.
import glob
import os
import os.path
from typing import Optional
from collections.abc import Iterable
from qutebrowser.qt.core import QAbstractListModel, QModelIndex, QObject, Qt, QUrl
@ -87,7 +86,7 @@ class FilePathCategory(QAbstractListModel, BaseCategory):
paths = self._glob(expanded)
self._paths = sorted(self._contract_user(val, path) for path in paths)
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> Optional[str]:
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> str | None:
"""Implement abstract method in QAbstractListModel."""
if role == Qt.ItemDataRole.DisplayRole and index.column() == 0:
return self._paths[index.row()]

View File

@ -4,7 +4,6 @@
"""A completion category that queries the SQL history store."""
from typing import Optional
from qutebrowser.qt.sql import QSqlQueryModel
from qutebrowser.qt.widgets import QWidget
@ -26,12 +25,12 @@ class HistoryCategory(QSqlQueryModel, BaseCategory):
super().__init__(parent=parent)
self._database = database
self.name = "History"
self._query: Optional[sql.Query] = None
self._query: sql.Query | None = None
# advertise that this model filters by URL and title
self.columns_to_filter = [0, 1]
self.delete_func = delete_func
self._empty_prefix: Optional[str] = None
self._empty_prefix: str | None = None
def _atime_expr(self):
"""If max_items is set, return an expression to limit the query."""

View File

@ -102,7 +102,7 @@ _RESOURCE_TYPE_STRINGS = {
}
def _resource_type_to_string(resource_type: Optional[ResourceType]) -> str:
def _resource_type_to_string(resource_type: ResourceType | None) -> str:
return _RESOURCE_TYPE_STRINGS.get(resource_type, "other")
@ -174,8 +174,8 @@ class BraveAdBlocker:
def _is_blocked(
self,
request_url: QUrl,
first_party_url: Optional[QUrl] = None,
resource_type: Optional[interceptor.ResourceType] = None,
first_party_url: QUrl | None = None,
resource_type: interceptor.ResourceType | None = None,
) -> bool:
"""Check whether the given request is blocked."""
if not self.enabled:

View File

@ -11,7 +11,6 @@ import os
import signal
import logging
import pathlib
from typing import Optional
from collections.abc import Sequence, Callable
try:
@ -34,7 +33,7 @@ _LOGGER = logging.getLogger('misc')
@cmdutils.register(name='reload')
@cmdutils.argument('tab', value=cmdutils.Value.count_tab)
def reloadpage(tab: Optional[apitypes.Tab],
def reloadpage(tab: apitypes.Tab | None,
force: bool = False) -> None:
"""Reload the current/[count]th tab.
@ -48,7 +47,7 @@ def reloadpage(tab: Optional[apitypes.Tab],
@cmdutils.register()
@cmdutils.argument('tab', value=cmdutils.Value.count_tab)
def stop(tab: Optional[apitypes.Tab]) -> None:
def stop(tab: apitypes.Tab | None) -> None:
"""Stop loading in the current/[count]th tab.
Args:
@ -88,9 +87,9 @@ def _print_pdf(tab: apitypes.Tab, path: pathlib.Path) -> None:
@cmdutils.register(name='print')
@cmdutils.argument('tab', value=cmdutils.Value.count_tab)
@cmdutils.argument('pdf', flag='f', metavar='file')
def printpage(tab: Optional[apitypes.Tab],
def printpage(tab: apitypes.Tab | None,
preview: bool = False, *,
pdf: Optional[pathlib.Path] = None) -> None:
pdf: pathlib.Path | None = None) -> None:
"""Print the current/[count]th tab.
Args:
@ -193,7 +192,7 @@ def insert_text(tab: apitypes.Tab, text: str) -> None:
Args:
text: The text to insert.
"""
def _insert_text_cb(elem: Optional[apitypes.WebElement]) -> None:
def _insert_text_cb(elem: apitypes.WebElement | None) -> None:
if elem is None:
message.error("No element focused!")
return
@ -207,7 +206,7 @@ def insert_text(tab: apitypes.Tab, text: str) -> None:
def _wrap_find_at_pos(value: str, tab: apitypes.Tab,
callback: Callable[[Optional[apitypes.WebElement]], None]
callback: Callable[[apitypes.WebElement | None], None]
) -> None:
try:
point = utils.parse_point(value)
@ -257,7 +256,7 @@ def click_element(tab: apitypes.Tab, filter_: str, value: str = None, *, # noqa
except apitypes.WebElemError as e:
message.error(str(e))
def single_cb(elem: Optional[apitypes.WebElement]) -> None:
def single_cb(elem: apitypes.WebElement | None) -> None:
"""Click a single element."""
if elem is None:
message.error(f"No element found {_FILTER_ERRORS[filter_](value)}!")
@ -322,7 +321,7 @@ def debug_webaction(tab: apitypes.Tab, action: str, count: int = 1) -> None:
@cmdutils.register()
@cmdutils.argument('tab', value=cmdutils.Value.count_tab)
def tab_mute(tab: Optional[apitypes.Tab]) -> None:
def tab_mute(tab: apitypes.Tab | None) -> None:
"""Mute/Unmute the current/[count]th tab.
Args:

View File

@ -5,7 +5,7 @@
"""Bridge to provide readline-like shortcuts for QLineEdits."""
import os
from typing import Optional, Any
from typing import Any
from collections.abc import Iterable, MutableMapping, Callable
from qutebrowser.qt.widgets import QApplication, QLineEdit
@ -24,7 +24,7 @@ class _ReadlineBridge:
def __init__(self) -> None:
self._deleted: MutableMapping[QLineEdit, str] = {}
def _widget(self) -> Optional[QLineEdit]:
def _widget(self) -> QLineEdit | None:
"""Get the currently active QLineEdit."""
# FIXME add this to api.utils or so
qapp = QApplication.instance()

View File

@ -6,7 +6,7 @@
import os
import functools
from typing import IO, Optional
from typing import IO
from qutebrowser.qt.core import QUrl, QObject, pyqtSignal
@ -47,7 +47,7 @@ class BlocklistDownloads(QObject):
single_download_finished = pyqtSignal(object) # arg: the file object
all_downloads_finished = pyqtSignal(int) # arg: download count
def __init__(self, urls: list[QUrl], parent: Optional[QObject] = None) -> None:
def __init__(self, urls: list[QUrl], parent: QObject | None = None) -> None:
super().__init__(parent)
self._urls = urls

View File

@ -7,7 +7,7 @@
import copy
import contextlib
import functools
from typing import (TYPE_CHECKING, Any, Optional, cast)
from typing import (TYPE_CHECKING, Any, cast)
from collections.abc import Iterator, Mapping, MutableMapping, MutableSequence, Callable
from qutebrowser.qt.core import pyqtSignal, QObject, QUrl
@ -69,7 +69,7 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name
not configdata.is_valid_prefix(self._option)):
raise configexc.NoOptionError(self._option)
def check_match(self, option: Optional[str]) -> bool:
def check_match(self, option: str | None) -> bool:
"""Check if the given option matches the filter."""
if option is None:
# Called directly, not from a config change event.
@ -153,7 +153,7 @@ class KeyConfig:
bindings[key] = binding
return bindings
def _implied_cmd(self, cmdline: str) -> Optional[str]:
def _implied_cmd(self, cmdline: str) -> str | None:
"""Return cmdline, or the implied cmd if cmdline is a cmd-set-text."""
try:
results = parser.CommandParser().parse_all(cmdline)
@ -198,7 +198,7 @@ class KeyConfig:
def get_command(self,
key: keyutils.KeySequence,
mode: str,
default: bool = False) -> Optional[str]:
default: bool = False) -> str | None:
"""Get the command for a given key (or None)."""
self._validate(key, mode)
if default:
@ -415,7 +415,7 @@ class Config(QObject):
def get_obj_for_pattern(
self, name: str, *,
pattern: Optional[urlmatch.UrlPattern]
pattern: urlmatch.UrlPattern | None
) -> Any:
"""Get the given setting as object (for YAML/config.py).

View File

@ -6,7 +6,7 @@
import os.path
import contextlib
from typing import TYPE_CHECKING, Optional, Any
from typing import TYPE_CHECKING, Any
from collections.abc import Iterator
from qutebrowser.qt.core import QUrl, QUrlQuery
@ -40,7 +40,7 @@ class ConfigCommands:
except configexc.Error as e:
raise cmdutils.CommandError(str(e))
def _parse_pattern(self, pattern: Optional[str]) -> Optional[urlmatch.UrlPattern]:
def _parse_pattern(self, pattern: str | None) -> urlmatch.UrlPattern | None:
"""Parse a pattern string argument to a pattern."""
if pattern is None:
return None
@ -58,7 +58,7 @@ class ConfigCommands:
except keyutils.KeyParseError as e:
raise cmdutils.CommandError(str(e))
def _print_value(self, option: str, pattern: Optional[urlmatch.UrlPattern]) -> None:
def _print_value(self, option: str, pattern: urlmatch.UrlPattern | None) -> None:
"""Print the value of the given option."""
with self._handle_config_error():
value = self._config.get_str(option, pattern=pattern)
@ -473,7 +473,7 @@ class ConfigCommands:
raise cmdutils.CommandError("{} already exists - use --force to "
"overwrite!".format(filename))
options: list[tuple[Optional[urlmatch.UrlPattern], configdata.Option, Any]] = []
options: list[tuple[urlmatch.UrlPattern | None, configdata.Option, Any]] = []
if defaults:
options = [(None, opt, opt.default)
for _name, opt in sorted(configdata.DATA.items())]

View File

@ -9,7 +9,7 @@ Module attributes:
DATA: A dict of Option objects after init() has been called.
"""
from typing import (Any, Optional, Union, NoReturn, cast)
from typing import (Any, NoReturn, cast)
from collections.abc import Iterable, Mapping, MutableMapping, Sequence
import functools
import dataclasses
@ -21,7 +21,7 @@ from qutebrowser.misc import debugcachestats
DATA = cast(Mapping[str, 'Option'], None)
MIGRATIONS = cast('Migrations', None)
_BackendDict = Mapping[str, Union[str, bool]]
_BackendDict = Mapping[str, str | bool]
@dataclasses.dataclass(order=True)
@ -36,7 +36,7 @@ class Option:
typ: configtypes.BaseType
default: Any
backends: Iterable[usertypes.Backend]
raw_backends: Optional[Mapping[str, bool]]
raw_backends: Mapping[str, bool] | None
description: str
supports_pattern: bool = False
restart: bool = False
@ -71,7 +71,7 @@ def _raise_invalid_node(name: str, what: str, node: Any) -> NoReturn:
def _parse_yaml_type(
name: str,
node: Union[str, Mapping[str, Any]],
node: str | Mapping[str, Any],
) -> configtypes.BaseType:
if isinstance(node, str):
# e.g:
@ -157,7 +157,7 @@ def _parse_yaml_backends_dict(
def _parse_yaml_backends(
name: str,
node: Union[None, str, _BackendDict],
node: None | str | _BackendDict,
) -> Sequence[usertypes.Backend]:
"""Parse a backend node in the yaml.

View File

@ -6,7 +6,7 @@
import difflib
import dataclasses
from typing import Any, Optional, Union
from typing import Any
from collections.abc import Mapping, Sequence
from qutebrowser.utils import usertypes, log
@ -33,7 +33,7 @@ class BackendError(Error):
def __init__(
self, name: str,
backend: usertypes.Backend,
raw_backends: Optional[Mapping[str, bool]]
raw_backends: Mapping[str, bool] | None
) -> None:
if raw_backends is None or not raw_backends[backend.name]:
msg = ("The {} setting is not available with the {} backend!"
@ -63,7 +63,7 @@ class ValidationError(Error):
msg: Additional error message.
"""
def __init__(self, value: Any, msg: Union[str, Exception]) -> None:
def __init__(self, value: Any, msg: str | Exception) -> None:
super().__init__("Invalid value '{}' - {}".format(value, msg))
self.option = None
@ -111,8 +111,8 @@ class ConfigErrorDesc:
"""
text: str
exception: Union[str, Exception]
traceback: Optional[str] = None
exception: str | Exception
traceback: str | None = None
def __str__(self) -> str:
if self.traceback:

View File

@ -14,7 +14,7 @@ import traceback
import configparser
import contextlib
import re
from typing import (TYPE_CHECKING, Any, Optional, cast)
from typing import (TYPE_CHECKING, Any, cast)
from collections.abc import Iterable, Iterator, Mapping, MutableMapping
import yaml
@ -114,7 +114,7 @@ class StateConfig(configparser.ConfigParser):
return False
return True
def _qtwe_versions(self) -> Optional[version.WebEngineVersions]:
def _qtwe_versions(self) -> version.WebEngineVersions | None:
"""Get the QtWebEngine versions."""
if not self._has_webengine():
return None
@ -758,7 +758,7 @@ class ConfigAPI:
urlpattern = urlmatch.UrlPattern(pattern) if pattern else None
self._config.set_obj(name, value, pattern=urlpattern)
def bind(self, key: str, command: Optional[str], mode: str = 'normal') -> None:
def bind(self, key: str, command: str | None, mode: str = 'normal') -> None:
"""Bind a key to a command, with an optional key mode."""
with self._handle_error(f"binding '{key}'"):
seq = keyutils.KeySequence.parse(key)
@ -805,12 +805,12 @@ class ConfigPyWriter:
self,
options: list[
tuple[
Optional[urlmatch.UrlPattern],
urlmatch.UrlPattern | None,
configdata.Option,
Any
]
],
bindings: MutableMapping[str, Mapping[str, Optional[str]]],
bindings: MutableMapping[str, Mapping[str, str | None]],
*,
commented: bool,
) -> None:

View File

@ -7,7 +7,6 @@
import argparse
import os.path
import sys
from typing import Optional
from qutebrowser.qt.widgets import QMessageBox
@ -20,7 +19,7 @@ from qutebrowser.misc import msgbox, objects, savemanager
# Error which happened during init, so we can show a message box.
_init_errors: Optional[configexc.ConfigFileErrors] = None
_init_errors: configexc.ConfigFileErrors | None = None
def early_init(args: argparse.Namespace) -> None:

View File

@ -36,7 +36,7 @@ import functools
import operator
import json
import dataclasses
from typing import Any, Optional, Union
from typing import Any, Union, TypeAlias
from re import Pattern
from collections.abc import Iterable, Iterator, Sequence, Callable
@ -66,13 +66,13 @@ BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True,
'0': False, 'no': False, 'false': False, 'off': False}
_Completions = Optional[Iterable[tuple[str, str]]]
_StrUnset = Union[str, usertypes.Unset]
_UnsetNone = Union[None, usertypes.Unset]
_StrUnsetNone = Union[str, _UnsetNone]
_Completions: TypeAlias = Iterable[tuple[str, str]] | None
_StrUnset: TypeAlias = str | usertypes.Unset
_UnsetNone: TypeAlias = None | usertypes.Unset
_StrUnsetNone: TypeAlias = str | _UnsetNone
def _validate_encoding(encoding: Optional[str], value: str) -> None:
def _validate_encoding(encoding: str | None, value: str) -> None:
"""Check if the given value fits into the given encoding.
Raises ValidationError if not.
@ -101,11 +101,7 @@ class ValidValues:
def __init__(
self,
*values: Union[
str,
dict[str, Optional[str]],
tuple[str, Optional[str]],
],
*values: str | dict[str, str | None] | tuple[str, str | None],
generate_docs: bool = True,
others_permitted: bool = False
) -> None:
@ -178,19 +174,19 @@ class BaseType:
) -> None:
self._completions = completions
self.none_ok = none_ok
self.valid_values: Optional[ValidValues] = None
self.valid_values: ValidValues | None = None
def get_name(self) -> str:
"""Get a name for the type for documentation."""
return self.__class__.__name__
def get_valid_values(self) -> Optional[ValidValues]:
def get_valid_values(self) -> ValidValues | None:
"""Get the type's valid values for documentation."""
return self.valid_values
def _basic_py_validation(
self, value: Any,
pytype: Union[type, tuple[type, ...]]) -> None:
pytype: type | tuple[type, ...]) -> None:
"""Do some basic validation for Python values (emptyness, type).
Arguments:
@ -356,7 +352,7 @@ class MappingType(BaseType):
MAPPING: A mapping from config values to (translated_value, docs) tuples.
"""
MAPPING: dict[str, tuple[Any, Optional[str]]] = {}
MAPPING: dict[str, tuple[Any, str | None]] = {}
def __init__(
self, *,
@ -505,10 +501,10 @@ class List(BaseType):
name += " of " + self.valtype.get_name()
return name
def get_valid_values(self) -> Optional[ValidValues]:
def get_valid_values(self) -> ValidValues | None:
return self.valtype.get_valid_values()
def from_str(self, value: str) -> Optional[list]:
def from_str(self, value: str) -> list | None:
self._basic_str_validation(value)
if not value:
return None
@ -523,15 +519,15 @@ class List(BaseType):
self.to_py(yaml_val)
return yaml_val
def from_obj(self, value: Optional[list]) -> list:
def from_obj(self, value: list | None) -> list:
if value is None:
return []
return [self.valtype.from_obj(v) for v in value]
def to_py(
self,
value: Union[list, usertypes.Unset]
) -> Union[list, usertypes.Unset]:
value: list | usertypes.Unset
) -> list | usertypes.Unset:
self._basic_py_validation(value, list)
if isinstance(value, usertypes.Unset):
return value
@ -610,7 +606,7 @@ class ListOrValue(BaseType):
def get_name(self) -> str:
return self.listtype.get_name() + ', or ' + self.valtype.get_name()
def get_valid_values(self) -> Optional[ValidValues]:
def get_valid_values(self) -> ValidValues | None:
return self.valtype.get_valid_values()
def from_str(self, value: str) -> Any:
@ -659,7 +655,7 @@ class FlagList(List):
the valid values of the setting.
"""
combinable_values: Optional[Sequence] = None
combinable_values: Sequence | None = None
_show_valtype = False
@ -685,8 +681,8 @@ class FlagList(List):
def to_py(
self,
value: Union[usertypes.Unset, list],
) -> Union[usertypes.Unset, list]:
value: usertypes.Unset | list,
) -> usertypes.Unset | list:
vals = super().to_py(value)
if not isinstance(vals, usertypes.Unset):
self._check_duplicates(vals)
@ -737,12 +733,12 @@ class Bool(BaseType):
super().__init__(none_ok=none_ok, completions=completions)
self.valid_values = ValidValues('true', 'false', generate_docs=False)
def to_py(self, value: Union[bool, str, None]) -> Optional[bool]:
def to_py(self, value: bool | str | None) -> bool | None:
self._basic_py_validation(value, bool)
assert not isinstance(value, str)
return value
def from_str(self, value: str) -> Optional[bool]:
def from_str(self, value: str) -> bool | None:
self._basic_str_validation(value)
if not value:
return None
@ -752,7 +748,7 @@ class Bool(BaseType):
except KeyError:
raise configexc.ValidationError(value, "must be a boolean!")
def to_str(self, value: Optional[bool]) -> str:
def to_str(self, value: bool | None) -> str:
mapping = {
None: '',
True: 'true',
@ -774,7 +770,7 @@ class BoolAsk(Bool):
self.valid_values = ValidValues('true', 'false', 'ask')
def to_py(self, # type: ignore[override]
value: Union[bool, str]) -> Union[bool, str, None]:
value: bool | str) -> bool | str | None:
# basic validation unneeded if it's == 'ask' and done by Bool if we
# call super().to_py
if isinstance(value, str) and value.lower() == 'ask':
@ -782,14 +778,14 @@ class BoolAsk(Bool):
return super().to_py(value)
def from_str(self, # type: ignore[override]
value: str) -> Union[bool, str, None]:
value: str) -> bool | str | None:
# basic validation unneeded if it's == 'ask' and done by Bool if we
# call super().from_str
if value.lower() == 'ask':
return 'ask'
return super().from_str(value)
def to_str(self, value: Union[bool, str, None]) -> str:
def to_str(self, value: bool | str | None) -> str:
mapping = {
None: '',
True: 'true',
@ -826,8 +822,8 @@ class _Numeric(BaseType): # pylint: disable=abstract-method
.format(self.minval, self.maxval))
def _parse_bound(
self, bound: Union[None, str, int, float]
) -> Union[None, int, float]:
self, bound: None | str | int | float
) -> None | int | float:
"""Get a numeric bound from a string like 'maxint'."""
if bound == 'maxint':
return qtutils.MAXVALS['int']
@ -839,7 +835,7 @@ class _Numeric(BaseType): # pylint: disable=abstract-method
return bound
def _validate_bounds(self,
value: Union[int, float, _UnsetNone],
value: int | float | _UnsetNone,
suffix: str = '') -> None:
"""Validate self.minval and self.maxval."""
if value is None:
@ -855,7 +851,7 @@ class _Numeric(BaseType): # pylint: disable=abstract-method
elif not self.zero_ok and value == 0:
raise configexc.ValidationError(value, "must not be 0!")
def to_str(self, value: Union[None, int, float]) -> str:
def to_str(self, value: None | int | float) -> str:
if value is None:
return ''
return str(value)
@ -869,7 +865,7 @@ class Int(_Numeric):
"""Base class for an integer setting."""
def from_str(self, value: str) -> Optional[int]:
def from_str(self, value: str) -> int | None:
self._basic_str_validation(value)
if not value:
return None
@ -881,7 +877,7 @@ class Int(_Numeric):
self.to_py(intval)
return intval
def to_py(self, value: Union[int, _UnsetNone]) -> Union[int, _UnsetNone]:
def to_py(self, value: int | _UnsetNone) -> int | _UnsetNone:
self._basic_py_validation(value, int)
self._validate_bounds(value)
return value
@ -891,7 +887,7 @@ class Float(_Numeric):
"""Base class for a float setting."""
def from_str(self, value: str) -> Optional[float]:
def from_str(self, value: str) -> float | None:
self._basic_str_validation(value)
if not value:
return None
@ -905,8 +901,8 @@ class Float(_Numeric):
def to_py(
self,
value: Union[int, float, _UnsetNone],
) -> Union[int, float, _UnsetNone]:
value: int | float | _UnsetNone,
) -> int | float | _UnsetNone:
self._basic_py_validation(value, (int, float))
self._validate_bounds(value)
return value
@ -918,8 +914,8 @@ class Perc(_Numeric):
def to_py(
self,
value: Union[float, int, str, _UnsetNone]
) -> Union[float, int, _UnsetNone]:
value: float | int | str | _UnsetNone
) -> float | int | _UnsetNone:
self._basic_py_validation(value, (float, int, str))
if isinstance(value, usertypes.Unset):
return value
@ -936,7 +932,7 @@ class Perc(_Numeric):
self._validate_bounds(value, suffix='%')
return value
def to_str(self, value: Union[None, float, int, str]) -> str:
def to_str(self, value: None | float | int | str) -> str:
if value is None:
return ''
elif isinstance(value, str):
@ -978,7 +974,7 @@ class PercOrInt(_Numeric):
raise ValueError("minperc ({}) needs to be <= maxperc "
"({})!".format(self.minperc, self.maxperc))
def from_str(self, value: str) -> Union[None, str, int]:
def from_str(self, value: str) -> None | str | int:
self._basic_str_validation(value)
if not value:
return None
@ -995,7 +991,7 @@ class PercOrInt(_Numeric):
self.to_py(intval)
return intval
def to_py(self, value: Union[None, str, int]) -> Union[None, str, int]:
def to_py(self, value: None | str | int) -> None | str | int:
"""Expect a value like '42%' as string, or 23 as int."""
self._basic_py_validation(value, (int, str))
if value is None:
@ -1110,7 +1106,7 @@ class QtColor(BaseType):
except ValueError:
raise configexc.ValidationError(val, "must be a valid color value")
def to_py(self, value: _StrUnset) -> Union[_UnsetNone, QColor]:
def to_py(self, value: _StrUnset) -> _UnsetNone | QColor:
self._basic_py_validation(value, str)
if isinstance(value, usertypes.Unset):
return value
@ -1193,8 +1189,8 @@ class FontBase(BaseType):
"""Base class for Font/FontFamily."""
# Gets set when the config is initialized.
default_family: Optional[str] = None
default_size: Optional[str] = None
default_family: str | None = None
default_size: str | None = None
font_regex = re.compile(r"""
(
(
@ -1334,8 +1330,8 @@ class Regex(BaseType):
def to_py(
self,
value: Union[str, Pattern[str], usertypes.Unset]
) -> Union[_UnsetNone, Pattern[str]]:
value: str | Pattern[str] | usertypes.Unset
) -> _UnsetNone | Pattern[str]:
"""Get a compiled regex from either a string or a regex object."""
self._basic_py_validation(value, (str, self._regex_type))
if isinstance(value, usertypes.Unset):
@ -1347,7 +1343,7 @@ class Regex(BaseType):
else:
return value
def to_str(self, value: Union[None, str, Pattern[str]]) -> str:
def to_str(self, value: None | str | Pattern[str]) -> str:
if value is None:
return ''
elif isinstance(value, self._regex_type):
@ -1396,7 +1392,7 @@ class Dict(BaseType):
raise configexc.ValidationError(
value, "Required keys {}".format(self.required_keys))
def from_str(self, value: str) -> Optional[dict]:
def from_str(self, value: str) -> dict | None:
self._basic_str_validation(value)
if not value:
return None
@ -1411,7 +1407,7 @@ class Dict(BaseType):
self.to_py(yaml_val)
return yaml_val
def from_obj(self, value: Optional[dict]) -> dict:
def from_obj(self, value: dict | None) -> dict:
if value is None:
return {}
@ -1429,8 +1425,8 @@ class Dict(BaseType):
def to_py(
self,
value: Union[dict, _UnsetNone]
) -> Union[dict, usertypes.Unset]:
value: dict | _UnsetNone
) -> dict | usertypes.Unset:
self._basic_py_validation(value, dict)
if isinstance(value, usertypes.Unset):
return value
@ -1606,8 +1602,8 @@ class ShellCommand(List):
def to_py(
self,
value: Union[list, usertypes.Unset],
) -> Union[list, usertypes.Unset]:
value: list | usertypes.Unset,
) -> list | usertypes.Unset:
py_value = super().to_py(value)
if isinstance(py_value, usertypes.Unset):
return py_value
@ -1646,7 +1642,7 @@ class Proxy(BaseType):
def to_py(
self,
value: _StrUnset
) -> Union[_UnsetNone, QNetworkProxy, _SystemProxy, pac.PACFetcher]:
) -> _UnsetNone | QNetworkProxy | _SystemProxy | pac.PACFetcher:
self._basic_py_validation(value, str)
if isinstance(value, usertypes.Unset):
return value
@ -1719,7 +1715,7 @@ class FuzzyUrl(BaseType):
"""A URL which gets interpreted as search if needed."""
def to_py(self, value: _StrUnset) -> Union[QUrl, _UnsetNone]:
def to_py(self, value: _StrUnset) -> QUrl | _UnsetNone:
self._basic_py_validation(value, str)
if isinstance(value, usertypes.Unset):
return value
@ -1764,8 +1760,8 @@ class Padding(Dict):
def to_py( # type: ignore[override]
self,
value: Union[dict, _UnsetNone],
) -> Union[usertypes.Unset, PaddingValues]:
value: dict | _UnsetNone,
) -> usertypes.Unset | PaddingValues:
d = super().to_py(value)
if isinstance(d, usertypes.Unset):
return d
@ -1842,7 +1838,7 @@ class Url(BaseType):
"""A URL as a string."""
def to_py(self, value: _StrUnset) -> Union[_UnsetNone, QUrl]:
def to_py(self, value: _StrUnset) -> _UnsetNone | QUrl:
self._basic_py_validation(value, str)
if isinstance(value, usertypes.Unset):
return value
@ -1917,8 +1913,8 @@ class ConfirmQuit(FlagList):
def to_py(
self,
value: Union[usertypes.Unset, list],
) -> Union[list, usertypes.Unset]:
value: usertypes.Unset | list,
) -> list | usertypes.Unset:
values = super().to_py(value)
if isinstance(values, usertypes.Unset):
return values
@ -1979,7 +1975,7 @@ class Key(BaseType):
def to_py(
self,
value: _StrUnset
) -> Union[_UnsetNone, keyutils.KeySequence]:
) -> _UnsetNone | keyutils.KeySequence:
self._basic_py_validation(value, str)
if isinstance(value, usertypes.Unset):
return value
@ -2004,7 +2000,7 @@ class UrlPattern(BaseType):
def to_py(
self,
value: _StrUnset
) -> Union[_UnsetNone, urlmatch.UrlPattern]:
) -> _UnsetNone | urlmatch.UrlPattern:
self._basic_py_validation(value, str)
if isinstance(value, usertypes.Unset):
return value

View File

@ -9,7 +9,7 @@ import collections
import itertools
import operator
from typing import (
TYPE_CHECKING, Any, Optional, Union)
TYPE_CHECKING, Any, TypeAlias)
from collections.abc import Iterator, Sequence, MutableMapping
from qutebrowser.qt.core import QUrl
@ -36,7 +36,7 @@ class ScopedValue:
id_gen = itertools.count(0)
def __init__(self, value: Any,
pattern: Optional[urlmatch.UrlPattern],
pattern: urlmatch.UrlPattern | None,
hide_userconfig: bool = False) -> None:
self.value = value
self.pattern = pattern
@ -69,7 +69,7 @@ class Values:
_domain_map: A mapping from hostnames to all associated ScopedValues.
"""
_VmapKeyType = Optional[urlmatch.UrlPattern]
_VmapKeyType: TypeAlias = urlmatch.UrlPattern | None
def __init__(self,
opt: 'configdata.Option',
@ -79,7 +79,7 @@ class Values:
Values._VmapKeyType, ScopedValue] = collections.OrderedDict()
# A map from domain parts to rules that fall under them.
self._domain_map: dict[
Optional[str], set[ScopedValue]] = collections.defaultdict(set)
str | None, set[ScopedValue]] = collections.defaultdict(set)
for scoped in values:
self._add_scoped(scoped)
@ -130,7 +130,7 @@ class Values:
return bool(self._vmap)
def _check_pattern_support(
self, arg: Union[urlmatch.UrlPattern, QUrl, None]) -> None:
self, arg: urlmatch.UrlPattern | QUrl | None) -> None:
"""Make sure patterns are supported if one was given."""
if arg is not None and not self.opt.supports_pattern:
raise configexc.NoPatternError(self.opt.name)
@ -225,7 +225,7 @@ class Values:
return self._get_fallback(fallback)
def get_for_pattern(self,
pattern: Optional[urlmatch.UrlPattern], *,
pattern: urlmatch.UrlPattern | None, *,
fallback: bool = True) -> Any:
"""Get a value only if it's been overridden for the given pattern.

View File

@ -11,7 +11,7 @@ import pathlib
# Using deprecated typing.Callable as a WORKAROUND because
# collections.abc.Callable inside Optional[...]/Union[...]
# is broken on Python 3.9.0 and 3.9.1
from typing import Any, Optional, Union, Callable
from typing import Any, Callable, TypeAlias
from collections.abc import Iterator, Sequence
from qutebrowser.qt import machinery
@ -213,7 +213,7 @@ def _webengine_locales_path() -> pathlib.Path:
def _get_lang_override(
webengine_version: utils.VersionNumber,
locale_name: str
) -> Optional[str]:
) -> str | None:
"""Get a --lang switch to override Qt's locale handling.
This is needed as a WORKAROUND for https://bugreports.qt.io/browse/QTBUG-91715
@ -290,16 +290,8 @@ def _qtwebengine_args(
yield from _qtwebengine_settings_args(versions)
_SettingValueType = Union[
str,
Callable[
[
version.WebEngineVersions,
],
Optional[str],
],
]
_WEBENGINE_SETTINGS: dict[str, dict[Any, Optional[_SettingValueType]]] = {
_SettingValueType: TypeAlias = str | Callable[[version.WebEngineVersions], str | None]
_WEBENGINE_SETTINGS: dict[str, dict[Any, _SettingValueType | None]] = {
'qt.force_software_rendering': {
'software-opengl': None,
'qt-quick': None,

View File

@ -5,7 +5,6 @@
"""Handling of Qt qss stylesheets."""
import functools
from typing import Optional
from qutebrowser.qt.core import pyqtSlot, QObject
from qutebrowser.qt.widgets import QWidget
@ -58,7 +57,7 @@ class _StyleSheetObserver(QObject):
"""
def __init__(self, obj: QWidget,
stylesheet: Optional[str], update: bool) -> None:
stylesheet: str | None, update: bool) -> None:
super().__init__()
self._obj = obj
self._update = update
@ -72,7 +71,7 @@ class _StyleSheetObserver(QObject):
self._stylesheet = stylesheet
if update:
self._options: Optional[frozenset[str]] = jinja.template_config_variables(
self._options: frozenset[str] | None = jinja.template_config_variables(
self._stylesheet)
else:
self._options = None

View File

@ -8,7 +8,7 @@ import re
import argparse
import functools
import dataclasses
from typing import Any, Optional, Union
from typing import Any
from collections.abc import Callable
from qutebrowser.qt.core import QUrl, pyqtSlot, qVersion
@ -32,7 +32,7 @@ class UserAgent:
upstream_browser_key: str
upstream_browser_version: str
qt_key: str
qt_version: Optional[str]
qt_version: str | None
@property
def upstream_browser_version_short(self) -> str:
@ -123,7 +123,7 @@ class AbstractSettings:
info = self._ATTRIBUTES[name]
return self._settings.testAttribute(info.attributes[0])
def set_font_size(self, name: str, value: Union[int, usertypes.Unset]) -> None:
def set_font_size(self, name: str, value: int | usertypes.Unset) -> None:
"""Set the given QWebSettings/QWebEngineSettings font size."""
family = self._FONT_SIZES[name]
if value is usertypes.UNSET:
@ -134,7 +134,7 @@ class AbstractSettings:
def set_font_family(
self,
name: str,
value: Union[str, None, usertypes.Unset],
value: str | None | usertypes.Unset,
) -> None:
"""Set the given QWebSettings/QWebEngineSettings font family.
@ -152,7 +152,7 @@ class AbstractSettings:
else:
self._settings.setFontFamily(family, value)
def set_default_text_encoding(self, encoding: Union[str, usertypes.Unset]) -> None:
def set_default_text_encoding(self, encoding: str | usertypes.Unset) -> None:
"""Set the default text encoding to use."""
assert encoding is not usertypes.UNSET # unclear how to reset
self._settings.setDefaultTextEncoding(encoding)

View File

@ -6,7 +6,6 @@
import enum
import dataclasses
from typing import Optional
from collections.abc import Callable
from qutebrowser.qt.core import QUrl
@ -55,7 +54,7 @@ class Request:
"""A request which can be intercepted/blocked."""
#: The URL of the page being shown.
first_party_url: Optional[QUrl]
first_party_url: QUrl | None
#: The URL of the file being requested.
request_url: QUrl
@ -63,7 +62,7 @@ class Request:
is_blocked: bool = False
#: The resource type of the request. None if not supported on this backend.
resource_type: Optional[ResourceType] = None
resource_type: ResourceType | None = None
def block(self) -> None:
"""Block this request."""

View File

@ -10,7 +10,6 @@ import pathlib
import importlib
import argparse
import dataclasses
from typing import Optional
from collections.abc import Iterator, Callable
from qutebrowser.qt.core import pyqtSlot
@ -47,10 +46,10 @@ class ModuleInfo:
"""
skip_hooks: bool = False
init_hook: Optional[InitHookType] = None
init_hook: InitHookType | None = None
config_changed_hooks: list[
tuple[
Optional[str],
str | None,
ConfigChangedHookType,
]
] = dataclasses.field(default_factory=list)

View File

@ -8,7 +8,6 @@ import string
import types
import dataclasses
import traceback
from typing import Optional
from collections.abc import Mapping, MutableMapping, Sequence
from qutebrowser.qt.core import QObject, pyqtSignal
@ -25,7 +24,7 @@ class MatchResult:
"""The result of matching a keybinding."""
match_type: QKeySequence.SequenceMatch
command: Optional[str]
command: str | None
sequence: keyutils.KeySequence
def __post_init__(self) -> None:
@ -63,7 +62,7 @@ class BindingTrie:
def __init__(self) -> None:
self.children: MutableMapping[keyutils.KeyInfo, BindingTrie] = {}
self.command: Optional[str] = None
self.command: str | None = None
def __setitem__(self, sequence: keyutils.KeySequence,
command: str) -> None:

View File

@ -4,7 +4,7 @@
"""Global Qt event filter which dispatches key events."""
from typing import cast, Optional
from typing import cast
from qutebrowser.qt.core import pyqtSlot, QObject, QEvent, qVersion
from qutebrowser.qt.gui import QKeyEvent, QWindow
@ -62,7 +62,7 @@ class EventFilter(QObject):
# No window available yet, or not a MainWindow
return False
def eventFilter(self, obj: Optional[QObject], event: Optional[QEvent]) -> bool:
def eventFilter(self, obj: QObject | None, event: QEvent | None) -> bool:
"""Handle an event.
Args:

View File

@ -18,7 +18,7 @@ handle what we actually think we do.
import itertools
import dataclasses
from typing import Optional, Union, overload, cast
from typing import Union, overload, cast, TypeAlias
from collections.abc import Iterator, Iterable, Mapping
from qutebrowser.qt import machinery
@ -52,7 +52,7 @@ _MODIFIER_MAP = {
}
try:
_NIL_KEY: Union[Qt.Key, int] = Qt.Key(0)
_NIL_KEY: Qt.Key | int = Qt.Key(0)
except ValueError:
# WORKAROUND for
# https://www.riverbankcomputing.com/pipermail/pyqt/2022-April/044607.html
@ -63,7 +63,7 @@ if machinery.IS_QT6:
_ModifierType = Qt.KeyboardModifier
else:
_KeyInfoType = int
_ModifierType = Union[Qt.KeyboardModifiers, Qt.KeyboardModifier]
_ModifierType: TypeAlias = Qt.KeyboardModifiers | Qt.KeyboardModifier
_SPECIAL_NAMES = {
@ -203,7 +203,7 @@ def _remap_unicode(key: Qt.Key, text: str) -> Qt.Key:
return key
def _check_valid_utf8(s: str, data: Union[Qt.Key, _ModifierType]) -> None:
def _check_valid_utf8(s: str, data: Qt.Key | _ModifierType) -> None:
"""Make sure the given string is valid UTF-8.
Makes sure there are no chars where Qt did fall back to weird UTF-16
@ -259,7 +259,7 @@ class KeyParseError(Exception):
"""Raised by _parse_single_key/parse_keystring on parse errors."""
def __init__(self, keystr: Optional[str], error: str) -> None:
def __init__(self, keystr: str | None, error: str) -> None:
if keystr is None:
msg = "Could not parse keystring: {}".format(error)
else:
@ -593,7 +593,7 @@ class KeySequence:
def __getitem__(self, item: slice) -> 'KeySequence':
...
def __getitem__(self, item: Union[int, slice]) -> Union[KeyInfo, 'KeySequence']:
def __getitem__(self, item: int | slice) -> Union[KeyInfo, 'KeySequence']:
infos = list(self)
if isinstance(item, slice):
return self.__class__(*infos[item])

View File

@ -5,7 +5,7 @@
"""Keyboard macro system."""
from typing import cast, Optional
from typing import cast
from qutebrowser.commands import runners
from qutebrowser.api import cmdutils
@ -33,9 +33,9 @@ class MacroRecorder:
def __init__(self) -> None:
self._macros: dict[str, list[_CommandType]] = {}
self._recording_macro: Optional[str] = None
self._recording_macro: str | None = None
self._macro_count: dict[int, int] = {}
self._last_register: Optional[str] = None
self._last_register: str | None = None
@cmdutils.register(instance='macro-recorder')
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)

View File

@ -6,7 +6,7 @@
import functools
import dataclasses
from typing import Union, cast
from typing import cast
from collections.abc import Mapping, MutableMapping, Callable
from qutebrowser.qt import machinery
@ -185,7 +185,7 @@ def init(win_id: int, parent: QObject) -> 'ModeManager':
return modeman
def instance(win_id: Union[int, str]) -> 'ModeManager':
def instance(win_id: int | str) -> 'ModeManager':
"""Get a modemanager object.
Raises UnavailableError if there is no instance available yet.

View File

@ -8,7 +8,7 @@ import binascii
import base64
import itertools
import functools
from typing import Optional, cast
from typing import cast
from collections.abc import MutableSequence
from qutebrowser.qt import machinery
@ -184,8 +184,8 @@ class MainWindow(QWidget):
def __init__(self, *,
private: bool,
geometry: Optional[QByteArray] = None,
parent: Optional[QWidget] = None) -> None:
geometry: QByteArray | None = None,
parent: QWidget | None = None) -> None:
"""Create a new main window.
Args:

View File

@ -4,7 +4,6 @@
"""Showing messages above the statusbar."""
from typing import Optional
from collections.abc import MutableSequence
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, Qt
@ -22,7 +21,7 @@ class Message(QLabel):
self,
level: usertypes.MessageLevel,
text: str,
replace: Optional[str],
replace: str | None,
text_format: Qt.TextFormat,
parent: QWidget = None,
) -> None:

View File

@ -9,7 +9,7 @@ import html
import collections
import functools
import dataclasses
from typing import Optional, cast
from typing import cast
from collections.abc import MutableSequence
from qutebrowser.qt.core import (pyqtSlot, pyqtSignal, Qt, QTimer, QDir, QModelIndex,
@ -270,7 +270,7 @@ class PromptContainer(QWidget):
self._layout = QVBoxLayout(self)
self._layout.setContentsMargins(10, 10, 10, 10)
self._win_id = win_id
self._prompt: Optional[_BasePrompt] = None
self._prompt: _BasePrompt | None = None
self.setObjectName('PromptContainer')
self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)

View File

@ -4,7 +4,7 @@
"""The commandline in the statusbar."""
from typing import Optional, cast
from typing import cast
from qutebrowser.qt import machinery
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, Qt, QSize
@ -238,7 +238,7 @@ class Command(misc.CommandLineEdit):
self.clear_completion_selection.emit()
self.hide_completion.emit()
def setText(self, text: Optional[str]) -> None:
def setText(self, text: str | None) -> None:
"""Extend setText to set prefix and make sure the prompt is ok."""
if not text:
pass
@ -252,7 +252,7 @@ class Command(misc.CommandLineEdit):
text = cast(str, text)
super().setText(text)
def keyPressEvent(self, e: Optional[QKeyEvent]) -> None:
def keyPressEvent(self, e: QKeyEvent | None) -> None:
"""Override keyPressEvent to ignore Return key presses, and add Shift-Ins.
If this widget is focused, we are in passthrough key mode, and

View File

@ -12,7 +12,7 @@ import weakref
import datetime
import dataclasses
from typing import (
Any, Optional)
Any)
from collections.abc import Mapping, MutableMapping, MutableSequence
from qutebrowser.qt.widgets import QSizePolicy, QWidget, QApplication
@ -85,7 +85,7 @@ class TabDeque:
Throws IndexError on failure.
"""
tab: Optional[browsertab.AbstractTab] = None
tab: browsertab.AbstractTab | None = None
while tab is None or tab.pending_removal or tab is cur_tab:
tab = self._stack.pop()()
self._stack_deleted.append(weakref.ref(cur_tab))
@ -102,7 +102,7 @@ class TabDeque:
Throws IndexError on failure.
"""
tab: Optional[browsertab.AbstractTab] = None
tab: browsertab.AbstractTab | None = None
while tab is None or tab.pending_removal or tab is cur_tab:
tab = self._stack_deleted.pop()()
# On next tab-switch, current tab will be added to stack as normal.
@ -397,7 +397,7 @@ class TabbedBrowser(QWidget):
assert window is not None
return window
def _tab_by_idx(self, idx: int) -> Optional[browsertab.AbstractTab]:
def _tab_by_idx(self, idx: int) -> browsertab.AbstractTab | None:
"""Get a browser tab by index.
If no tab was found at the given index, None is returned.

View File

@ -7,7 +7,7 @@
import functools
import contextlib
import dataclasses
from typing import Optional, Any
from typing import Any
from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, Qt, QSize, QRect, QPoint,
QTimer, QUrl)
@ -79,7 +79,7 @@ class TabWidget(QTabWidget):
assert isinstance(bar, TabBar), bar
return bar
def _tab_by_idx(self, idx: int) -> Optional[browsertab.AbstractTab]:
def _tab_by_idx(self, idx: int) -> browsertab.AbstractTab | None:
"""Get the tab at the given index."""
tab = self.widget(idx)
if tab is not None:

View File

@ -13,7 +13,7 @@ import shutil
import os.path
import argparse
import dataclasses
from typing import Any, Optional
from typing import Any
from collections.abc import Sequence
from qutebrowser.qt import machinery
@ -154,8 +154,8 @@ class _BackendImports:
"""Whether backend modules could be imported."""
webkit_error: Optional[str] = None
webengine_error: Optional[str] = None
webkit_error: str | None = None
webengine_error: str | None = None
class _BackendProblemChecker:

View File

@ -16,7 +16,7 @@ import functools
import threading
import faulthandler
import dataclasses
from typing import TYPE_CHECKING, Optional, cast
from typing import TYPE_CHECKING, cast
from collections.abc import Callable, MutableMapping
from qutebrowser.qt.core import (pyqtSlot, qInstallMessageHandler, QObject,
@ -323,10 +323,10 @@ class SignalHandler(QObject):
self._timer = usertypes.Timer(self, 'python_hacks')
self._orig_handlers: MutableMapping[int, 'signal._HANDLER'] = {}
self._activated = False
self._orig_wakeup_fd: Optional[int] = None
self._orig_wakeup_fd: int | None = None
self._handlers: dict[
signal.Signals, Callable[[int, Optional[types.FrameType]], None]
signal.Signals, Callable[[int, types.FrameType | None], None]
] = {
signal.SIGINT: self.interrupt,
signal.SIGTERM: self.interrupt,

View File

@ -9,7 +9,7 @@ dependencies as possible to avoid cyclic dependencies.
"""
import weakref
from typing import Any, Optional, TypeVar
from typing import Any, TypeVar
from collections.abc import MutableMapping, Callable
from qutebrowser.utils import log
@ -22,7 +22,7 @@ _CACHE_FUNCTIONS: MutableMapping[str, Any] = weakref.WeakValueDictionary()
_T = TypeVar('_T', bound=Callable[..., Any])
def register(name: Optional[str] = None) -> Callable[[_T], _T]:
def register(name: str | None = None) -> Callable[[_T], _T]:
"""Register a lru_cache wrapped function for debug_cache_stats."""
def wrapper(fn: _T) -> _T:
fn_name = fn.__name__ if name is None else name

View File

@ -49,7 +49,7 @@ import re
import dataclasses
import mmap
import pathlib
from typing import IO, ClassVar, Optional, cast
from typing import IO, ClassVar, cast
from qutebrowser.qt import machinery
from qutebrowser.utils import log, version, qtutils
@ -289,7 +289,7 @@ def _parse_from_file(f: IO[bytes]) -> Versions:
return _find_versions(data)
def parse_webenginecore() -> Optional[Versions]:
def parse_webenginecore() -> Versions | None:
"""Parse the QtWebEngineCore library file."""
if version.is_flatpak():
# Flatpak has Qt in /usr/lib/x86_64-linux-gnu, but QtWebEngine in /app/lib.

View File

@ -21,7 +21,7 @@ from qutebrowser.completion.models import miscmodels
all_processes: dict[int, Optional['GUIProcess']] = {}
last_pid: Optional[int] = None
last_pid: int | None = None
@cmdutils.register()
@ -71,8 +71,8 @@ class ProcessOutcome:
what: str
running: bool = False
status: Optional[QProcess.ExitStatus] = None
code: Optional[int] = None
status: QProcess.ExitStatus | None = None
code: int | None = None
def was_successful(self) -> bool:
"""Whether the process exited successfully.
@ -95,7 +95,7 @@ class ProcessOutcome:
self.code == signal.SIGTERM
)
def _crash_signal(self) -> Optional[signal.Signals]:
def _crash_signal(self) -> signal.Signals | None:
"""Get a Python signal (e.g. signal.SIGTERM) from a crashed process."""
assert self.status == QProcess.ExitStatus.CrashExit
if self.code is None:
@ -185,10 +185,10 @@ class GUIProcess(QObject):
self.verbose = verbose
self._output_messages = output_messages
self.outcome = ProcessOutcome(what=what)
self.cmd: Optional[str] = None
self.resolved_cmd: Optional[str] = None
self.args: Optional[Sequence[str]] = None
self.pid: Optional[int] = None
self.cmd: str | None = None
self.resolved_cmd: str | None = None
self.args: Sequence[str] | None = None
self.pid: int | None = None
self.stdout: str = ""
self.stderr: str = ""

View File

@ -176,7 +176,7 @@ class IPCServer(QObject):
self._atime_timer.timeout.connect(self.update_atime)
self._atime_timer.setTimerType(Qt.TimerType.VeryCoarseTimer)
self._server: Optional[QLocalServer] = QLocalServer(self)
self._server: QLocalServer | None = QLocalServer(self)
self._server.newConnection.connect(self.handle_connection)
self._socket = None

View File

@ -4,7 +4,6 @@
"""Misc. widgets used at different places."""
from typing import Optional
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, Qt, QSize, QTimer
from qutebrowser.qt.widgets import (QLineEdit, QWidget, QHBoxLayout, QLabel,
@ -192,8 +191,8 @@ class WrapperLayout(QLayout):
def __init__(self, parent=None):
super().__init__(parent)
self._widget: Optional[QWidget] = None
self._container: Optional[QWidget] = None
self._widget: QWidget | None = None
self._container: QWidget | None = None
def addItem(self, _widget):
raise utils.Unreachable
@ -310,10 +309,10 @@ class InspectorSplitter(QSplitter):
self.addWidget(main_webview)
self.setFocusProxy(main_webview)
self.splitterMoved.connect(self._on_splitter_moved)
self._main_idx: Optional[int] = None
self._inspector_idx: Optional[int] = None
self._position: Optional[inspector.Position] = None
self._preferred_size: Optional[int] = None
self._main_idx: int | None = None
self._inspector_idx: int | None = None
self._position: inspector.Position | None = None
self._preferred_size: int | None = None
def cycle_focus(self):
"""Cycle keyboard focus between the main/inspector widget."""
@ -439,7 +438,7 @@ class InspectorSplitter(QSplitter):
self._preferred_size = sizes[self._inspector_idx]
self._save_preferred_size()
def resizeEvent(self, e: Optional[QResizeEvent]) -> None:
def resizeEvent(self, e: QResizeEvent | None) -> None:
"""Window resize event."""
assert e is not None
super().resizeEvent(e)

View File

@ -7,7 +7,7 @@
This entire file is a giant WORKAROUND for https://bugreports.qt.io/browse/QTBUG-114334.
"""
from typing import Union, Optional
from typing import Optional
import enum
import ctypes
import ctypes.util
@ -138,8 +138,8 @@ class NativeEventFilter(QAbstractNativeEventFilter):
def nativeEventFilter(
self,
evtype: Union[QByteArray, bytes, bytearray, memoryview],
message: Optional[sip.voidptr],
evtype: QByteArray | bytes | bytearray | memoryview,
message: sip.voidptr | None,
) -> tuple[bool, _PointerRetType]:
"""Handle XCB events."""
# We're only installed when the platform plugin is xcb

View File

@ -31,7 +31,7 @@ import shutil
import pathlib
import dataclasses
import contextlib
from typing import ClassVar, IO, Optional
from typing import ClassVar, IO
from collections.abc import Iterator
from qutebrowser.config import config
@ -127,7 +127,7 @@ class PakParser:
except ValueError:
raise binparsing.ParseError("Couldn't find URL in manifest")
def _maybe_get_hangouts_manifest(self, entry: PakEntry) -> Optional[bytes]:
def _maybe_get_hangouts_manifest(self, entry: PakEntry) -> bytes | None:
self.fobj.seek(entry.file_offset)
data = self.fobj.read(entry.size)
@ -210,7 +210,7 @@ def _find_webengine_resources() -> pathlib.Path:
f"Couldn't find webengine resources dir, candidates:\n{candidates_str}")
def copy_webengine_resources() -> Optional[pathlib.Path]:
def copy_webengine_resources() -> pathlib.Path | None:
"""Copy qtwebengine resources to local dir for patching."""
resources_dir = _find_webengine_resources()
work_dir = pathlib.Path(standarddir.cache()) / CACHE_DIR_NAME
@ -265,7 +265,7 @@ def _patch(file_to_patch: pathlib.Path) -> None:
_error(e, "Failed to apply quirk to resources pak.")
def _error(exc: Optional[BaseException], text: str) -> None:
def _error(exc: BaseException | None, text: str) -> None:
if config.val.qt.workarounds.disable_hangouts_extension:
# Explicitly requested -> hard error
lines = ["Failed to disable Hangouts extension:", text]

View File

@ -10,7 +10,7 @@ import itertools
import urllib
import shutil
import pathlib
from typing import Any, Optional, Union, cast
from typing import Any, cast, TypeAlias
from collections.abc import Iterable, MutableMapping, MutableSequence
from qutebrowser.qt.core import Qt, QUrl, QObject, QPoint, QTimer, QDateTime
@ -37,7 +37,7 @@ class Sentinel:
default = Sentinel()
session_manager = cast('SessionManager', None)
ArgType = Union[str, Sentinel]
ArgType: TypeAlias = str | Sentinel
def init(parent=None):
@ -63,7 +63,7 @@ def init(parent=None):
session_manager = SessionManager(str(base_path), parent)
def shutdown(session: Optional[ArgType], last_window: bool) -> None:
def shutdown(session: ArgType | None, last_window: bool) -> None:
"""Handle a shutdown by saving sessions and removing the autosave file."""
if session_manager is None:
return # type: ignore[unreachable]
@ -136,7 +136,7 @@ class SessionManager(QObject):
def __init__(self, base_path, parent=None):
super().__init__(parent)
self.current: Optional[str] = None
self.current: str | None = None
self._base_path = base_path
self._last_window_session = None
self.did_load = False
@ -436,7 +436,7 @@ class SessionManager(QObject):
orig_url = url
if histentry.get("last_visited"):
last_visited: Optional[QDateTime] = QDateTime.fromString(
last_visited: QDateTime | None = QDateTime.fromString(
histentry.get("last_visited"),
Qt.DateFormat.ISODate,
)

View File

@ -9,7 +9,7 @@ import collections
import contextlib
import dataclasses
import types
from typing import Any, Optional, Union
from typing import Any
from collections.abc import Iterator, Mapping, MutableSequence
from qutebrowser.qt.core import QObject, pyqtSignal
@ -101,7 +101,7 @@ class Error(Exception):
"""Base class for all SQL related errors."""
def __init__(self, msg: str, error: Optional[QSqlError] = None) -> None:
def __init__(self, msg: str, error: QSqlError | None = None) -> None:
super().__init__(msg)
self.error = error
@ -135,7 +135,7 @@ class BugError(Error):
def raise_sqlite_error(msg: str, error: QSqlError) -> None:
"""Raise either a BugError or KnownError."""
error_code = error.nativeErrorCode()
primary_error_code: Union[SqliteErrorCode, str]
primary_error_code: SqliteErrorCode | str
try:
# https://sqlite.org/rescode.html#pve
primary_error_code = SqliteErrorCode(int(error_code) & 0xff)
@ -228,8 +228,8 @@ class Database:
return Query(self, querystr, forward_only)
def table(self, name: str, fields: list[str],
constraints: Optional[dict[str, str]] = None,
parent: Optional[QObject] = None) -> 'SqlTable':
constraints: dict[str, str] | None = None,
parent: QObject | None = None) -> 'SqlTable':
"""Return a SqlTable instance linked to this Database."""
return SqlTable(self, name, fields, constraints, parent)
@ -277,9 +277,9 @@ class Transaction(contextlib.AbstractContextManager): # type: ignore[type-arg]
raise_sqlite_error(msg, error)
def __exit__(self,
_exc_type: Optional[type[BaseException]],
exc_val: Optional[BaseException],
_exc_tb: Optional[types.TracebackType]) -> None:
_exc_type: type[BaseException] | None,
exc_val: BaseException | None,
_exc_tb: types.TracebackType | None) -> None:
db = self._database.qt_database()
if exc_val:
log.sql.debug('Rolling back a transaction')
@ -428,8 +428,8 @@ class SqlTable(QObject):
database: Database
def __init__(self, database: Database, name: str, fields: list[str],
constraints: Optional[dict[str, str]] = None,
parent: Optional[QObject] = None) -> None:
constraints: dict[str, str] | None = None,
parent: QObject | None = None) -> None:
"""Wrapper over a table in the SQL database.
Args:
@ -443,7 +443,7 @@ class SqlTable(QObject):
self.database = database
self._create_table(fields, constraints)
def _create_table(self, fields: list[str], constraints: Optional[dict[str, str]],
def _create_table(self, fields: list[str], constraints: dict[str, str] | None,
*, force: bool = False) -> None:
"""Create the table if the database is uninitialized.

View File

@ -6,7 +6,7 @@
import dataclasses
import time
from typing import Any, Optional
from typing import Any
from collections.abc import Mapping, Sequence, Callable
from qutebrowser.qt.core import QObject
@ -45,8 +45,8 @@ class Throttle(QObject):
super().__init__(parent)
self._delay_ms = delay_ms
self._func = func
self._pending_call: Optional[_CallArgs] = None
self._last_call_ms: Optional[int] = None
self._pending_call: _CallArgs | None = None
self._last_call_ms: int | None = None
self._timer = usertypes.Timer(self, 'throttle-timer')
self._timer.setSingleShot(True)

View File

@ -9,7 +9,6 @@
import functools
import os
import traceback
from typing import Optional
from qutebrowser.qt.core import QUrl
from qutebrowser.qt.widgets import QApplication
@ -264,7 +263,7 @@ def version(win_id: int, paste: bool = False) -> None:
pastebin_version()
_keytester_widget: Optional[miscwidgets.KeyTesterWidget] = None
_keytester_widget: miscwidgets.KeyTesterWidget | None = None
@cmdutils.register(debug=True)

View File

@ -30,7 +30,6 @@ import argparse
import warnings
import importlib
import dataclasses
from typing import Optional
from qutebrowser.utils import log
@ -105,7 +104,7 @@ class SelectionReason(enum.Enum):
class SelectionInfo:
"""Information about outcomes of importing Qt wrappers."""
wrapper: Optional[str] = None
wrapper: str | None = None
outcomes: dict[str, str] = dataclasses.field(default_factory=dict)
reason: SelectionReason = SelectionReason.unknown
@ -164,7 +163,7 @@ def _autoselect_wrapper() -> SelectionInfo:
return info
def _select_wrapper(args: Optional[argparse.Namespace]) -> SelectionInfo:
def _select_wrapper(args: argparse.Namespace | None) -> SelectionInfo:
"""Select a Qt wrapper.
- If --qt-wrapper is given, use that.

View File

@ -12,7 +12,7 @@ import functools
import datetime
import types
from typing import (
Any, Optional, Union)
Any, TypeAlias)
from collections.abc import Mapping, MutableSequence, Sequence, Callable
from qutebrowser.qt.core import Qt, QEvent, QMetaMethod, QObject, pyqtBoundSignal
@ -40,7 +40,7 @@ def log_events(klass: type[QObject]) -> type[QObject]:
return klass
def log_signals(obj: Union[QObject, type[QObject]]) -> Union[QObject, type[QObject]]:
def log_signals(obj: QObject | type[QObject]) -> QObject | type[QObject]:
"""Log all signals of an object or class.
Can be used as class decorator.
@ -89,15 +89,15 @@ def log_signals(obj: Union[QObject, type[QObject]]) -> Union[QObject, type[QObje
if machinery.IS_QT6:
_EnumValueType = Union[enum.Enum, int]
_EnumValueType: TypeAlias = enum.Enum | int
else:
_EnumValueType = Union[sip.simplewrapper, int]
_EnumValueType: TypeAlias = sip.simplewrapper | int
def _qenum_key_python(
value: _EnumValueType,
klass: type[_EnumValueType],
) -> Optional[str]:
) -> str | None:
"""New-style PyQt6: Try getting value from Python enum."""
if isinstance(value, enum.Enum) and value.name:
return value.name
@ -119,7 +119,7 @@ def _qenum_key_qt(
base: type[sip.simplewrapper],
value: _EnumValueType,
klass: type[_EnumValueType],
) -> Optional[str]:
) -> str | None:
# On PyQt5, or PyQt6 with int passed: Try to ask Qt's introspection.
# However, not every Qt enum value has a staticMetaObject
try:
@ -308,7 +308,7 @@ class log_time: # noqa: N801,N806 pylint: disable=invalid-name
Usable as context manager or as decorator.
"""
def __init__(self, logger: Union[logging.Logger, str],
def __init__(self, logger: logging.Logger | str,
action: str = 'operation') -> None:
"""Constructor.
@ -320,16 +320,16 @@ class log_time: # noqa: N801,N806 pylint: disable=invalid-name
self._logger = logging.getLogger(logger)
else:
self._logger = logger
self._started: Optional[datetime.datetime] = None
self._started: datetime.datetime | None = None
self._action = action
def __enter__(self) -> None:
self._started = datetime.datetime.now()
def __exit__(self,
_exc_type: Optional[type[BaseException]],
_exc_val: Optional[BaseException],
_exc_tb: Optional[types.TracebackType]) -> None:
_exc_type: type[BaseException] | None,
_exc_val: BaseException | None,
_exc_tb: types.TracebackType | None) -> None:
assert self._started is not None
finished = datetime.datetime.now()
delta = (finished - self._started).total_seconds()

View File

@ -10,7 +10,7 @@ import inspect
import os.path
import collections
import enum
from typing import Any, Optional, Union
from typing import Any
from collections.abc import MutableMapping, Callable
import qutebrowser
@ -81,11 +81,11 @@ class DocstringParser:
func: The function to parse the docstring for.
"""
self._state = self.State.short
self._cur_arg_name: Optional[str] = None
self._cur_arg_name: str | None = None
self._short_desc_parts: list[str] = []
self._long_desc_parts: list[str] = []
self.arg_descs: MutableMapping[
str, Union[str, list[str]]] = collections.OrderedDict()
str, str | list[str]] = collections.OrderedDict()
doc = inspect.getdoc(func)
handlers = {
self.State.short: self._parse_short,

View File

@ -4,11 +4,11 @@
"""Utilities related to javascript interaction."""
from typing import Union
from typing import TypeAlias
from collections.abc import Sequence
_InnerJsArgType = Union[None, str, bool, int, float]
_JsArgType = Union[_InnerJsArgType, Sequence[_InnerJsArgType]]
_InnerJsArgType: TypeAlias = None | str | bool | int | float
_JsArgType: TypeAlias = _InnerJsArgType | Sequence[_InnerJsArgType]
def string_escape(text: str) -> str:

View File

@ -32,7 +32,7 @@ if TYPE_CHECKING:
from qutebrowser.config import config as configmodule
_log_inited = False
_args: Optional[argparse.Namespace] = None
_args: argparse.Namespace | None = None
COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'purple', 'cyan', 'white']
COLOR_ESCAPES = {color: '\033[{}m'.format(i)
@ -146,7 +146,7 @@ LOGGER_NAMES = [
ram_handler: Optional['RAMHandler'] = None
console_handler: Optional[logging.Handler] = None
console_handler: logging.Handler | None = None
console_filter: Optional["LogFilter"] = None
@ -426,7 +426,7 @@ class LogFilter(logging.Filter):
self.only_debug = only_debug
@classmethod
def parse(cls, filter_str: Optional[str], *,
def parse(cls, filter_str: str | None, *,
only_debug: bool = True) -> 'LogFilter':
"""Parse a log filter from a string."""
if filter_str is None or filter_str == 'none':
@ -480,7 +480,7 @@ class RAMHandler(logging.Handler):
def __init__(self, capacity: int) -> None:
super().__init__()
self.html_formatter: Optional[HTMLFormatter] = None
self.html_formatter: HTMLFormatter | None = None
if capacity != -1:
self._data: MutableSequence[logging.LogRecord] = collections.deque(
maxlen=capacity

View File

@ -10,7 +10,7 @@
import dataclasses
import traceback
from typing import Any, Union, Optional
from typing import Any
from collections.abc import Iterable, Callable
from qutebrowser.qt.core import pyqtSignal, pyqtBoundSignal, QObject
@ -25,7 +25,7 @@ class MessageInfo:
level: usertypes.MessageLevel
text: str
replace: Optional[str] = None
replace: str | None = None
rich: bool = False
@ -108,7 +108,7 @@ def info(message: str, *, replace: str = None, rich: bool = False) -> None:
def _build_question(title: str,
text: str = None, *,
mode: usertypes.PromptMode,
default: Union[None, bool, str] = None,
default: None | bool | str = None,
abort_on: Iterable[pyqtBoundSignal] = (),
url: str = None,
option: bool = None) -> usertypes.Question:

View File

@ -8,7 +8,7 @@
import collections
import functools
from typing import (TYPE_CHECKING, Any,
Optional, Union)
TypeAlias)
from collections.abc import MutableMapping, MutableSequence, Sequence, Callable
from qutebrowser.qt.core import QObject, QTimer
@ -20,7 +20,7 @@ if TYPE_CHECKING:
from qutebrowser.mainwindow import mainwindow
_WindowTab = Union[str, int, None]
_WindowTab: TypeAlias = str | int | None
class RegistryUnavailableError(Exception):
@ -38,7 +38,7 @@ class CommandOnlyError(Exception):
"""Raised when an object is requested which is used for commands only."""
_IndexType = Union[str, int]
_IndexType: TypeAlias = str | int
# UserDict is only generic in Python 3.9+
@ -153,7 +153,7 @@ def _get_tab_registry(win_id: _WindowTab,
if tab_id is None:
raise ValueError("Got tab_id None (win_id {})".format(win_id))
if tab_id == 'current' and win_id is None:
window: Optional[QWidget] = QApplication.activeWindow()
window: QWidget | None = QApplication.activeWindow()
if window is None or not hasattr(window, 'win_id'):
raise RegistryUnavailableError('tab')
win_id = window.win_id
@ -179,7 +179,7 @@ def _get_window_registry(window: _WindowTab) -> ObjectRegistry:
raise TypeError("window is None with scope window!")
try:
if window == 'current':
win: Optional[QWidget] = QApplication.activeWindow()
win: QWidget | None = QApplication.activeWindow()
elif window == 'last-focused':
win = last_focused_window()
else:

View File

@ -10,13 +10,12 @@ import faulthandler
import logging
import sys
import traceback
from typing import Optional
from collections.abc import Iterator
from qutebrowser.qt import core as qtcore
from qutebrowser.utils import log
_args: Optional[argparse.Namespace] = None
_args: argparse.Namespace | None = None
def init(args: argparse.Namespace) -> None:
@ -43,7 +42,7 @@ def disable_qt_msghandler() -> Iterator[None]:
def qt_message_handler(msg_type: qtcore.QtMsgType,
context: qtcore.QMessageLogContext,
msg: Optional[str]) -> None:
msg: str | None) -> None:
"""Qt message handler to redirect qWarning etc. to the logging system.
Args:
@ -179,7 +178,7 @@ def qt_message_handler(msg_type: qtcore.QtMsgType,
assert _args is not None
if _args.debug:
stack: Optional[str] = ''.join(traceback.format_stack())
stack: str | None = ''.join(traceback.format_stack())
else:
stack = None

View File

@ -19,7 +19,7 @@ import pathlib
import operator
import contextlib
from typing import (Any, TYPE_CHECKING, BinaryIO, IO, Literal,
Optional, Union, Protocol, cast, overload, TypeVar)
Union, Protocol, cast, overload, TypeVar, TypeAlias)
from collections.abc import Iterator
from qutebrowser.qt import machinery, sip
@ -62,7 +62,7 @@ class QtOSError(OSError):
if msg is None:
msg = dev.errorString()
self.qt_errno: Optional[QFileDevice.FileError] = None
self.qt_errno: QFileDevice.FileError | None = None
if isinstance(dev, QFileDevice):
msg = self._init_filedev(dev, msg)
@ -207,7 +207,7 @@ def check_qdatastream(stream: QDataStream) -> None:
raise OSError(status_to_str[stream.status()])
_QtSerializableType = Union[
_QtSerializableType: TypeAlias = Union[
QObject,
QByteArray,
QUrl,
@ -271,7 +271,7 @@ def savefile_open(
filename: str,
binary: bool = False,
encoding: str = 'utf-8'
) -> Iterator[Union[IO[str], IO[bytes]]]:
) -> Iterator[IO[str] | IO[bytes]]:
"""Context manager to easily use a QSaveFile."""
f = QSaveFile(filename)
cancelled = False
@ -283,7 +283,7 @@ def savefile_open(
dev = cast(BinaryIO, PyQIODevice(f))
if binary:
new_f: Union[IO[str], IO[bytes]] = dev
new_f: IO[str] | IO[bytes] = dev
else:
new_f = io.TextIOWrapper(dev, encoding=encoding)
@ -405,7 +405,7 @@ class PyQIODevice(io.BufferedIOBase):
def readable(self) -> bool:
return self.dev.isReadable()
def readline(self, size: Optional[int] = -1) -> bytes:
def readline(self, size: int | None = -1) -> bytes:
self._check_open()
self._check_readable()
@ -416,7 +416,7 @@ class PyQIODevice(io.BufferedIOBase):
else:
qt_size = size + 1 # Qt also counts the NUL byte
buf: Union[QByteArray, bytes, None] = None
buf: QByteArray | bytes | None = None
if self.dev.canReadLine():
if qt_size is None:
buf = self.dev.readLine()
@ -450,7 +450,7 @@ class PyQIODevice(io.BufferedIOBase):
def write( # type: ignore[override]
self,
data: Union[bytes, bytearray]
data: bytes | bytearray
) -> int:
self._check_open()
self._check_writable()
@ -459,11 +459,11 @@ class PyQIODevice(io.BufferedIOBase):
raise QtOSError(self.dev)
return num
def read(self, size: Optional[int] = None) -> bytes:
def read(self, size: int | None = None) -> bytes:
self._check_open()
self._check_readable()
buf: Union[QByteArray, bytes, None] = None
buf: QByteArray | bytes | None = None
if size in [None, -1]:
buf = self.dev.readAll()
else:
@ -499,8 +499,7 @@ class QtValueError(ValueError):
if machinery.IS_QT6:
_ProcessEventFlagType = QEventLoop.ProcessEventsFlag
else:
_ProcessEventFlagType = Union[
QEventLoop.ProcessEventsFlag, QEventLoop.ProcessEventsFlags]
_ProcessEventFlagType: TypeAlias = QEventLoop.ProcessEventsFlag | QEventLoop.ProcessEventsFlags
class EventLoop(QEventLoop):
@ -559,7 +558,7 @@ def interpolate_color(
start: QColor,
end: QColor,
percent: int,
colorspace: Optional[QColor.Spec] = QColor.Spec.Rgb
colorspace: QColor.Spec | None = QColor.Spec.Rgb
) -> QColor:
"""Get an interpolated color value.
@ -677,7 +676,7 @@ def library_path(which: LibraryPath) -> pathlib.Path:
return pathlib.Path(ret)
def extract_enum_val(val: Union[sip.simplewrapper, int, enum.Enum]) -> int:
def extract_enum_val(val: sip.simplewrapper | int | enum.Enum) -> int:
"""Extract an int value from a Qt enum value.
For Qt 5, enum values are basically Python integers.
@ -691,7 +690,7 @@ def extract_enum_val(val: Union[sip.simplewrapper, int, enum.Enum]) -> int:
return val
def qobj_repr(obj: Optional[QObject]) -> str:
def qobj_repr(obj: QObject | None) -> str:
"""Show nicer debug information for a QObject."""
py_repr = repr(obj)
if obj is None:
@ -731,21 +730,21 @@ if machinery.IS_QT5:
# Also we have a special QT_NONE, which (being Any) we can pass to functions
# where PyQt type hints claim that it's not allowed.
def remove_optional(obj: Optional[_T]) -> _T:
def remove_optional(obj: _T | None) -> _T:
return cast(_T, obj)
def add_optional(obj: _T) -> Optional[_T]:
return cast(Optional[_T], obj)
def add_optional(obj: _T) -> _T | None:
return cast(_T | None, obj)
QT_NONE: Any = None
else:
# On Qt 6, all those things are handled correctly by type annotations, so we
# have a no-op below.
def remove_optional(obj: Optional[_T]) -> Optional[_T]:
def remove_optional(obj: _T | None) -> _T | None:
return obj
def add_optional(obj: Optional[_T]) -> Optional[_T]:
def add_optional(obj: _T | None) -> _T | None:
return obj
QT_NONE: None = None

View File

@ -10,7 +10,7 @@ import contextlib
import posixpath
import pathlib
import importlib.resources
from typing import Union
from typing import TypeAlias
from collections.abc import Iterator, Iterable
if sys.version_info >= (3, 11): # pragma: no cover
@ -24,7 +24,7 @@ _cache: dict[str, str] = {}
_bin_cache: dict[str, bytes] = {}
_ResourceType = Union[Traversable, pathlib.Path]
_ResourceType: TypeAlias = Traversable | pathlib.Path
def _path(filename: str) -> _ResourceType:

View File

@ -11,7 +11,6 @@ import contextlib
import enum
import argparse
import tempfile
from typing import Optional
from collections.abc import Iterator
from qutebrowser.qt.core import QStandardPaths
@ -62,7 +61,7 @@ def _unset_organization() -> Iterator[None]:
qapp.setOrganizationName(orgname)
def _init_config(args: Optional[argparse.Namespace]) -> None:
def _init_config(args: argparse.Namespace | None) -> None:
"""Initialize the location for configs."""
typ = QStandardPaths.StandardLocation.ConfigLocation
path = _from_args(typ, args)
@ -113,7 +112,7 @@ def config_py() -> str:
return _locations[_Location.config_py]
def _init_data(args: Optional[argparse.Namespace]) -> None:
def _init_data(args: argparse.Namespace | None) -> None:
"""Initialize the location for data."""
typ = QStandardPaths.StandardLocation.AppDataLocation
path = _from_args(typ, args)
@ -154,7 +153,7 @@ def data(system: bool = False) -> str:
return _locations[_Location.data]
def _init_cache(args: Optional[argparse.Namespace]) -> None:
def _init_cache(args: argparse.Namespace | None) -> None:
"""Initialize the location for the cache."""
typ = QStandardPaths.StandardLocation.CacheLocation
path = _from_args(typ, args)
@ -174,7 +173,7 @@ def cache() -> str:
return _locations[_Location.cache]
def _init_download(args: Optional[argparse.Namespace]) -> None:
def _init_download(args: argparse.Namespace | None) -> None:
"""Initialize the location for downloads.
Note this is only the default directory as found by Qt.
@ -191,7 +190,7 @@ def download() -> str:
return _locations[_Location.download]
def _init_runtime(args: Optional[argparse.Namespace]) -> None:
def _init_runtime(args: argparse.Namespace | None) -> None:
"""Initialize location for runtime data."""
if utils.is_mac or utils.is_windows:
# RuntimeLocation is a weird path on macOS and Windows.
@ -277,8 +276,8 @@ def _writable_location(typ: QStandardPaths.StandardLocation) -> str:
def _from_args(
typ: QStandardPaths.StandardLocation,
args: Optional[argparse.Namespace]
) -> Optional[str]:
args: argparse.Namespace | None
) -> str | None:
"""Get the standard directory from an argparse namespace.
Return:
@ -337,7 +336,7 @@ def _init_dirs(args: argparse.Namespace = None) -> None:
_init_runtime(args)
def init(args: Optional[argparse.Namespace]) -> None:
def init(args: argparse.Namespace | None) -> None:
"""Initialize all standard dirs."""
if args is not None:
# args can be None during tests

View File

@ -17,7 +17,7 @@ https://chromium.googlesource.com/chromium/src/+/6f4a6681eae01c2036336c18b06303e
import ipaddress
import fnmatch
import urllib.parse
from typing import Any, Optional
from typing import Any
from qutebrowser.qt.core import QUrl
@ -59,10 +59,10 @@ class UrlPattern:
self._pattern = pattern
self._match_all = False
self._match_subdomains: bool = False
self._scheme: Optional[str] = None
self.host: Optional[str] = None
self._path: Optional[str] = None
self._port: Optional[int] = None
self._scheme: str | None = None
self.host: str | None = None
self._path: str | None = None
self._port: int | None = None
# > The special pattern <all_urls> matches any URL that starts with a
# > permitted scheme.
@ -92,10 +92,10 @@ class UrlPattern:
def _to_tuple(self) -> tuple[
bool, # _match_all
bool, # _match_subdomains
Optional[str], # _scheme
Optional[str], # host
Optional[str], # _path
Optional[int], # _port
str | None, # _scheme
str | None, # host
str | None, # _path
int | None, # _port
]:
"""Get a pattern with information used for __eq__/__hash__."""
return (self._match_all, self._match_subdomains, self._scheme,

View File

@ -11,7 +11,7 @@ import ipaddress
import posixpath
import urllib.parse
import mimetypes
from typing import Optional, Union, cast
from typing import cast, TypeAlias
from collections.abc import Iterable
from qutebrowser.qt import machinery
@ -29,7 +29,7 @@ from qutebrowser.browser.network import pac
if machinery.IS_QT6:
UrlFlagsType = Union[QUrl.UrlFormattingOption, QUrl.ComponentFormattingOption]
UrlFlagsType: TypeAlias = QUrl.UrlFormattingOption | QUrl.ComponentFormattingOption
class FormatOption:
"""Simple wrapper around Qt enums to fix typing problems on Qt 5."""
@ -42,12 +42,7 @@ if machinery.IS_QT6:
REMOVE_PASSWORD = QUrl.UrlFormattingOption.RemovePassword
REMOVE_QUERY = QUrl.UrlFormattingOption.RemoveQuery
else:
UrlFlagsType = Union[
QUrl.FormattingOptions,
QUrl.UrlFormattingOption,
QUrl.ComponentFormattingOption,
QUrl.ComponentFormattingOptions,
]
UrlFlagsType: TypeAlias = QUrl.FormattingOptions | QUrl.UrlFormattingOption | QUrl.ComponentFormattingOption | QUrl.ComponentFormattingOptions
class _QtFormattingOptions(QUrl.FormattingOptions):
"""WORKAROUND for invalid stubs.
@ -112,7 +107,7 @@ class InvalidUrlError(Error):
super().__init__(self.msg)
def _parse_search_term(s: str) -> tuple[Optional[str], Optional[str]]:
def _parse_search_term(s: str) -> tuple[str | None, str | None]:
"""Get a search engine name and search term from a string.
Args:
@ -128,8 +123,8 @@ def _parse_search_term(s: str) -> tuple[Optional[str], Optional[str]]:
if len(split) == 2:
if split[0] in config.val.url.searchengines:
engine: Optional[str] = split[0]
term: Optional[str] = split[1]
engine: str | None = split[0]
term: str | None = split[1]
else:
engine = None
term = s
@ -390,7 +385,7 @@ def raise_cmdexc_if_invalid(url: QUrl) -> None:
def get_path_if_valid(pathstr: str,
cwd: str = None,
relative: bool = False,
check_exists: bool = False) -> Optional[str]:
check_exists: bool = False) -> str | None:
"""Check if path is a valid path.
Args:
@ -408,7 +403,7 @@ def get_path_if_valid(pathstr: str,
expanded = os.path.expanduser(pathstr)
if os.path.isabs(expanded):
path: Optional[str] = expanded
path: str | None = expanded
elif relative and cwd:
path = os.path.join(cwd, expanded)
elif relative:
@ -435,7 +430,7 @@ def get_path_if_valid(pathstr: str,
return path
def filename_from_url(url: QUrl, fallback: str = None) -> Optional[str]:
def filename_from_url(url: QUrl, fallback: str = None) -> str | None:
"""Get a suitable filename from a URL.
Args:
@ -616,7 +611,7 @@ class InvalidProxyTypeError(Exception):
super().__init__("Invalid proxy type {}!".format(typ))
def proxy_from_url(url: QUrl) -> Union[QNetworkProxy, pac.PACFetcher]:
def proxy_from_url(url: QUrl) -> QNetworkProxy | pac.PACFetcher:
"""Create a QNetworkProxy from QUrl and a proxy type.
Args:

View File

@ -10,7 +10,7 @@ import enum
import time
import dataclasses
import logging
from typing import Optional, TypeVar, Union
from typing import TypeVar
from collections.abc import Sequence
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, QTimer
@ -57,7 +57,7 @@ class NeighborList(Sequence[_T]):
exception = enum.auto()
def __init__(self, items: Sequence[_T] = None,
default: Union[_T, Unset] = UNSET,
default: _T | Unset = UNSET,
mode: Modes = Modes.exception) -> None:
"""Constructor.
@ -78,12 +78,12 @@ class NeighborList(Sequence[_T]):
if not isinstance(default, Unset):
idx = self._items.index(default)
self._idx: Optional[int] = idx
self._idx: int | None = idx
else:
self._idx = None
self._mode = mode
self.fuzzyval: Optional[int] = None
self.fuzzyval: int | None = None
def __getitem__(self, key: int) -> _T: # type: ignore[override]
return self._items[key]
@ -393,13 +393,13 @@ class Question(QObject):
def __init__(self, parent: QObject = None) -> None:
super().__init__(parent)
self.mode: Optional[PromptMode] = None
self.default: Union[bool, str, None] = None
self.title: Optional[str] = None
self.text: Optional[str] = None
self.url: Optional[str] = None
self.option: Optional[bool] = None
self.answer: Union[str, bool, None] = None
self.mode: PromptMode | None = None
self.default: bool | str | None = None
self.title: str | None = None
self.text: str | None = None
self.url: str | None = None
self.option: bool | None = None
self.answer: str | bool | None = None
self.is_aborted = False
self.interrupted = False
@ -446,7 +446,7 @@ class Timer(QTimer):
def __init__(self, parent: QObject = None, name: str = None) -> None:
super().__init__(parent)
self._start_time: Optional[float] = None
self._start_time: float | None = None
self.timeout.connect(self._validity_check_handler)
if name is None:
self._name = "unnamed"
@ -515,7 +515,7 @@ class AbstractCertificateErrorWrapper:
"""A wrapper over an SSL/certificate error."""
def __init__(self) -> None:
self._certificate_accepted: Optional[bool] = None
self._certificate_accepted: bool | None = None
def __str__(self) -> str:
raise NotImplementedError

View File

@ -20,8 +20,8 @@ import shlex
import sysconfig
import mimetypes
from typing import (Any, IO,
Optional, Union,
TypeVar, Protocol)
TypeVar, Protocol,
TypeAlias)
from collections.abc import Iterator, Sequence, Callable
from qutebrowser.qt.core import QUrl, QVersionNumber, QRect, QPoint
@ -40,7 +40,7 @@ except ImportError: # pragma: no cover
from qutebrowser.utils import log
fake_clipboard: Optional[str] = None
fake_clipboard: str | None = None
log_clipboard = False
is_mac = sys.platform.startswith('darwin')
@ -231,7 +231,7 @@ def format_seconds(total_seconds: int) -> str:
return prefix + ':'.join(chunks)
def format_size(size: Optional[float], base: int = 1024, suffix: str = '') -> str:
def format_size(size: float | None, base: int = 1024, suffix: str = '') -> str:
"""Format a byte size so it's human readable.
Inspired by https://stackoverflow.com/q/1094841
@ -408,7 +408,7 @@ def qualname(obj: Any) -> str:
return repr(obj)
_ExceptionType = Union[type[BaseException], tuple[type[BaseException]]]
_ExceptionType: TypeAlias = type[BaseException] | tuple[type[BaseException]]
def raises(exc: _ExceptionType, func: Callable[..., Any], *args: Any) -> bool:
@ -439,7 +439,7 @@ def force_encoding(text: str, encoding: str) -> str:
def sanitize_filename(name: str,
replacement: Optional[str] = '_',
replacement: str | None = '_',
shorten: bool = False) -> str:
"""Replace invalid filename characters.
@ -647,7 +647,7 @@ def expand_windows_drive(path: str) -> str:
return path
def yaml_load(f: Union[str, IO[str]]) -> Any:
def yaml_load(f: str | IO[str]) -> Any:
"""Wrapper over yaml.load using the C loader if possible."""
start = datetime.datetime.now()
@ -687,7 +687,7 @@ def yaml_load(f: Union[str, IO[str]]) -> Any:
return data
def yaml_dump(data: Any, f: IO[str] = None) -> Optional[str]:
def yaml_dump(data: Any, f: IO[str] = None) -> str | None:
"""Wrapper over yaml.dump using the C dumper if possible.
Also returns a str instead of bytes.
@ -777,7 +777,7 @@ def parse_duration(duration: str) -> int:
return milliseconds
def mimetype_extension(mimetype: str) -> Optional[str]:
def mimetype_extension(mimetype: str) -> str | None:
"""Get a suitable extension for a given mimetype.
This mostly delegates to Python's mimetypes.guess_extension(), but backports some
@ -876,7 +876,7 @@ def parse_point(s: str) -> QPoint:
raise ValueError(e)
def match_globs(patterns: list[str], value: str) -> Optional[str]:
def match_globs(patterns: list[str], value: str) -> str | None:
"""Match a list of glob-like patterns against a value.
Return:

View File

@ -19,8 +19,7 @@ import getpass
import functools
import dataclasses
import importlib.metadata
from typing import (Optional, ClassVar, Any,
TYPE_CHECKING)
from typing import (ClassVar, Any, TYPE_CHECKING)
from collections.abc import Mapping, Sequence
from qutebrowser.qt import machinery
@ -74,12 +73,12 @@ class DistributionInfo:
"""Information about the running distribution."""
id: Optional[str]
id: str | None
parsed: 'Distribution'
pretty: str
pastebin_url: Optional[str] = None
pastebin_url: str | None = None
class Distribution(enum.Enum):
@ -106,7 +105,7 @@ class Distribution(enum.Enum):
solus = enum.auto()
def _parse_os_release() -> Optional[dict[str, str]]:
def _parse_os_release() -> dict[str, str] | None:
"""Parse an /etc/os-release file."""
filename = os.environ.get('QUTE_FAKE_OS_RELEASE', '/etc/os-release')
info = {}
@ -124,7 +123,7 @@ def _parse_os_release() -> Optional[dict[str, str]]:
return info
def distribution() -> Optional[DistributionInfo]:
def distribution() -> DistributionInfo | None:
"""Get some information about the running Linux distribution.
Returns:
@ -178,7 +177,7 @@ def is_flatpak() -> bool:
_FLATPAK_INFO_PATH = '/.flatpak-info'
def flatpak_id() -> Optional[str]:
def flatpak_id() -> str | None:
"""Get the ID of the currently running Flatpak (or None if outside of Flatpak)."""
if 'FLATPAK_ID' in os.environ:
return os.environ['FLATPAK_ID']
@ -195,7 +194,7 @@ def flatpak_id() -> Optional[str]:
return parser['Application']['name']
def _git_str() -> Optional[str]:
def _git_str() -> str | None:
"""Try to find out git version.
Return:
@ -229,7 +228,7 @@ def _call_git(gitpath: str, *args: str) -> str:
stdout=subprocess.PIPE).stdout.decode('UTF-8').strip()
def _git_str_subprocess(gitpath: str) -> Optional[str]:
def _git_str_subprocess(gitpath: str) -> str | None:
"""Try to get the git commit ID and timestamp by calling git.
Args:
@ -296,13 +295,13 @@ class ModuleInfo:
self,
name: str,
version_attributes: Sequence[str],
min_version: Optional[str] = None
min_version: str | None = None
):
self.name = name
self._version_attributes = version_attributes
self.min_version = min_version
self._installed = False
self._version: Optional[str] = None
self._version: str | None = None
self._initialized = False
def _reset_cache(self) -> None:
@ -341,7 +340,7 @@ class ModuleInfo:
self._initialized = True
def get_version(self) -> Optional[str]:
def get_version(self) -> str | None:
"""Finds the module version if it exists."""
if not self._initialized:
self._initialize_info()
@ -353,7 +352,7 @@ class ModuleInfo:
self._initialize_info()
return self._installed
def is_outdated(self) -> Optional[bool]:
def is_outdated(self) -> bool | None:
"""Checks whether the module is outdated.
Return:
@ -505,7 +504,7 @@ def _pdfjs_version() -> str:
return '{} ({})'.format(pdfjs_version, file_path)
def _get_pyqt_webengine_qt_version() -> Optional[str]:
def _get_pyqt_webengine_qt_version() -> str | None:
"""Get the version of the PyQtWebEngine-Qt package.
With PyQtWebEngine 5.15.3, the QtWebEngine binary got split into its own
@ -541,10 +540,10 @@ class WebEngineVersions:
"""Version numbers for QtWebEngine and the underlying Chromium."""
webengine: utils.VersionNumber
chromium: Optional[str]
chromium: str | None
source: str
chromium_security: Optional[str] = None
chromium_major: Optional[int] = dataclasses.field(init=False)
chromium_security: str | None = None
chromium_major: int | None = dataclasses.field(init=False)
# Dates based on https://chromium.googlesource.com/chromium/src/+refs
_BASES: ClassVar[dict[int, str]] = {
@ -563,7 +562,7 @@ class WebEngineVersions:
}
# Dates based on https://chromereleases.googleblog.com/
_CHROMIUM_VERSIONS: ClassVar[dict[utils.VersionNumber, tuple[str, Optional[str]]]] = {
_CHROMIUM_VERSIONS: ClassVar[dict[utils.VersionNumber, tuple[str, str | None]]] = {
# ====== UNSUPPORTED =====
# Qt 5.12: Chromium 69
@ -734,7 +733,7 @@ class WebEngineVersions:
def _infer_chromium_version(
cls,
pyqt_webengine_version: utils.VersionNumber,
) -> tuple[Optional[str], Optional[str]]:
) -> tuple[str | None, str | None]:
"""Infer the Chromium version based on the PyQtWebEngine version.
Returns:
@ -762,8 +761,8 @@ class WebEngineVersions:
def from_api(
cls,
qtwe_version: str,
chromium_version: Optional[str],
chromium_security: Optional[str] = None,
chromium_version: str | None,
chromium_security: str | None = None,
) -> 'WebEngineVersions':
"""Get the versions based on the exact versions.
@ -1085,16 +1084,16 @@ class OpenGLInfo:
# The name of the vendor. Examples:
# - nouveau
# - "Intel Open Source Technology Center", "Intel", "Intel Inc."
vendor: Optional[str] = None
vendor: str | None = None
# The OpenGL version as a string. See tests for examples.
version_str: Optional[str] = None
version_str: str | None = None
# The parsed version as a (major, minor) tuple of ints
version: Optional[tuple[int, ...]] = None
version: tuple[int, ...] | None = None
# The vendor specific information following the version number
vendor_specific: Optional[str] = None
vendor_specific: str | None = None
def __str__(self) -> str:
if self.gles:
@ -1132,7 +1131,7 @@ class OpenGLInfo:
@functools.lru_cache(maxsize=1)
def opengl_info() -> Optional[OpenGLInfo]: # pragma: no cover
def opengl_info() -> OpenGLInfo | None: # pragma: no cover
"""Get the OpenGL vendor used.
This returns a string such as 'nouveau' or
@ -1147,7 +1146,7 @@ def opengl_info() -> Optional[OpenGLInfo]: # pragma: no cover
vendor, version = override.split(', ', maxsplit=1)
return OpenGLInfo.parse(vendor=vendor, version=version)
old_context: Optional[QOpenGLContext] = QOpenGLContext.currentContext()
old_context: QOpenGLContext | None = QOpenGLContext.currentContext()
old_surface = None if old_context is None else old_context.surface()
surface = QOffscreenSurface()

View File

@ -18,7 +18,7 @@ CACHE_PATH = pathlib.Path(tempfile.gettempdir(), "ublock-matches-cache.tsv")
ROWS_TO_USE = 30_000
def type_rename(type_str: str) -> Optional[str]:
def type_rename(type_str: str) -> str | None:
"""Use the same resource type names as QtWebEngine."""
if type_str == "other":
return "unknown"

View File

@ -25,8 +25,8 @@ def collect_tests():
@dataclasses.dataclass
class ParsedFile:
target: Optional[str]
qtwebengine_todo: Optional[str]
target: str | None
qtwebengine_todo: str | None
class InvalidFile(Exception):

View File

@ -375,7 +375,7 @@ def enum_members(base, enumtype):
}
def is_userns_restricted() -> Optional[bool]:
def is_userns_restricted() -> bool | None:
if not utils.is_linux:
return None

View File

@ -29,7 +29,7 @@ class FakeDBusMessage:
signature: str,
*arguments: Any,
typ: QDBusMessage.MessageType = QDBusMessage.MessageType.ReplyMessage,
error_name: Optional[str] = None,
error_name: str | None = None,
) -> None:
self._signature = signature
self._arguments = arguments
@ -170,7 +170,7 @@ class FakeNotificationAdapter(notification.AbstractNotificationAdapter):
def present(
self,
qt_notification: "QWebEngineNotification", *,
replaces_id: Optional[int],
replaces_id: int | None,
) -> int:
self.presented.append(qt_notification)
return next(self.id_gen)

View File

@ -28,10 +28,10 @@ class Key:
"""
attribute: str
name: Optional[str] = None
name: str | None = None
text: str = ''
uppertext: str = ''
member: Optional[int] = None
member: int | None = None
qtest: bool = True
def __post_init__(self):
@ -54,8 +54,8 @@ class Modifier:
"""
attribute: str
name: Optional[str] = None
member: Optional[int] = None
name: str | None = None
member: int | None = None
def __post_init__(self):
self.member = getattr(Qt.KeyboardModifier, self.attribute + 'Modifier')

View File

@ -632,7 +632,7 @@ class TestSendOrListen:
no_err_windows: bool
basedir: str
command: list[str]
target: Optional[str]
target: str | None
@pytest.fixture
def args(self):

View File

@ -210,7 +210,7 @@ def modules():
)
def test_autoselect(
stubs: Any,
available: dict[str, Union[bool, Exception]],
available: dict[str, bool | Exception],
expected: machinery.SelectionInfo,
monkeypatch: pytest.MonkeyPatch,
):
@ -222,9 +222,9 @@ def test_autoselect(
class SelectWrapperCase:
name: str
expected: machinery.SelectionInfo
args: Optional[argparse.Namespace] = None
env: Optional[str] = None
override: Optional[str] = None
args: argparse.Namespace | None = None
env: str | None = None
override: str | None = None
def __str__(self):
return self.name
@ -345,8 +345,8 @@ class TestSelectWrapper:
)
def test_autoselect_by_default(
self,
args: Optional[argparse.Namespace],
env: Optional[str],
args: argparse.Namespace | None,
env: str | None,
monkeypatch: pytest.MonkeyPatch,
):
"""Test that the default behavior is to autoselect a wrapper.