diff options
author | Ander Punnar <ander@kvlt.ee> | 2021-05-20 20:52:42 +0300 |
---|---|---|
committer | Ander Punnar <ander@kvlt.ee> | 2021-05-20 20:52:42 +0300 |
commit | 4e47af21586aad3846c2458dc0c8243e9d6eb792 (patch) | |
tree | 11b2073411b7decc68ba049bdfd4d97e8ab48343 /qutebrowser | |
parent | 2fc588358b27153721cc83e728e0d15b0e4d0d22 (diff) | |
parent | 90fbe1e181463379f38b8f0b01d488d1f7a586e0 (diff) | |
download | qutebrowser-4e47af21586aad3846c2458dc0c8243e9d6eb792.tar.gz qutebrowser-4e47af21586aad3846c2458dc0c8243e9d6eb792.zip |
Merge remote-tracking branch 'origin/master' into 4nd3r/hostblock_subdomains
Diffstat (limited to 'qutebrowser')
32 files changed, 206 insertions, 92 deletions
diff --git a/qutebrowser/__init__.py b/qutebrowser/__init__.py index 91a49d5b5..96062d9bd 100644 --- a/qutebrowser/__init__.py +++ b/qutebrowser/__init__.py @@ -26,7 +26,7 @@ __copyright__ = "Copyright 2014-2021 Florian Bruhin (The Compiler)" __license__ = "GPL" __maintainer__ = __author__ __email__ = "mail@qutebrowser.org" -__version__ = "2.2.1" +__version__ = "2.2.2" __version_info__ = tuple(int(part) for part in __version__.split('.')) __description__ = "A keyboard-driven, vim-like browser based on PyQt5." diff --git a/qutebrowser/api/cmdutils.py b/qutebrowser/api/cmdutils.py index 85a700c43..73c6a1bc5 100644 --- a/qutebrowser/api/cmdutils.py +++ b/qutebrowser/api/cmdutils.py @@ -105,6 +105,9 @@ def check_exclusive(flags: Iterable[bool], names: Iterable[str]) -> None: raise CommandError("Only one of {} can be given!".format(argstr)) +_CmdHandlerType = Callable[..., Any] + + class register: # noqa: N801,N806 pylint: disable=invalid-name """Decorator to register a new command handler.""" @@ -130,7 +133,7 @@ class register: # noqa: N801,N806 pylint: disable=invalid-name # The arguments to pass to Command. self._kwargs = kwargs - def __call__(self, func: Callable) -> Callable: + def __call__(self, func: _CmdHandlerType) -> _CmdHandlerType: """Register the command before running the function. Gets called when a function should be decorated. @@ -222,7 +225,7 @@ class argument: # noqa: N801,N806 pylint: disable=invalid-name self._argname = argname # The name of the argument to handle. self._kwargs = kwargs # Valid ArgInfo members. - def __call__(self, func: Callable) -> Callable: + def __call__(self, func: _CmdHandlerType) -> _CmdHandlerType: funcname = func.__name__ if self._argname not in inspect.signature(func).parameters: diff --git a/qutebrowser/api/hook.py b/qutebrowser/api/hook.py index eadc310f3..884d6c67f 100644 --- a/qutebrowser/api/hook.py +++ b/qutebrowser/api/hook.py @@ -22,13 +22,13 @@ """Hooks for extensions.""" import importlib -from typing import Callable +from typing import Callable, Any from qutebrowser.extensions import loader -def _add_module_info(func: Callable) -> loader.ModuleInfo: +def _add_module_info(func: Callable[..., Any]) -> loader.ModuleInfo: """Add module info to the given function.""" module = importlib.import_module(func.__module__) return loader.add_module_info(module) @@ -48,7 +48,7 @@ class init: message.info("Extension initialized.") """ - def __call__(self, func: Callable) -> Callable: + def __call__(self, func: loader.InitHookType) -> loader.InitHookType: info = _add_module_info(func) if info.init_hook is not None: raise ValueError("init hook is already registered!") @@ -86,7 +86,10 @@ class config_changed: def __init__(self, option_filter: str = None) -> None: self._filter = option_filter - def __call__(self, func: Callable) -> Callable: + def __call__( + self, + func: loader.ConfigChangedHookType, + ) -> loader.ConfigChangedHookType: info = _add_module_info(func) info.config_changed_hooks.append((self._filter, func)) return func diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index cbe698009..b3d1e85f7 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -34,9 +34,10 @@ from PyQt5.QtPrintSupport import QPrintDialog, QPrinter from PyQt5.QtNetwork import QNetworkAccessManager if TYPE_CHECKING: - from PyQt5.QtWebKit import QWebHistory + from PyQt5.QtWebKit import QWebHistory, QWebHistoryItem from PyQt5.QtWebKitWidgets import QWebPage - from PyQt5.QtWebEngineWidgets import QWebEngineHistory, QWebEnginePage + from PyQt5.QtWebEngineWidgets import ( + QWebEngineHistory, QWebEngineHistoryItem, QWebEnginePage) from qutebrowser.keyinput import modeman from qutebrowser.config import config @@ -634,8 +635,8 @@ class AbstractHistoryPrivate: """Deserialize from a format produced by self.serialize.""" raise NotImplementedError - def load_items(self, items: Sequence) -> None: - """Deserialize from a list of WebHistoryItems.""" + def load_items(self, items: Sequence[sessions.TabHistoryItem]) -> None: + """Deserialize from a list of TabHistoryItems.""" raise NotImplementedError @@ -651,7 +652,7 @@ class AbstractHistory: def __len__(self) -> int: raise NotImplementedError - def __iter__(self) -> Iterable: + def __iter__(self) -> Iterable[Union['QWebHistoryItem', 'QWebEngineHistoryItem']]: raise NotImplementedError def _check_count(self, count: int) -> None: diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index e9653ae19..8cd73ae4f 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -602,7 +602,7 @@ class CommandDispatcher: widget = self._current_widget() url = self._current_url() - handlers: Dict[str, Callable] = { + handlers: Dict[str, Callable[..., QUrl]] = { 'prev': functools.partial(navigate.prevnext, prev=True), 'next': functools.partial(navigate.prevnext, prev=False), 'up': navigate.path_up, diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py index cfb238188..031b6fe06 100644 --- a/qutebrowser/browser/qutescheme.py +++ b/qutebrowser/browser/qutescheme.py @@ -92,7 +92,8 @@ class Redirect(Exception): # Return value: (mimetype, data) (encoded as utf-8 if a str is returned) _HandlerRet = Tuple[str, Union[str, bytes]] -_Handler = TypeVar('_Handler', bound=Callable[[QUrl], _HandlerRet]) +_HandlerCallable = Callable[[QUrl], _HandlerRet] +_Handler = TypeVar('_Handler', bound=_HandlerCallable) class add_handler: # noqa: N801,N806 pylint: disable=invalid-name @@ -105,7 +106,7 @@ class add_handler: # noqa: N801,N806 pylint: disable=invalid-name def __init__(self, name: str) -> None: self._name = name - self._function: Optional[Callable] = None + self._function: Optional[_HandlerCallable] = None def __call__(self, function: _Handler) -> _Handler: self._function = function diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py index f53ad1afb..9ec29ce07 100644 --- a/qutebrowser/browser/webelem.py +++ b/qutebrowser/browser/webelem.py @@ -58,7 +58,8 @@ def css_selector(group: str, url: QUrl) -> str: return ','.join(selectors[group]) -class AbstractWebElement(collections.abc.MutableMapping): +# MutableMapping is only generic in Python 3.9+ +class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-arg] """A wrapper around QtWebKit/QtWebEngine web element.""" diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py index 50f73fca4..d8387e6d4 100644 --- a/qutebrowser/browser/webengine/notification.py +++ b/qutebrowser/browser/webengine/notification.py @@ -669,7 +669,8 @@ class _ServerCapabilities: def _as_uint32(x: int) -> QVariant: """Convert the given int to an uint32 for DBus.""" variant = QVariant(x) - assert variant.convert(QVariant.UInt) + successful = variant.convert(QVariant.UInt) + assert successful return variant diff --git a/qutebrowser/browser/webengine/tabhistory.py b/qutebrowser/browser/webengine/tabhistory.py index d6c795fb2..ab4b05fe9 100644 --- a/qutebrowser/browser/webengine/tabhistory.py +++ b/qutebrowser/browser/webengine/tabhistory.py @@ -35,10 +35,10 @@ HISTORY_STREAM_VERSION = 3 def _serialize_item(item, stream): - """Serialize a single WebHistoryItem into a QDataStream. + """Serialize a single TabHistoryItem into a QDataStream. Args: - item: The WebHistoryItem to write. + item: The TabHistoryItem to write. stream: The QDataStream to write to. """ # Thanks to Otter Browser: @@ -108,10 +108,10 @@ def _serialize_item(item, stream): def serialize(items): - """Serialize a list of WebHistoryItems to a data stream. + """Serialize a list of TabHistoryItems to a data stream. Args: - items: An iterable of WebHistoryItems. + items: An iterable of TabHistoryItems. Return: A (stream, data, user_data) tuple. diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 15784d6bf..c793a1929 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -983,6 +983,11 @@ class _Quirk: QWebEngineScript.DocumentCreation) world: QWebEngineScript.ScriptWorldId = QWebEngineScript.MainWorld predicate: bool = True + name: Optional[str] = None + + def __post_init__(self): + if self.name is None: + self.name = f"js-{self.filename.replace('_', '-')}" class _WebEngineScripts(QObject): @@ -1154,6 +1159,11 @@ class _WebEngineScripts(QObject): ), _Quirk('discord'), _Quirk( + 'googledocs', + # will be an UA quirk once we set the JS UA as well + name='ua-googledocs', + ), + _Quirk( 'string_replaceall', predicate=versions.webengine < utils.VersionNumber(5, 15, 3), ), @@ -1171,8 +1181,7 @@ class _WebEngineScripts(QObject): if not quirk.predicate: continue src = resources.read_file(f'javascript/quirks/{quirk.filename}.user.js') - name = f"js-{quirk.filename.replace('_', '-')}" - if name not in config.val.content.site_specific_quirks.skip: + if quirk.name not in config.val.content.site_specific_quirks.skip: self._inject_js( f'quirk_{quirk.filename}', src, diff --git a/qutebrowser/browser/webkit/tabhistory.py b/qutebrowser/browser/webkit/tabhistory.py index c38968b62..a707030d1 100644 --- a/qutebrowser/browser/webkit/tabhistory.py +++ b/qutebrowser/browser/webkit/tabhistory.py @@ -64,10 +64,10 @@ def _serialize_item(item): def serialize(items): - """Serialize a list of WebHistoryItems to a data stream. + """Serialize a list of TabHistoryItems to a data stream. Args: - items: An iterable of WebHistoryItems. + items: An iterable of TabHistoryItems. Return: A (stream, data, user_data) tuple. diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index 374019677..437a54a33 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -97,7 +97,10 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name else: return False - def __call__(self, func: Callable) -> Callable: + def __call__( + self, + func: Callable[..., None], + ) -> Callable[..., None]: """Filter calls to the decorated function. Gets called when a function should be decorated. @@ -105,7 +108,9 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name Adds a filter which returns if we're not interested in the change-event and calls the wrapped function if we are. - We assume the function passed doesn't take any parameters. + We assume the function passed doesn't take any parameters. However, it + could take a "self" argument, so we can't cleary express this in the + type above. Args: func: The function to be decorated. @@ -173,6 +178,8 @@ class KeyConfig: result = results[0] if result.cmd.name != "set-cmd-text": return cmdline + if not result.args: + return None # doesn't look like this sets a command *flags, cmd = result.args if "-a" in flags or "--append" in flags or not cmd.startswith(":"): return None # doesn't look like this sets a command @@ -307,7 +314,7 @@ class Config(QObject): def _init_values(self) -> None: """Populate the self._values dict.""" - self._values: Mapping = {} + self._values: Mapping[str, configutils.Values] = {} for name, opt in configdata.DATA.items(): self._values[name] = configutils.Values(opt) diff --git a/qutebrowser/config/configcommands.py b/qutebrowser/config/configcommands.py index 2084556da..143b02fca 100644 --- a/qutebrowser/config/configcommands.py +++ b/qutebrowser/config/configcommands.py @@ -21,7 +21,7 @@ import os.path import contextlib -from typing import TYPE_CHECKING, Iterator, List, Optional +from typing import TYPE_CHECKING, Iterator, List, Optional, Any, Tuple from PyQt5.QtCore import QUrl @@ -475,7 +475,7 @@ class ConfigCommands: raise cmdutils.CommandError("{} already exists - use --force to " "overwrite!".format(filename)) - options: List = [] + options: List[Tuple[Optional[urlmatch.UrlPattern], configdata.Option, Any]] = [] if defaults: options = [(None, opt, opt.default) for _name, opt in sorted(configdata.DATA.items())] diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 6cb277e5c..80732d43d 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -545,6 +545,7 @@ content.site_specific_quirks.skip: - ua-whatsapp - ua-google - ua-slack + - ua-googledocs - js-whatsapp-web - js-discord - js-string-replaceall @@ -3269,6 +3270,7 @@ fonts.tabs.unselected: fonts.web.family.standard: default: '' + supports_pattern: true type: name: FontFamily none_ok: true @@ -3276,6 +3278,7 @@ fonts.web.family.standard: fonts.web.family.fixed: default: '' + supports_pattern: true type: name: FontFamily none_ok: true @@ -3283,6 +3286,7 @@ fonts.web.family.fixed: fonts.web.family.serif: default: '' + supports_pattern: true type: name: FontFamily none_ok: true @@ -3290,6 +3294,7 @@ fonts.web.family.serif: fonts.web.family.sans_serif: default: '' + supports_pattern: true type: name: FontFamily none_ok: true @@ -3297,6 +3302,7 @@ fonts.web.family.sans_serif: fonts.web.family.cursive: default: '' + supports_pattern: true type: name: FontFamily none_ok: true @@ -3304,6 +3310,7 @@ fonts.web.family.cursive: fonts.web.family.fantasy: default: '' + supports_pattern: true type: name: FontFamily none_ok: true @@ -3316,6 +3323,7 @@ fonts.web.family.fantasy: fonts.web.size.default: default: 16 + supports_pattern: true type: name: Int minval: 1 @@ -3324,6 +3332,7 @@ fonts.web.size.default: fonts.web.size.default_fixed: default: 13 + supports_pattern: true type: name: Int minval: 1 @@ -3332,6 +3341,7 @@ fonts.web.size.default_fixed: fonts.web.size.minimum: default: 0 + supports_pattern: true type: name: Int minval: 0 @@ -3342,6 +3352,7 @@ fonts.web.size.minimum_logical: # This is 0 as default on QtWebKit, and 6 on QtWebEngine - so let's # just go for 6 here. default: 6 + supports_pattern: true type: name: Int minval: 0 diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index f8566e2d0..6f0d0b13c 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -30,7 +30,7 @@ import configparser import contextlib import re from typing import (TYPE_CHECKING, Any, Dict, Iterable, Iterator, List, Mapping, - MutableMapping, Optional, cast) + MutableMapping, Optional, Tuple, cast) import yaml from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QSettings, qVersion @@ -39,7 +39,7 @@ import qutebrowser from qutebrowser.config import (configexc, config, configdata, configutils, configtypes) from qutebrowser.keyinput import keyutils -from qutebrowser.utils import standarddir, utils, qtutils, log, urlmatch +from qutebrowser.utils import standarddir, utils, qtutils, log, urlmatch, version if TYPE_CHECKING: from qutebrowser.misc import savemanager @@ -89,6 +89,7 @@ class StateConfig(configparser.ConfigParser): self.read(self._filename, encoding='utf-8') self.qt_version_changed = False + self.qtwe_version_changed = False self.qutebrowser_version_changed = VersionChange.unknown self._set_changed_attributes() @@ -108,8 +109,20 @@ class StateConfig(configparser.ConfigParser): self[sect].pop(key, None) self['general']['qt_version'] = qVersion() + self['general']['qtwe_version'] = self._qtwe_version_str() self['general']['version'] = qutebrowser.__version__ + def _qtwe_version_str(self) -> str: + """Get the QtWebEngine version string. + + Note that it's too early to use objects.backend here... + """ + try: + import PyQt5.QtWebEngineWidgets # pylint: disable=unused-import + except ImportError: + return 'no' + return str(version.qtwebengine_versions(avoid_init=True).webengine) + def _set_changed_attributes(self) -> None: """Set qt_version_changed/qutebrowser_version_changed attributes. @@ -123,6 +136,9 @@ class StateConfig(configparser.ConfigParser): old_qt_version = self['general'].get('qt_version', None) self.qt_version_changed = old_qt_version != qVersion() + old_qtwe_version = self['general'].get('qtwe_version', None) + self.qtwe_version_changed = old_qtwe_version != self._qtwe_version_str() + old_qutebrowser_version = self['general'].get('version', None) if old_qutebrowser_version is None: # https://github.com/python/typeshed/issues/2093 @@ -286,18 +302,18 @@ class YamlConfig(QObject): self._validate_names(settings) self._build_values(settings) - def _load_settings_object(self, yaml_data: Any) -> '_SettingsType': + def _load_settings_object(self, yaml_data: Any) -> _SettingsType: """Load the settings from the settings: key.""" return self._pop_object(yaml_data, 'settings', dict) - def _load_legacy_settings_object(self, yaml_data: Any) -> '_SettingsType': + def _load_legacy_settings_object(self, yaml_data: Any) -> _SettingsType: data = self._pop_object(yaml_data, 'global', dict) settings = {} for name, value in data.items(): settings[name] = {'global': value} return settings - def _build_values(self, settings: Mapping) -> None: + def _build_values(self, settings: Mapping[str, Any]) -> None: """Build up self._values from the values in the given dict.""" errors = [] for name, yaml_values in settings.items(): @@ -724,9 +740,17 @@ class ConfigPyWriter: def __init__( self, - options: List, + options: List[ + Tuple[ + Optional[urlmatch.UrlPattern], + configdata.Option, + Any + ] + ], bindings: MutableMapping[str, Mapping[str, Optional[str]]], - *, commented: bool) -> None: + *, + commented: bool, + ) -> None: self._options = options self._bindings = bindings self._commented = commented diff --git a/qutebrowser/config/websettings.py b/qutebrowser/config/websettings.py index 1b07baab7..7556d2b6d 100644 --- a/qutebrowser/config/websettings.py +++ b/qutebrowser/config/websettings.py @@ -23,7 +23,7 @@ import re import argparse import functools import dataclasses -from typing import Any, Callable, Dict, Optional +from typing import Any, Callable, Dict, Optional, Union from PyQt5.QtCore import QUrl, pyqtSlot, qVersion from PyQt5.QtGui import QFont @@ -85,7 +85,11 @@ class AttributeInfo: """Info about a settings attribute.""" - def __init__(self, *attributes: Any, converter: Callable = None) -> None: + def __init__( + self, + *attributes: Any, + converter: Callable[[Any], bool] = None, + ) -> None: self.attributes = attributes if converter is None: self.converter = lambda val: val @@ -105,9 +109,6 @@ class AbstractSettings: def __init__(self, settings: Any) -> None: self._settings = settings - def _assert_not_unset(self, value: Any) -> None: - assert value is not usertypes.UNSET |