mypy: check_untyped_defs for most of qutebrowser.browser

This commit is contained in:
Florian Bruhin 2019-10-15 22:52:48 +02:00
parent 3a9d0bd3ff
commit 7ada7082aa
15 changed files with 91 additions and 50 deletions

View File

@ -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

View File

@ -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."""

View File

@ -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',

View File

@ -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):

View File

@ -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:

View File

@ -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()

View File

@ -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%" '

View File

@ -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

View File

@ -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()])

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

@ -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:

View File

@ -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: