From 7ada7082aa4485a1f5ccc88f05298b17f2997700 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 15 Oct 2019 22:52:48 +0200 Subject: [PATCH] mypy: check_untyped_defs for most of qutebrowser.browser --- mypy.ini | 10 ++++++++-- qutebrowser/api/downloads.py | 3 +++ qutebrowser/browser/commands.py | 6 +++--- qutebrowser/browser/downloads.py | 20 ++++++++++++-------- qutebrowser/browser/downloadview.py | 18 +++++++++++------- qutebrowser/browser/greasemonkey.py | 18 ++++++++++-------- qutebrowser/browser/history.py | 9 +++++++-- qutebrowser/browser/navigate.py | 11 ++++++++--- qutebrowser/browser/network/pac.py | 5 +++-- qutebrowser/browser/network/proxy.py | 7 ++++--- qutebrowser/browser/pdfjs.py | 2 +- qutebrowser/browser/qutescheme.py | 21 +++++++++++++-------- qutebrowser/browser/shared.py | 3 ++- qutebrowser/browser/urlmarks.py | 4 +++- qutebrowser/components/adblock.py | 4 +++- 15 files changed, 91 insertions(+), 50 deletions(-) diff --git a/mypy.ini b/mypy.ini index f830f3fca..1236db7a7 100644 --- a/mypy.ini +++ b/mypy.ini @@ -126,8 +126,14 @@ disallow_incomplete_defs = True disallow_untyped_defs = True disallow_incomplete_defs = True -# [mypy-qutebrowser.browser.*] -# check_untyped_defs = True +[mypy-qutebrowser.browser.*] +check_untyped_defs = True + +[mypy-qutebrowser.browser.webengine.*] +check_untyped_defs = False + +[mypy-qutebrowser.browser.webkit.*] +check_untyped_defs = False [mypy-qutebrowser.commands.*] check_untyped_defs = True diff --git a/qutebrowser/api/downloads.py b/qutebrowser/api/downloads.py index 70389bc51..307421f1b 100644 --- a/qutebrowser/api/downloads.py +++ b/qutebrowser/api/downloads.py @@ -29,6 +29,9 @@ from qutebrowser.browser import downloads, qtnetworkdownloads from qutebrowser.utils import objreg +UnsupportedAttribute = downloads.UnsupportedAttribute + + class TempDownload(QObject): """A download of some data into a file object.""" diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 10aa3538b..c4b8e86f8 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -640,9 +640,9 @@ class CommandDispatcher: assert what in ['url', 'pretty-url', 'markdown'], what flags = QUrl.RemovePassword if what == 'pretty-url': - flags |= QUrl.DecodeReserved + flags |= QUrl.DecodeReserved # type: ignore else: - flags |= QUrl.FullyEncoded + flags |= QUrl.FullyEncoded # type: ignore url = QUrl(self._current_url()) url_query = QUrlQuery() url_query_str = urlutils.query_string(url) @@ -653,7 +653,7 @@ class CommandDispatcher: if key in config.val.url.yank_ignored_parameters: url_query.removeQueryItem(key) url.setQuery(url_query) - return url.toString(flags) + return url.toString(flags) # type: ignore @cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.argument('what', choices=['selection', 'url', 'pretty-url', diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 38fa806a9..e876c1396 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -28,6 +28,7 @@ import functools import pathlib import tempfile import enum +import typing from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex, QTimer, QAbstractListModel, QUrl) @@ -48,7 +49,7 @@ class ModelRole(enum.IntEnum): # Remember the last used directory -last_used_directory = None +last_used_directory = None # type: typing.Optional[str] # All REFRESH_INTERVAL milliseconds, speeds will be recalculated and downloads # redrawn. @@ -226,12 +227,13 @@ def suggested_fn_from_title(url_path, title=None): """ ext_whitelist = [".html", ".htm", ".php", ""] _, ext = os.path.splitext(url_path) + + suggested_fn = None # type: typing.Optional[str] if ext.lower() in ext_whitelist and title: suggested_fn = utils.sanitize_filename(title) if not suggested_fn.lower().endswith((".html", ".htm")): suggested_fn += ".html" - else: - suggested_fn = None + return suggested_fn @@ -352,7 +354,8 @@ class DownloadItemStats(QObject): self.speed = 0 self._last_done = 0 samples = int(self.SPEED_AVG_WINDOW * (1000 / _REFRESH_INTERVAL)) - self._speed_avg = collections.deque(maxlen=samples) + self._speed_avg = collections.deque( + maxlen=samples) # type: typing.Sequence[float] def update_speed(self): """Recalculate the current download speed. @@ -451,7 +454,8 @@ class AbstractDownloadItem(QObject): self.basename = '???' self.successful = False - self.fileobj = UnsupportedAttribute() + self.fileobj = UnsupportedAttribute( + ) # type: typing.Union[UnsupportedAttribute, typing.IO[bytes]] self.raw_headers = UnsupportedAttribute() self._filename = None @@ -830,7 +834,7 @@ class AbstractDownloadManager(QObject): def __init__(self, parent=None): super().__init__(parent) - self.downloads = [] + self.downloads = [] # type: typing.Sequence[AbstractDownloadItem] self._update_timer = usertypes.Timer(self, 'download-update') self._update_timer.timeout.connect(self._update_gui) self._update_timer.setInterval(_REFRESH_INTERVAL) @@ -1195,7 +1199,7 @@ class DownloadModel(QAbstractListModel): item = self[index.row()] if role == Qt.DisplayRole: - data = str(item) + data = str(item) # type: typing.Any elif role == Qt.ForegroundRole: data = item.get_status_color('fg') elif role == Qt.BackgroundRole: @@ -1241,7 +1245,7 @@ class TempDownloadManager: """ def __init__(self): - self.files = [] + self.files = [] # type: typing.Sequence[typing.IO[str]] self._tmpdir = None def cleanup(self): diff --git a/qutebrowser/browser/downloadview.py b/qutebrowser/browser/downloadview.py index ea7c96469..c6a46bb14 100644 --- a/qutebrowser/browser/downloadview.py +++ b/qutebrowser/browser/downloadview.py @@ -20,6 +20,7 @@ """The ListView to display downloads in.""" import functools +import typing from PyQt5.QtCore import pyqtSlot, QSize, Qt, QTimer from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu, QStyleFactory @@ -53,6 +54,14 @@ def update_geometry(obj): QTimer.singleShot(0, _update_geometry) +_ActionListType = typing.MutableSequence[ + typing.Union[ + typing.Tuple[None, None], # separator + typing.Tuple[str, typing.Callable[[], None]], + ] +] + + class DownloadView(QListView): """QListView which shows currently running downloads as a bar. @@ -123,19 +132,14 @@ class DownloadView(QListView): item.open_file() item.remove() - def _get_menu_actions(self, item): + def _get_menu_actions(self, item) -> _ActionListType: """Get the available context menu actions for a given DownloadItem. Args: item: The DownloadItem to get the actions for, or None. - - Return: - A list of either: - - (QAction, callable) tuples. - - (None, None) for a separator """ model = self.model() - actions = [] + actions = [] # type: _ActionListType if item is None: pass elif item.done: diff --git a/qutebrowser/browser/greasemonkey.py b/qutebrowser/browser/greasemonkey.py index 3a5b60544..6693497d6 100644 --- a/qutebrowser/browser/greasemonkey.py +++ b/qutebrowser/browser/greasemonkey.py @@ -26,6 +26,7 @@ import fnmatch import functools import glob import textwrap +import typing import attr from PyQt5.QtCore import pyqtSignal, QObject, QUrl @@ -50,10 +51,10 @@ class GreasemonkeyScript: def __init__(self, properties, code, # noqa: C901 pragma: no mccabe filename=None): self._code = code - self.includes = [] - self.matches = [] - self.excludes = [] - self.requires = [] + self.includes = [] # type: typing.Sequence[str] + self.matches = [] # type: typing.Sequence[str] + self.excludes = [] # type: typing.Sequence[str] + self.requires = [] # type: typing.Sequence[str] self.description = None self.name = None self.namespace = None @@ -253,10 +254,11 @@ class GreasemonkeyManager(QObject): def __init__(self, parent=None): super().__init__(parent) - self._run_start = [] - self._run_end = [] - self._run_idle = [] - self._in_progress_dls = [] + self._run_start = [] # type: typing.Sequence[GreasemonkeyScript] + self._run_end = [] # type: typing.Sequence[GreasemonkeyScript] + self._run_idle = [] # type: typing.Sequence[GreasemonkeyScript] + self._in_progress_dls = [ + ] # type: typing.Sequence[downloads.AbstractDownloadItem] self.load_scripts() diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index 3cdce4853..5c818e265 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -22,6 +22,7 @@ import os import time import contextlib +import typing from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal from PyQt5.QtWidgets import QProgressDialog, QApplication @@ -55,7 +56,7 @@ class HistoryProgress: self._progress.setMinimumDuration(500) self._progress.setLabelText(text) self._progress.setMaximum(maximum) - self._progress.setCancelButton(None) + self._progress.setCancelButton(None) # type: ignore self._progress.show() QApplication.processEvents() @@ -206,7 +207,11 @@ class WebHistory(sql.SqlTable): return any(pattern.matches(url) for pattern in patterns) def _rebuild_completion(self): - data = {'url': [], 'title': [], 'last_atime': []} + data = { + 'url': [], + 'title': [], + 'last_atime': [] + } # type: typing.Mapping[str, typing.MutableSequence[str]] # select the latest entry for each url q = sql.Query('SELECT url, title, max(atime) AS atime FROM History ' 'WHERE NOT redirect and url NOT LIKE "qute://back%" ' diff --git a/qutebrowser/browser/navigate.py b/qutebrowser/browser/navigate.py index 99ed7c1d7..d4d7c8211 100644 --- a/qutebrowser/browser/navigate.py +++ b/qutebrowser/browser/navigate.py @@ -21,6 +21,7 @@ import re import posixpath +import typing from PyQt5.QtCore import QUrl @@ -96,7 +97,9 @@ def incdec(url, count, inc_or_dec): window: Open the link in a new window. """ urlutils.ensure_valid(url) - segments = set(config.val.url.incdec_segments) + segments = ( + set(config.val.url.incdec_segments) + ) # type: typing.Optional[typing.Set[str]] if segments is None: segments = {'path', 'query'} @@ -159,7 +162,8 @@ def _find_prevnext(prev, elems): # pylint: disable=bad-config-option for regex in getattr(config.val.hints, option): # pylint: enable=bad-config-option - log.hints.vdebug("== Checking regex '{}'.".format(regex.pattern)) + log.hints.vdebug("== Checking regex '{}'." # type: ignore + .format(regex.pattern)) for e in elems: text = str(e) if not text: @@ -169,7 +173,8 @@ def _find_prevnext(prev, elems): regex.pattern, text)) return e else: - log.hints.vdebug("No match on '{}'!".format(text)) + log.hints.vdebug("No match on '{}'!" # type: ignore + .format(text)) return None diff --git a/qutebrowser/browser/network/pac.py b/qutebrowser/browser/network/pac.py index 4fc4a6fe9..275412be2 100644 --- a/qutebrowser/browser/network/pac.py +++ b/qutebrowser/browser/network/pac.py @@ -214,9 +214,10 @@ class PACResolver: if from_file: string_flags = QUrl.PrettyDecoded else: - string_flags = QUrl.RemoveUserInfo + string_flags = QUrl.RemoveUserInfo # type: ignore if query.url().scheme() == 'https': - string_flags |= QUrl.RemovePath | QUrl.RemoveQuery + string_flags |= QUrl.RemovePath # type: ignore + string_flags |= QUrl.RemoveQuery # type: ignore result = self._resolver.call([query.url().toString(string_flags), query.peerHostName()]) diff --git a/qutebrowser/browser/network/proxy.py b/qutebrowser/browser/network/proxy.py index 2bd1a6325..0f085d256 100644 --- a/qutebrowser/browser/network/proxy.py +++ b/qutebrowser/browser/network/proxy.py @@ -54,7 +54,7 @@ def _warn_for_pac(): @pyqtSlot() def shutdown(): - QNetworkProxyFactory.setApplicationProxyFactory(None) + QNetworkProxyFactory.setApplicationProxyFactory(None) # type: ignore class ProxyFactory(QNetworkProxyFactory): @@ -99,9 +99,10 @@ class ProxyFactory(QNetworkProxyFactory): for p in proxies: if p.type() != QNetworkProxy.NoProxy: capabilities = p.capabilities() + lookup_cap = QNetworkProxy.HostNameLookupCapability if config.val.content.proxy_dns_requests: - capabilities |= QNetworkProxy.HostNameLookupCapability + capabilities |= lookup_cap # type: ignore else: - capabilities &= ~QNetworkProxy.HostNameLookupCapability + capabilities &= ~lookup_cap # type: ignore p.setCapabilities(capabilities) return proxies diff --git a/qutebrowser/browser/pdfjs.py b/qutebrowser/browser/pdfjs.py index a5ae1b7f4..bc4ef10b8 100644 --- a/qutebrowser/browser/pdfjs.py +++ b/qutebrowser/browser/pdfjs.py @@ -105,7 +105,7 @@ def _generate_pdfjs_script(filename): viewer.open({{ url }}); }); """).render( - url=javascript.to_js(url.toString(QUrl.FullyEncoded)), + url=javascript.to_js(url.toString(QUrl.FullyEncoded)), # type: ignore # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-70420 disable_create_object_url=( not qtutils.version_check('5.12') and diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py index 606a05fc1..898337840 100644 --- a/qutebrowser/browser/qutescheme.py +++ b/qutebrowser/browser/qutescheme.py @@ -32,6 +32,7 @@ import textwrap import urllib import collections import base64 +import typing try: import secrets @@ -190,7 +191,8 @@ def qute_bookmarks(_url): @add_handler('tabs') def qute_tabs(_url): """Handler for qute://tabs. Display information about all open tabs.""" - tabs = collections.defaultdict(list) + tabs = collections.defaultdict( + list) # type: typing.Dict[str, typing.List[typing.Tuple[str, str]]] for win_id, window in objreg.window_registry.items(): if sip.isdeleted(window): continue @@ -234,15 +236,16 @@ def history_data(start_time, offset=None): def qute_history(url): """Handler for qute://history. Display and serve history.""" if url.path() == '/data': + q_offset = QUrlQuery(url).queryItemValue("offset") try: - offset = QUrlQuery(url).queryItemValue("offset") - offset = int(offset) if offset else None + offset = int(q_offset) if q_offset else None except ValueError: raise UrlInvalidError("Query parameter offset is invalid") + # Use start_time in query or current time. + q_start_time = QUrlQuery(url).queryItemValue("start_time") try: - start_time = QUrlQuery(url).queryItemValue("start_time") - start_time = float(start_time) if start_time else time.time() + start_time = float(q_start_time) if q_start_time else time.time() except ValueError: raise UrlInvalidError("Query parameter start_time is invalid") @@ -451,9 +454,11 @@ def qute_bindings(_url): """Handler for qute://bindings. View keybindings.""" bindings = {} defaults = config.val.bindings.default - modes = set(defaults.keys()).union(config.val.bindings.commands) - modes.remove('normal') - modes = ['normal'] + sorted(list(modes)) + + config_modes = set(defaults.keys()).union(config.val.bindings.commands) + config_modes.remove('normal') + + modes = ['normal'] + sorted(list(config_modes)) for mode in modes: bindings[mode] = config.key_instance.get_bindings_for(mode) diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 4781aac47..58b85567a 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -22,6 +22,7 @@ import os import html import netrc +import typing from PyQt5.QtCore import QUrl @@ -138,7 +139,7 @@ _JS_LOGMAP = { 'info': log.js.info, 'warning': log.js.warning, 'error': log.js.error, -} +} # type: typing.Mapping[str, typing.Callable[[str], None]] def javascript_log_message(level, source, line, msg): diff --git a/qutebrowser/browser/urlmarks.py b/qutebrowser/browser/urlmarks.py index 2ff71c2df..18e5f68d3 100644 --- a/qutebrowser/browser/urlmarks.py +++ b/qutebrowser/browser/urlmarks.py @@ -30,6 +30,7 @@ import os.path import html import functools import collections +import typing from PyQt5.QtCore import pyqtSignal, QUrl, QObject @@ -77,7 +78,8 @@ class UrlMarkManager(QObject): """Initialize and read quickmarks.""" super().__init__(parent) - self.marks = collections.OrderedDict() + self.marks = collections.OrderedDict( + ) # type: typing.MutableMapping[str, QUrl] self._init_lineparser() for line in self._lineparser: diff --git a/qutebrowser/components/adblock.py b/qutebrowser/components/adblock.py index 24dfcb8dd..9c504f8fb 100644 --- a/qutebrowser/components/adblock.py +++ b/qutebrowser/components/adblock.py @@ -247,7 +247,7 @@ class HostBlocker: self._in_progress.append(download) self._on_download_finished(download) - def _merge_file(self, byte_io: io.BytesIO) -> None: + def _merge_file(self, byte_io: typing.IO[bytes]) -> None: """Read and merge host files. Args: @@ -303,6 +303,8 @@ class HostBlocker: self._in_progress.remove(download) if download.successful: self._done_count += 1 + assert not isinstance(download.fileobj, + downloads.UnsupportedAttribute) try: self._merge_file(download.fileobj) finally: