diff --git a/qutebrowser/api/cmdutils.py b/qutebrowser/api/cmdutils.py index 3939dbb0a..35b089a9f 100644 --- a/qutebrowser/api/cmdutils.py +++ b/qutebrowser/api/cmdutils.py @@ -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: ... diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 66bd485fc..02304bb34 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -234,7 +234,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 +296,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. diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 597b8d37c..54cc32c4e 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -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. diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index ebce4b37a..4258335dc 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -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: diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index bdbd910db..78fd997b0 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -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): diff --git a/qutebrowser/browser/downloadview.py b/qutebrowser/browser/downloadview.py index 5f67b344d..49d00c446 100644 --- a/qutebrowser/browser/downloadview.py +++ b/qutebrowser/browser/downloadview.py @@ -17,10 +17,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 +64,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: diff --git a/qutebrowser/browser/greasemonkey.py b/qutebrowser/browser/greasemonkey.py index ab63046db..b1c9f38a6 100644 --- a/qutebrowser/browser/greasemonkey.py +++ b/qutebrowser/browser/greasemonkey.py @@ -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. diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index b3f45610d..49b61c0e7 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -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) diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index ebcd26e72..298cf72f2 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -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: diff --git a/qutebrowser/browser/inspector.py b/qutebrowser/browser/inspector.py index e60e4a2b8..2b32acf2d 100644 --- a/qutebrowser/browser/inspector.py +++ b/qutebrowser/browser/inspector.py @@ -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') diff --git a/qutebrowser/browser/navigate.py b/qutebrowser/browser/navigate.py index 956f222b4..97f78f00d 100644 --- a/qutebrowser/browser/navigate.py +++ b/qutebrowser/browser/navigate.py @@ -79,7 +79,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) ) diff --git a/qutebrowser/browser/network/pac.py b/qutebrowser/browser/network/pac.py index 20516366e..34116ede0 100644 --- a/qutebrowser/browser/network/pac.py +++ b/qutebrowser/browser/network/pac.py @@ -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 diff --git a/qutebrowser/browser/qtnetworkdownloads.py b/qutebrowser/browser/qtnetworkdownloads.py index 3d3c0475a..db3b4a498 100644 --- a/qutebrowser/browser/qtnetworkdownloads.py +++ b/qutebrowser/browser/qtnetworkdownloads.py @@ -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 diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py index fa7970e6d..f829566f9 100644 --- a/qutebrowser/browser/qutescheme.py +++ b/qutebrowser/browser/qutescheme.py @@ -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: diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index ab72690b2..c0c9c540b 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -513,7 +513,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. diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py index 82960cc8d..4eed8be4c 100644 --- a/qutebrowser/browser/webelem.py +++ b/qutebrowser/browser/webelem.py @@ -20,12 +20,12 @@ if TYPE_CHECKING: from qutebrowser.browser import browsertab -JsValueType = Union[int, float, str, None] +JsValueType = int| float | str | None if machinery.IS_QT6: KeyboardModifierType = Qt.KeyboardModifier else: - KeyboardModifierType = Union[Qt.KeyboardModifiers, Qt.KeyboardModifier] + KeyboardModifierType = 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: diff --git a/qutebrowser/browser/webengine/darkmode.py b/qutebrowser/browser/webengine/darkmode.py index 88b71a8fe..536765efb 100644 --- a/qutebrowser/browser/webengine/darkmode.py +++ b/qutebrowser/browser/webengine/darkmode.py @@ -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 = str | usertypes.Unset _PREFERRED_COLOR_SCHEME_DEFINITIONS: MutableMapping[Variant, Mapping[_SettingValType, str]] = { Variant.qt_515_2: { # 0: no-preference (not exposed) diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py index 9037ff214..c89abd5b2 100644 --- a/qutebrowser/browser/webengine/notification.py +++ b/qutebrowser/browser/webengine/notification.py @@ -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 diff --git a/qutebrowser/browser/webengine/webengineelem.py b/qutebrowser/browser/webengine/webengineelem.py index f65044998..033a7c831 100644 --- a/qutebrowser/browser/webengine/webengineelem.py +++ b/qutebrowser/browser/webengine/webengineelem.py @@ -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. diff --git a/qutebrowser/browser/webengine/webengineinspector.py b/qutebrowser/browser/webengine/webengineinspector.py index d37f41ba5..0d241f416 100644 --- a/qutebrowser/browser/webengine/webengineinspector.py +++ b/qutebrowser/browser/webengine/webengineinspector.py @@ -61,7 +61,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.""" diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index 6680fa637..5e898c25b 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -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 diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index cae8fa300..fb9346dde 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -92,7 +92,7 @@ class WebEnginePrinting(browsertab.AbstractPrinting): if machinery.IS_QT5: - _FindFlagType = Union[QWebEnginePage.FindFlag, QWebEnginePage.FindFlags] + _FindFlagType = QWebEnginePage.FindFlag | QWebEnginePage.FindFlags else: _FindFlagType = QWebEnginePage.FindFlag @@ -1019,7 +1019,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: @@ -1375,7 +1375,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 = QWebEngineScript.ScriptWorldId | int if world is None: world_id: world_id_type = QWebEngineScript.ScriptWorldId.ApplicationWorld elif isinstance(world, int): diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py index 362f00ca0..dd41ce74f 100644 --- a/qutebrowser/browser/webengine/webview.py +++ b/qutebrowser/browser/webengine/webview.py @@ -314,8 +314,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] diff --git a/qutebrowser/browser/webkit/certificateerror.py b/qutebrowser/browser/webkit/certificateerror.py index 2c18af62e..7b1753ad8 100644 --- a/qutebrowser/browser/webkit/certificateerror.py +++ b/qutebrowser/browser/webkit/certificateerror.py @@ -21,7 +21,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 diff --git a/qutebrowser/browser/webkit/network/networkmanager.py b/qutebrowser/browser/webkit/network/networkmanager.py index a950d4239..7494e8d2b 100644 --- a/qutebrowser/browser/webkit/network/networkmanager.py +++ b/qutebrowser/browser/webkit/network/networkmanager.py @@ -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 diff --git a/qutebrowser/browser/webkit/webkitelem.py b/qutebrowser/browser/webkit/webkitelem.py index 6088a29d3..cfdcd8499 100644 --- a/qutebrowser/browser/webkit/webkitelem.py +++ b/qutebrowser/browser/webkit/webkitelem.py @@ -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 diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py index d89295440..98da8ca92 100644 --- a/qutebrowser/browser/webkit/webkittab.py +++ b/qutebrowser/browser/webkit/webkittab.py @@ -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() diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py index 620f6a4ae..42608476e 100644 --- a/qutebrowser/commands/command.py +++ b/qutebrowser/commands/command.py @@ -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: diff --git a/qutebrowser/completion/completionwidget.py b/qutebrowser/completion/completionwidget.py index c7e549f46..e41ca0b07 100644 --- a/qutebrowser/completion/completionwidget.py +++ b/qutebrowser/completion/completionwidget.py @@ -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 diff --git a/qutebrowser/completion/models/__init__.py b/qutebrowser/completion/models/__init__.py index a55a91215..186ed06cb 100644 --- a/qutebrowser/completion/models/__init__.py +++ b/qutebrowser/completion/models/__init__.py @@ -21,4 +21,4 @@ class BaseCategory(QAbstractItemModel): name: str columns_to_filter: Sequence[int] - delete_func: Optional[DeleteFuncType] = None + delete_func: DeleteFuncType | None = None diff --git a/qutebrowser/completion/models/completionmodel.py b/qutebrowser/completion/models/completionmodel.py index c0f6a86ff..5b7121a64 100644 --- a/qutebrowser/completion/models/completionmodel.py +++ b/qutebrowser/completion/models/completionmodel.py @@ -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): diff --git a/qutebrowser/completion/models/filepathcategory.py b/qutebrowser/completion/models/filepathcategory.py index 0b2d887b8..6296b393c 100644 --- a/qutebrowser/completion/models/filepathcategory.py +++ b/qutebrowser/completion/models/filepathcategory.py @@ -87,7 +87,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()] diff --git a/qutebrowser/completion/models/histcategory.py b/qutebrowser/completion/models/histcategory.py index 5b79b4ade..04db2d9b3 100644 --- a/qutebrowser/completion/models/histcategory.py +++ b/qutebrowser/completion/models/histcategory.py @@ -26,12 +26,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.""" diff --git a/qutebrowser/components/braveadblock.py b/qutebrowser/components/braveadblock.py index e140248a3..32cf23789 100644 --- a/qutebrowser/components/braveadblock.py +++ b/qutebrowser/components/braveadblock.py @@ -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: diff --git a/qutebrowser/components/misccommands.py b/qutebrowser/components/misccommands.py index b4eaa55d1..6d7ea9b40 100644 --- a/qutebrowser/components/misccommands.py +++ b/qutebrowser/components/misccommands.py @@ -34,7 +34,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 +48,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 +88,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 +193,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 +207,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 +257,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 +322,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: diff --git a/qutebrowser/components/readlinecommands.py b/qutebrowser/components/readlinecommands.py index a26f7ea4c..9732dca1c 100644 --- a/qutebrowser/components/readlinecommands.py +++ b/qutebrowser/components/readlinecommands.py @@ -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() diff --git a/qutebrowser/components/utils/blockutils.py b/qutebrowser/components/utils/blockutils.py index 154c04317..6a106a802 100644 --- a/qutebrowser/components/utils/blockutils.py +++ b/qutebrowser/components/utils/blockutils.py @@ -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 diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index d286bf733..1a9d9bc62 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -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: @@ -410,7 +410,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). diff --git a/qutebrowser/config/configcommands.py b/qutebrowser/config/configcommands.py index 9012cc2c4..44a4a0876 100644 --- a/qutebrowser/config/configcommands.py +++ b/qutebrowser/config/configcommands.py @@ -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) @@ -474,7 +474,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())] diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index d939f7ea6..ec09a0a14 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -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. diff --git a/qutebrowser/config/configexc.py b/qutebrowser/config/configexc.py index 85845f6fc..96216616b 100644 --- a/qutebrowser/config/configexc.py +++ b/qutebrowser/config/configexc.py @@ -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: diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index 3fcdd53d8..f2181cd72 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -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: diff --git a/qutebrowser/config/configinit.py b/qutebrowser/config/configinit.py index a08ddb619..4c783f89a 100644 --- a/qutebrowser/config/configinit.py +++ b/qutebrowser/config/configinit.py @@ -20,7 +20,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: diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index a64600652..ea2a8517c 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -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 = _Completions = Iterable[tuple[str, str]] | None +_StrUnset = str | usertypes.Unset +_UnsetNone = None | usertypes.Unset +_StrUnsetNone = 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 diff --git a/qutebrowser/config/configutils.py b/qutebrowser/config/configutils.py index 2aaef7a97..c36acee1a 100644 --- a/qutebrowser/config/configutils.py +++ b/qutebrowser/config/configutils.py @@ -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 = 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. diff --git a/qutebrowser/config/qtargs.py b/qutebrowser/config/qtargs.py index 9341b2004..47afe75aa 100644 --- a/qutebrowser/config/qtargs.py +++ b/qutebrowser/config/qtargs.py @@ -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,15 @@ 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 = ( + str + | Callable[ + [version.WebEngineVersions], + str | None, + ] +) + +_WEBENGINE_SETTINGS: dict[str, dict[Any, _SettingValueType | None]] = { 'qt.force_software_rendering': { 'software-opengl': None, 'qt-quick': None, diff --git a/qutebrowser/config/stylesheet.py b/qutebrowser/config/stylesheet.py index 258e26002..d5b7de7df 100644 --- a/qutebrowser/config/stylesheet.py +++ b/qutebrowser/config/stylesheet.py @@ -58,7 +58,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 +72,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 diff --git a/qutebrowser/config/websettings.py b/qutebrowser/config/websettings.py index 3913cb24e..5b9d15b56 100644 --- a/qutebrowser/config/websettings.py +++ b/qutebrowser/config/websettings.py @@ -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) diff --git a/qutebrowser/extensions/interceptors.py b/qutebrowser/extensions/interceptors.py index 31fc94e0d..5432c3f5c 100644 --- a/qutebrowser/extensions/interceptors.py +++ b/qutebrowser/extensions/interceptors.py @@ -55,7 +55,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 +63,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.""" diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py index a6917be35..22c5b031c 100644 --- a/qutebrowser/extensions/loader.py +++ b/qutebrowser/extensions/loader.py @@ -47,10 +47,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) diff --git a/qutebrowser/keyinput/basekeyparser.py b/qutebrowser/keyinput/basekeyparser.py index c97570369..cd796cc47 100644 --- a/qutebrowser/keyinput/basekeyparser.py +++ b/qutebrowser/keyinput/basekeyparser.py @@ -25,7 +25,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 +63,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: diff --git a/qutebrowser/keyinput/eventfilter.py b/qutebrowser/keyinput/eventfilter.py index a9e7e78aa..dfff2e62e 100644 --- a/qutebrowser/keyinput/eventfilter.py +++ b/qutebrowser/keyinput/eventfilter.py @@ -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: diff --git a/qutebrowser/keyinput/keyutils.py b/qutebrowser/keyinput/keyutils.py index 8bb63bbe6..31f11e263 100644 --- a/qutebrowser/keyinput/keyutils.py +++ b/qutebrowser/keyinput/keyutils.py @@ -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 = 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]) diff --git a/qutebrowser/keyinput/macros.py b/qutebrowser/keyinput/macros.py index 0eb7244d6..fd495e8cf 100644 --- a/qutebrowser/keyinput/macros.py +++ b/qutebrowser/keyinput/macros.py @@ -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) diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py index 681deeff6..1979d7540 100644 --- a/qutebrowser/keyinput/modeman.py +++ b/qutebrowser/keyinput/modeman.py @@ -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. diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py index 6e6821612..7b43f0ea1 100644 --- a/qutebrowser/mainwindow/mainwindow.py +++ b/qutebrowser/mainwindow/mainwindow.py @@ -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: diff --git a/qutebrowser/mainwindow/messageview.py b/qutebrowser/mainwindow/messageview.py index 66d065360..0cec7a148 100644 --- a/qutebrowser/mainwindow/messageview.py +++ b/qutebrowser/mainwindow/messageview.py @@ -22,7 +22,7 @@ class Message(QLabel): self, level: usertypes.MessageLevel, text: str, - replace: Optional[str], + replace: str | None, text_format: Qt.TextFormat, parent: QWidget = None, ) -> None: diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index c8045c0e8..3fef75708 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -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) diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index 988eed4a0..a79c527f2 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -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 diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py index e0938ae36..342653485 100644 --- a/qutebrowser/mainwindow/tabbedbrowser.py +++ b/qutebrowser/mainwindow/tabbedbrowser.py @@ -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. diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 8d50ac45d..750bd7889 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -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: diff --git a/qutebrowser/misc/backendproblem.py b/qutebrowser/misc/backendproblem.py index 9d9aef35c..1a62134fa 100644 --- a/qutebrowser/misc/backendproblem.py +++ b/qutebrowser/misc/backendproblem.py @@ -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: diff --git a/qutebrowser/misc/crashsignal.py b/qutebrowser/misc/crashsignal.py index 1b31536f8..03a983bd0 100644 --- a/qutebrowser/misc/crashsignal.py +++ b/qutebrowser/misc/crashsignal.py @@ -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, diff --git a/qutebrowser/misc/debugcachestats.py b/qutebrowser/misc/debugcachestats.py index b12995c5c..5fafd357d 100644 --- a/qutebrowser/misc/debugcachestats.py +++ b/qutebrowser/misc/debugcachestats.py @@ -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 diff --git a/qutebrowser/misc/elf.py b/qutebrowser/misc/elf.py index a012f4c69..9719bd676 100644 --- a/qutebrowser/misc/elf.py +++ b/qutebrowser/misc/elf.py @@ -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. diff --git a/qutebrowser/misc/guiprocess.py b/qutebrowser/misc/guiprocess.py index 2e4f33748..80d3795cd 100644 --- a/qutebrowser/misc/guiprocess.py +++ b/qutebrowser/misc/guiprocess.py @@ -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 = "" diff --git a/qutebrowser/misc/ipc.py b/qutebrowser/misc/ipc.py index eefa2e3f3..43382579a 100644 --- a/qutebrowser/misc/ipc.py +++ b/qutebrowser/misc/ipc.py @@ -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 diff --git a/qutebrowser/misc/miscwidgets.py b/qutebrowser/misc/miscwidgets.py index 7ca409afe..fe5f234ea 100644 --- a/qutebrowser/misc/miscwidgets.py +++ b/qutebrowser/misc/miscwidgets.py @@ -192,8 +192,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 +310,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 +439,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) diff --git a/qutebrowser/misc/nativeeventfilter.py b/qutebrowser/misc/nativeeventfilter.py index e93b3c6d1..5dded60ff 100644 --- a/qutebrowser/misc/nativeeventfilter.py +++ b/qutebrowser/misc/nativeeventfilter.py @@ -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 diff --git a/qutebrowser/misc/pakjoy.py b/qutebrowser/misc/pakjoy.py index 87b84789b..8056be8a2 100644 --- a/qutebrowser/misc/pakjoy.py +++ b/qutebrowser/misc/pakjoy.py @@ -124,7 +124,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) @@ -207,7 +207,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 @@ -262,7 +262,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] diff --git a/qutebrowser/misc/sessions.py b/qutebrowser/misc/sessions.py index b487fcd2c..6ca6db7d1 100644 --- a/qutebrowser/misc/sessions.py +++ b/qutebrowser/misc/sessions.py @@ -37,7 +37,7 @@ class Sentinel: default = Sentinel() session_manager = cast('SessionManager', None) -ArgType = Union[str, Sentinel] +ArgType = 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, ) diff --git a/qutebrowser/misc/sql.py b/qutebrowser/misc/sql.py index e2140c242..e6e9bfb51 100644 --- a/qutebrowser/misc/sql.py +++ b/qutebrowser/misc/sql.py @@ -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. diff --git a/qutebrowser/misc/throttle.py b/qutebrowser/misc/throttle.py index 78bc7f29b..eb3da327e 100644 --- a/qutebrowser/misc/throttle.py +++ b/qutebrowser/misc/throttle.py @@ -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) diff --git a/qutebrowser/misc/utilcmds.py b/qutebrowser/misc/utilcmds.py index 548c1e54b..ca7bcfc6e 100644 --- a/qutebrowser/misc/utilcmds.py +++ b/qutebrowser/misc/utilcmds.py @@ -264,7 +264,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) diff --git a/qutebrowser/qt/machinery.py b/qutebrowser/qt/machinery.py index f39fb7d7f..d99bfd8b7 100644 --- a/qutebrowser/qt/machinery.py +++ b/qutebrowser/qt/machinery.py @@ -105,7 +105,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 +164,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. diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py index 131639127..060af72c9 100644 --- a/qutebrowser/utils/debug.py +++ b/qutebrowser/utils/debug.py @@ -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 = enum.Enum | int else: - _EnumValueType = Union[sip.simplewrapper, int] + _EnumValueType = 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() diff --git a/qutebrowser/utils/docutils.py b/qutebrowser/utils/docutils.py index c357a2cd4..d4894fea9 100644 --- a/qutebrowser/utils/docutils.py +++ b/qutebrowser/utils/docutils.py @@ -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, diff --git a/qutebrowser/utils/javascript.py b/qutebrowser/utils/javascript.py index 66470155a..7a2770f11 100644 --- a/qutebrowser/utils/javascript.py +++ b/qutebrowser/utils/javascript.py @@ -7,8 +7,8 @@ from typing import Union from collections.abc import Sequence -_InnerJsArgType = Union[None, str, bool, int, float] -_JsArgType = Union[_InnerJsArgType, Sequence[_InnerJsArgType]] +_InnerJsArgType = None | str | bool | int | float +_JsArgType = _InnerJsArgType | Sequence[_InnerJsArgType] def string_escape(text: str) -> str: diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py index 01701b3b5..ae8d02d95 100644 --- a/qutebrowser/utils/log.py +++ b/qutebrowser/utils/log.py @@ -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 diff --git a/qutebrowser/utils/message.py b/qutebrowser/utils/message.py index 8fc8f6fbe..866aed8c5 100644 --- a/qutebrowser/utils/message.py +++ b/qutebrowser/utils/message.py @@ -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: diff --git a/qutebrowser/utils/objreg.py b/qutebrowser/utils/objreg.py index c027b3cf6..e1b06d039 100644 --- a/qutebrowser/utils/objreg.py +++ b/qutebrowser/utils/objreg.py @@ -20,7 +20,7 @@ if TYPE_CHECKING: from qutebrowser.mainwindow import mainwindow -_WindowTab = Union[str, int, None] +_WindowTab = 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 = 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: diff --git a/qutebrowser/utils/qtlog.py b/qutebrowser/utils/qtlog.py index 775895ed3..90fd66a89 100644 --- a/qutebrowser/utils/qtlog.py +++ b/qutebrowser/utils/qtlog.py @@ -16,7 +16,7 @@ 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 +43,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 +179,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 diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index d55f9bc2f..62f78d6db 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -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) @@ -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,9 @@ class QtValueError(ValueError): if machinery.IS_QT6: _ProcessEventFlagType = QEventLoop.ProcessEventsFlag else: - _ProcessEventFlagType = Union[ - QEventLoop.ProcessEventsFlag, QEventLoop.ProcessEventsFlags] + _ProcessEventFlagType = ( + QEventLoop.ProcessEventsFlag + | QEventLoop.ProcessEventsFlags ) class EventLoop(QEventLoop): @@ -559,7 +560,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 +678,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 +692,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 +732,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 diff --git a/qutebrowser/utils/resources.py b/qutebrowser/utils/resources.py index 35fd62f75..be00f0b93 100644 --- a/qutebrowser/utils/resources.py +++ b/qutebrowser/utils/resources.py @@ -24,7 +24,7 @@ _cache: dict[str, str] = {} _bin_cache: dict[str, bytes] = {} -_ResourceType = Union[Traversable, pathlib.Path] +_ResourceType = Traversable | pathlib.Path def _path(filename: str) -> _ResourceType: diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py index b82845a96..d80140103 100644 --- a/qutebrowser/utils/standarddir.py +++ b/qutebrowser/utils/standarddir.py @@ -62,7 +62,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 +113,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 +154,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 +174,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 +191,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 +277,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 +337,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 diff --git a/qutebrowser/utils/urlmatch.py b/qutebrowser/utils/urlmatch.py index 1a558f307..72ef735cb 100644 --- a/qutebrowser/utils/urlmatch.py +++ b/qutebrowser/utils/urlmatch.py @@ -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 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, diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py index 839fdbe84..81301c68c 100644 --- a/qutebrowser/utils/urlutils.py +++ b/qutebrowser/utils/urlutils.py @@ -29,7 +29,7 @@ from qutebrowser.browser.network import pac if machinery.IS_QT6: - UrlFlagsType = Union[QUrl.UrlFormattingOption, QUrl.ComponentFormattingOption] + UrlFlagsType = QUrl.UrlFormattingOption | QUrl.ComponentFormattingOption class FormatOption: """Simple wrapper around Qt enums to fix typing problems on Qt 5.""" @@ -42,12 +42,12 @@ 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 = ( + QUrl.FormattingOptions + | QUrl.UrlFormattingOption + | QUrl.ComponentFormattingOption + | QUrl.ComponentFormattingOptions + ) class _QtFormattingOptions(QUrl.FormattingOptions): """WORKAROUND for invalid stubs. @@ -112,7 +112,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 +128,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 +390,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 +408,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 +435,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 +616,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: diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py index c8e92bf17..418b03135 100644 --- a/qutebrowser/utils/usertypes.py +++ b/qutebrowser/utils/usertypes.py @@ -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 diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py index 37a72c07b..577674274 100644 --- a/qutebrowser/utils/utils.py +++ b/qutebrowser/utils/utils.py @@ -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 = 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: diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py index 9189be381..a47f3f214 100644 --- a/qutebrowser/utils/version.py +++ b/qutebrowser/utils/version.py @@ -74,12 +74,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 +106,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 +124,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 +178,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 +195,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 +229,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 +296,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 +341,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 +353,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 +505,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 +541,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 +563,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 @@ -732,7 +732,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: @@ -760,8 +760,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. @@ -1036,16 +1036,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: @@ -1083,7 +1083,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 @@ -1098,7 +1098,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() diff --git a/run_profile.py.lprof b/run_profile.py.lprof new file mode 100644 index 000000000..c02063883 Binary files /dev/null and b/run_profile.py.lprof differ diff --git a/tests/end2end/data/brave-adblock/generate.py b/tests/end2end/data/brave-adblock/generate.py index 1dae5b6e5..cb32b7178 100644 --- a/tests/end2end/data/brave-adblock/generate.py +++ b/tests/end2end/data/brave-adblock/generate.py @@ -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" diff --git a/tests/end2end/test_hints_html.py b/tests/end2end/test_hints_html.py index bd787bc4a..532b91fad 100644 --- a/tests/end2end/test_hints_html.py +++ b/tests/end2end/test_hints_html.py @@ -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): diff --git a/tests/helpers/testutils.py b/tests/helpers/testutils.py index 9b13b9dfe..abf81b966 100644 --- a/tests/helpers/testutils.py +++ b/tests/helpers/testutils.py @@ -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 diff --git a/tests/unit/browser/test_notification.py b/tests/unit/browser/test_notification.py index 6c888f084..b7d98eb91 100644 --- a/tests/unit/browser/test_notification.py +++ b/tests/unit/browser/test_notification.py @@ -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) diff --git a/tests/unit/keyinput/key_data.py b/tests/unit/keyinput/key_data.py index 5b05252f2..f8cbd19eb 100644 --- a/tests/unit/keyinput/key_data.py +++ b/tests/unit/keyinput/key_data.py @@ -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') diff --git a/tests/unit/misc/test_ipc.py b/tests/unit/misc/test_ipc.py index f611428af..fd7472790 100644 --- a/tests/unit/misc/test_ipc.py +++ b/tests/unit/misc/test_ipc.py @@ -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): diff --git a/tests/unit/test_qt_machinery.py b/tests/unit/test_qt_machinery.py index 677494ee5..ea193767c 100644 --- a/tests/unit/test_qt_machinery.py +++ b/tests/unit/test_qt_machinery.py @@ -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.