summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2021-05-19 13:15:09 +0200
committerFlorian Bruhin <me@the-compiler.org>2021-05-19 13:15:09 +0200
commitc01b47f27b46a8568096977363b38b01d138749c (patch)
treed0b47c3e9bebc757638f57a17a20e2cbc0332d15
parent06e49efd3d9f21058893a0c3751aa05caaf0e2f8 (diff)
downloadqutebrowser-c01b47f27b46a8568096977363b38b01d138749c.tar.gz
qutebrowser-c01b47f27b46a8568096977363b38b01d138749c.zip
mypy: Set disallow_any_generics
See #6100
-rw-r--r--.mypy.ini6
-rw-r--r--qutebrowser/api/cmdutils.py7
-rw-r--r--qutebrowser/api/hook.py11
-rw-r--r--qutebrowser/browser/browsertab.py11
-rw-r--r--qutebrowser/browser/commands.py2
-rw-r--r--qutebrowser/browser/qutescheme.py5
-rw-r--r--qutebrowser/browser/webelem.py2
-rw-r--r--qutebrowser/browser/webengine/tabhistory.py8
-rw-r--r--qutebrowser/browser/webkit/tabhistory.py4
-rw-r--r--qutebrowser/config/config.py11
-rw-r--r--qutebrowser/config/configcommands.py4
-rw-r--r--qutebrowser/config/configfiles.py20
-rw-r--r--qutebrowser/config/websettings.py6
-rw-r--r--qutebrowser/extensions/loader.py13
-rw-r--r--qutebrowser/keyinput/basekeyparser.py2
-rw-r--r--qutebrowser/keyinput/keyutils.py2
-rw-r--r--qutebrowser/misc/debugcachestats.py2
-rw-r--r--qutebrowser/misc/elf.py4
-rw-r--r--qutebrowser/misc/throttle.py2
-rw-r--r--qutebrowser/utils/debug.py34
-rw-r--r--qutebrowser/utils/docutils.py4
-rw-r--r--qutebrowser/utils/objreg.py3
-rw-r--r--qutebrowser/utils/qtutils.py13
-rw-r--r--qutebrowser/utils/urlmatch.py9
-rw-r--r--qutebrowser/utils/utils.py9
25 files changed, 125 insertions, 69 deletions
diff --git a/.mypy.ini b/.mypy.ini
index b1cd8967c..289f3eb87 100644
--- a/.mypy.ini
+++ b/.mypy.ini
@@ -3,7 +3,7 @@ python_version = 3.6
### --strict
warn_unused_configs = True
-# disallow_any_generics = True
+disallow_any_generics = True
disallow_subclassing_any = True
# disallow_untyped_calls = True
# disallow_untyped_defs = True
@@ -83,6 +83,10 @@ disallow_untyped_defs = True
[mypy-qutebrowser.config.*]
disallow_untyped_defs = True
+[mypy-qutebrowser.config.configtypes]
+# Needs some major work to use specific generics
+disallow_any_generics = False
+
[mypy-qutebrowser.api.*]
disallow_untyped_defs = True
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..11c95e4cd 100644
--- a/qutebrowser/browser/webelem.py
+++ b/qutebrowser/browser/webelem.py
@@ -58,7 +58,7 @@ def css_selector(group: str, url: QUrl) -> str:
return ','.join(selectors[group])
-class AbstractWebElement(collections.abc.MutableMapping):
+class AbstractWebElement(collections.abc.MutableMapping[str, str]):
"""A wrapper around QtWebKit/QtWebEngine web element."""
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/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 69f3ca2cc..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.
@@ -309,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/configfiles.py b/qutebrowser/config/configfiles.py
index a3320c5c1..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
@@ -302,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():
@@ -740,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 896f7639c..7556d2b6d 100644
--- a/qutebrowser/config/websettings.py
+++ b/qutebrowser/config/websettings.py
@@ -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
diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py
index 9b704c94d..7ae45023b 100644
--- a/qutebrowser/extensions/loader.py
+++ b/qutebrowser/extensions/loader.py
@@ -39,6 +39,9 @@ from qutebrowser.misc import objects
# ModuleInfo objects for all loaded plugins
_module_infos = []
+InitHookType = Callable[['InitContext'], None]
+ConfigChangedHookType = Callable[[], None]
+
@dataclasses.dataclass
class InitContext:
@@ -59,9 +62,13 @@ class ModuleInfo:
"""
skip_hooks: bool = False
- init_hook: Optional[Callable] = None
- config_changed_hooks: List[Tuple[Optional[str], Callable]] = dataclasses.field(
- default_factory=list)
+ init_hook: Optional[InitHookType] = None
+ config_changed_hooks: List[
+ Tuple[
+ Optional[str],
+ ConfigChangedHookType,
+ ]
+ ] = dataclasses.field(default_factory=list)
@dataclasses.dataclass
diff --git a/qutebrowser/keyinput/basekeyparser.py b/qutebrowser/keyinput/basekeyparser.py
index d1828791c..7e688dab1 100644
--- a/qutebrowser/keyinput/basekeyparser.py
+++ b/qutebrowser/keyinput/basekeyparser.py
@@ -112,7 +112,7 @@ class BindingTrie:
return lines
- def update(self, mapping: Mapping) -> None:
+ def update(self, mapping: Mapping[keyutils.KeySequence, str]) -> None:
"""Add data from the given mapping to the trie."""
for key in mapping:
self[key] = mapping[key]
diff --git a/qutebrowser/keyinput/keyutils.py b/qutebrowser/keyinput/keyutils.py
index ddf818708..6bd8c99b8 100644
--- a/qutebrowser/keyinput/keyutils.py
+++ b/qutebrowser/keyinput/keyutils.py
@@ -458,7 +458,7 @@ class KeySequence:
assert self
self._validate()
- def _convert_key(self, key: Qt.Key) -> int:
+ def _convert_key(self, key: Union[int, Qt.KeyboardModifiers]) -> int:
"""Convert a single key for QKeySequence."""
assert isinstance(key, (int, Qt.KeyboardModifiers)), key
return int(key)
diff --git a/qutebrowser/misc/debugcachestats.py b/qutebrowser/misc/debugcachestats.py
index f172f0854..2004ad7ab 100644
--- a/qutebrowser/misc/debugcachestats.py
+++ b/qutebrowser/misc/debugcachestats.py
@@ -30,7 +30,7 @@ from typing import Any, Callable, List, Optional, Tuple, TypeVar
_CACHE_FUNCTIONS: List[Tuple[str, Any]] = []
-_T = TypeVar('_T', bound=Callable)
+_T = TypeVar('_T', bound=Callable[..., Any])
def register(name: Optional[str] = None) -> Callable[[_T], _T]:
diff --git a/qutebrowser/misc/elf.py b/qutebrowser/misc/elf.py
index 307d3b4ac..bf824880a 100644
--- a/qutebrowser/misc/elf.py
+++ b/qutebrowser/misc/elf.py
@@ -65,7 +65,7 @@ import re
import dataclasses
import mmap
import pathlib
-from typing import IO, ClassVar, Dict, Optional, Tuple, cast
+from typing import Any, IO, ClassVar, Dict, Optional, Tuple, cast
from PyQt5.QtCore import QLibraryInfo
@@ -93,7 +93,7 @@ class Endianness(enum.Enum):
big = 2
-def _unpack(fmt: str, fobj: IO[bytes]) -> Tuple:
+def _unpack(fmt: str, fobj: IO[bytes]) -> Tuple[Any, ...]:
"""Unpack the given struct format from the given file."""
size = struct.calcsize(fmt)
data = _safe_read(fobj, size)
diff --git a/qutebrowser/misc/throttle.py b/qutebrowser/misc/throttle.py
index 1beebe1aa..ac565b68d 100644
--- a/qutebrowser/misc/throttle.py
+++ b/qutebrowser/misc/throttle.py
@@ -45,7 +45,7 @@ class Throttle(QObject):
"""
def __init__(self,
- func: Callable,
+ func: Callable[..., None],
delay_ms: int,
parent: QObject = None) -> None:
"""Constructor.
diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py
index 54fcd5aa9..7d069909a 100644
--- a/qutebrowser/utils/debug.py
+++ b/qutebrowser/utils/debug.py
@@ -35,7 +35,7 @@ from qutebrowser.misc import objects
from qutebrowser.qt import sip
-def log_events(klass: Type) -> Type:
+def log_events(klass: Type[QObject]) -> Type[QObject]:
"""Class decorator to log Qt events."""
old_event = klass.event
@@ -46,7 +46,7 @@ def log_events(klass: Type) -> Type:
qenum_key(QEvent, e.type())))
return old_event(self, e)
- klass.event = new_event
+ klass.event = new_event # type: ignore[assignment]
return klass
@@ -96,10 +96,13 @@ def log_signals(obj: QObject) -> QObject:
return obj
-def qenum_key(base: Type,
- value: Union[int, sip.simplewrapper],
+_EnumValueType = Union[sip.simplewrapper, int]
+
+
+def qenum_key(base: Type[_EnumValueType],
+ value: _EnumValueType,
add_base: bool = False,
- klass: Type = None) -> str:
+ klass: Type[_EnumValueType] = None) -> str:
"""Convert a Qt Enum value to its key as a string.
Args:
@@ -119,8 +122,9 @@ def qenum_key(base: Type,
raise TypeError("Can't guess enum class of an int!")
try:
- idx = base.staticMetaObject.indexOfEnumerator(klass.__name__)
- meta_enum = base.staticMetaObject.enumerator(idx)
+ meta_obj = base.staticMetaObject # type: ignore[union-attr]
+ idx = meta_obj.indexOfEnumerator(klass.__name__)
+ meta_enum = meta_obj.enumerator(idx)
ret = meta_enum.valueToKey(int(value)) # type: ignore[arg-type]
except AttributeError:
ret = None
@@ -139,10 +143,10 @@ def qenum_key(base: Type,
return ret
-def qflags_key(base: Type,
- value: Union[int, sip.simplewrapper],
+def qflags_key(base: Type[_EnumValueType],
+ value: _EnumValueType,
add_base: bool = False,
- klass: Type = None) -> str:
+ klass: Type[_EnumValueType] = None) -> str:
"""Convert a Qt QFlags value to its keys as string.
Note: Passing a combined value (such as Qt.AlignCenter) will get the names
@@ -220,7 +224,7 @@ def signal_name(sig: pyqtBoundSignal) -> str:
return m.group('name')
-def format_args(args: Sequence = None, kwargs: Mapping = None) -> str:
+def format_args(args: Sequence[Any] = None, kwargs: Mapping[str, Any] = None) -> str:
"""Format a list of arguments/kwargs to a function-call like string."""
if args is not None:
arglist = [utils.compact_text(repr(arg), 200) for arg in args]
@@ -245,9 +249,9 @@ def dbg_signal(sig: pyqtBoundSignal, args: Any) -> str:
return '{}({})'.format(signal_name(sig), format_args(args))
-def format_call(func: Callable,
- args: Sequence = None,
- kwargs: Mapping = None,
+def format_call(func: Callable[..., Any],
+ args: Sequence[Any] = None,
+ kwargs: Mapping[str, Any] = None,
full: bool = True) -> str:
"""Get a string representation of a function calls with the given args.
@@ -302,7 +306,7 @@ class log_time: # noqa: N801,N806 pylint: disable=invalid-name
self._logger.debug("{} took {} seconds.".format(
self._action.capitalize(), delta))
- def __call__(self, func: Callable) -> Callable:
+ def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
@functools.wraps(func)
def wrapped(*args: Any, **kwargs: Any) -> Any:
"""Call the original function."""
diff --git a/qutebrowser/utils/docutils.py b/qutebrowser/utils/docutils.py
index 202fcba95..89e799c89 100644
--- a/qutebrowser/utils/docutils.py
+++ b/qutebrowser/utils/docutils.py
@@ -25,7 +25,7 @@ import inspect
import os.path
import collections
import enum
-from typing import Callable, MutableMapping, Optional, List, Union
+from typing import Any, Callable, MutableMapping, Optional, List, Union
import qutebrowser
from qutebrowser.utils import log, utils
@@ -88,7 +88,7 @@ class DocstringParser:
arg_inside = enum.auto()
misc = enum.auto()
- def __init__(self, func: Callable) -> None:
+ def __init__(self, func: Callable[..., Any]) -> None:
"""Constructor.
Args:
diff --git a/qutebrowser/utils/objreg.py b/qutebrowser/utils/objreg.py
index 99d8a0936..0819a5d0a 100644
--- a/qutebrowser/utils/objreg.py
+++ b/qutebrowser/utils/objreg.py
@@ -55,7 +55,8 @@ class CommandOnlyError(Exception):
_IndexType = Union[str, int]
-class ObjectRegistry(collections.UserDict):
+# UserDict is only generic in Python 3.9+
+class ObjectRegistry(collections.UserDict): # type: ignore[type-arg]
"""A registry of long-living objects in qutebrowser.
diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py
index 01234a42b..ff8983c50 100644
--- a/qutebrowser/utils/qtutils.py
+++ b/qutebrowser/utils/qtutils.py
@@ -31,7 +31,8 @@ Module attributes:
import io
import operator
import contextlib
-from typing import TYPE_CHECKING, BinaryIO, IO, Iterator, Optional, Union, Tuple, cast
+from typing import (Any, AnyStr, TYPE_CHECKING, BinaryIO, IO, Iterator,
+ Optional, Union, Tuple, cast)
from PyQt5.QtCore import (qVersion, QEventLoop, QDataStream, QByteArray,
QIODevice, QFileDevice, QSaveFile, QT_VERSION_STR,
@@ -227,7 +228,7 @@ def savefile_open(
filename: str,
binary: bool = False,
encoding: str = 'utf-8'
-) -> Iterator[IO]:
+) -> Iterator[IO[AnyStr]]:
"""Context manager to easily use a QSaveFile."""
f = QSaveFile(filename)
cancelled = False
@@ -239,7 +240,7 @@ def savefile_open(
dev = cast(BinaryIO, PyQIODevice(f))
if binary:
- new_f: IO = dev
+ new_f: IO[Any] = dev # FIXME:mypy Why doesn't AnyStr work?
else:
new_f = io.TextIOWrapper(dev, encoding=encoding)
@@ -298,7 +299,11 @@ class PyQIODevice(io.BufferedIOBase):
if not self.writable():
raise OSError("Trying to write to unwritable file!")
- def open(self, mode: QIODevice.OpenMode) -> contextlib.closing:
+ # contextlib.closing is only generic in Python 3.9+
+ def open(
+ self,
+ mode: QIODevice.OpenMode,
+ ) -> contextlib.closing: # type: ignore[type-arg]
"""Open the underlying device and ensure opening succeeded.
Raises OSError if opening failed.
diff --git a/qutebrowser/utils/urlmatch.py b/qutebrowser/utils/urlmatch.py
index 8dfd6d273..f14c2083d 100644
--- a/qutebrowser/utils/urlmatch.py
+++ b/qutebrowser/utils/urlmatch.py
@@ -104,7 +104,14 @@ class UrlPattern:
self._init_path(parsed)
self._init_port(parsed)
- def _to_tuple(self) -> Tuple:
+ def _to_tuple(self) -> Tuple[
+ bool, # _match_all
+ bool, # _match_subdomains
+ Optional[str], # _scheme
+ Optional[str], # host
+ Optional[str], # _path
+ Optional[int], # _port
+ ]:
"""Get a pattern with information used for __eq__/__hash__."""
return (self._match_all, self._match_subdomains, self._scheme,
self.host, self._path, self._port)
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index 56ebe45c4..fb0165de2 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -341,7 +341,7 @@ class prevent_exceptions: # noqa: N801,N806 pylint: disable=invalid-name
self._retval = retval
self._predicate = predicate
- def __call__(self, func: Callable) -> Callable:
+ def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
"""Called when a function should be decorated.
Args:
@@ -447,7 +447,7 @@ def qualname(obj: Any) -> str:
_ExceptionType = Union[Type[BaseException], Tuple[Type[BaseException]]]
-def raises(exc: _ExceptionType, func: Callable, *args: Any) -> bool:
+def raises(exc: _ExceptionType, func: Callable[..., Any], *args: Any) -> bool:
"""Check if a function raises a given exception.
Args:
@@ -725,7 +725,10 @@ def yaml_dump(data: Any, f: IO[str] = None) -> Optional[str]:
return yaml_data.decode('utf-8')
-def chunk(elems: Sequence, n: int) -> Iterator[Sequence]:
+_T = TypeVar('_T')
+
+
+def chunk(elems: Sequence[_T], n: int) -> Iterator[Sequence[_T]]:
"""Yield successive n-sized chunks from elems.
If elems % n != 0, the last chunk will be smaller.