summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2023-07-19 17:07:04 +0200
committerFlorian Bruhin <me@the-compiler.org>2023-07-19 17:08:24 +0200
commit92dea988c01e74596cc6ed698e88ac56df392c14 (patch)
tree3fa4099b4ead84d5f057e532c44b3c605979fe04
parent3b04cb1d99244516b21084545d06daa7e58cd756 (diff)
downloadqutebrowser-92dea988c01e74596cc6ed698e88ac56df392c14.tar.gz
qutebrowser-92dea988c01e74596cc6ed698e88ac56df392c14.zip
Initial upgrade to new PyQt6 stubs
-rw-r--r--qutebrowser/browser/browsertab.py8
-rw-r--r--qutebrowser/browser/downloadview.py12
-rw-r--r--qutebrowser/browser/inspector.py9
-rw-r--r--qutebrowser/browser/network/pac.py1
-rw-r--r--qutebrowser/browser/network/proxy.py4
-rw-r--r--qutebrowser/browser/webengine/notification.py4
-rw-r--r--qutebrowser/browser/webengine/tabhistory.py4
-rw-r--r--qutebrowser/browser/webengine/webview.py4
-rw-r--r--qutebrowser/completion/completiondelegate.py1
-rw-r--r--qutebrowser/completion/completionwidget.py40
-rw-r--r--qutebrowser/config/configfiles.py4
-rw-r--r--qutebrowser/keyinput/eventfilter.py5
-rw-r--r--qutebrowser/mainwindow/prompt.py3
-rw-r--r--qutebrowser/mainwindow/statusbar/command.py3
-rw-r--r--qutebrowser/mainwindow/statusbar/url.py4
-rw-r--r--qutebrowser/mainwindow/tabbedbrowser.py33
-rw-r--r--qutebrowser/mainwindow/tabwidget.py28
-rw-r--r--qutebrowser/misc/consolewidget.py1
-rw-r--r--qutebrowser/misc/guiprocess.py4
-rw-r--r--qutebrowser/misc/ipc.py6
-rw-r--r--qutebrowser/misc/miscwidgets.py28
-rw-r--r--qutebrowser/misc/nativeeventfilter.py5
-rw-r--r--qutebrowser/utils/debug.py1
-rw-r--r--qutebrowser/utils/log.py18
-rw-r--r--qutebrowser/utils/qtutils.py65
-rw-r--r--qutebrowser/utils/standarddir.py4
-rw-r--r--qutebrowser/utils/urlutils.py6
-rw-r--r--qutebrowser/utils/utils.py13
-rw-r--r--qutebrowser/utils/version.py7
29 files changed, 244 insertions, 81 deletions
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index 47cba5922..eacd61dbb 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -286,10 +286,16 @@ class AbstractPrinting(QObject):
"""
raise NotImplementedError
+ def _do_print(self) -> None:
+ assert self._dialog is not None
+ printer = self._dialog.printer()
+ assert printer is not None
+ self.to_printer(printer)
+
def show_dialog(self) -> None:
"""Print with a QPrintDialog."""
self._dialog = dialog = QPrintDialog(self._tab)
- self._dialog.open(lambda: self.to_printer(dialog.printer()))
+ self._dialog.open(self._do_print)
# Gets cleaned up in on_printing_finished
diff --git a/qutebrowser/browser/downloadview.py b/qutebrowser/browser/downloadview.py
index f4790bc9f..8f04f8d9d 100644
--- a/qutebrowser/browser/downloadview.py
+++ b/qutebrowser/browser/downloadview.py
@@ -78,10 +78,11 @@ class DownloadView(QListView):
def __repr__(self):
model = self.model()
- if model is None:
- count = 'None' # type: ignore[unreachable]
- else:
+ count: Union[int, str]
+ if qtutils.is_not_none(model):
count = model.rowCount()
+ else:
+ count = 'None'
return utils.get_repr(self, count=count)
def _model(self) -> downloads.DownloadModel:
@@ -173,9 +174,12 @@ class DownloadView(QListView):
assert name is not None
assert handler is not None
action = self._menu.addAction(name)
+ assert action is not None
action.triggered.connect(handler)
if actions:
- self._menu.popup(self.viewport().mapToGlobal(point))
+ viewport = self.viewport()
+ assert viewport is not None
+ self._menu.popup(viewport.mapToGlobal(point))
def minimumSizeHint(self):
"""Override minimumSizeHint so the size is correct in a layout."""
diff --git a/qutebrowser/browser/inspector.py b/qutebrowser/browser/inspector.py
index a2ce67750..15ff6c48a 100644
--- a/qutebrowser/browser/inspector.py
+++ b/qutebrowser/browser/inspector.py
@@ -28,7 +28,7 @@ from qutebrowser.qt.gui import QCloseEvent
from qutebrowser.browser import eventfilter
from qutebrowser.config import configfiles, config
-from qutebrowser.utils import log, usertypes
+from qutebrowser.utils import log, usertypes, qtutils
from qutebrowser.keyinput import modeman
from qutebrowser.misc import miscwidgets
@@ -70,8 +70,9 @@ class _EventFilter(QObject):
clicked = pyqtSignal()
- def eventFilter(self, _obj: QObject, event: QEvent) -> bool:
+ def eventFilter(self, _obj: Optional[QObject], event: Optional[QEvent]) -> bool:
"""Translate mouse presses to a clicked signal."""
+ assert event is not None
if event.type() == QEvent.Type.MouseButtonPress:
self.clicked.emit()
return False
@@ -162,7 +163,7 @@ class AbstractWebInspector(QWidget):
self.shutdown()
return
elif position == Position.window:
- self.setParent(None) # type: ignore[call-overload]
+ self.setParent(qtutils.allow_none(None))
self._load_state_geometry()
else:
self._splitter.set_inspector(self, position)
@@ -195,7 +196,7 @@ class AbstractWebInspector(QWidget):
if not ok:
log.init.warning("Error while loading geometry.")
- def closeEvent(self, _e: QCloseEvent) -> None:
+ def closeEvent(self, _e: Optional[QCloseEvent]) -> None:
"""Save the geometry when closed."""
data = self._widget.saveGeometry().data()
geom = base64.b64encode(data).decode('ASCII')
diff --git a/qutebrowser/browser/network/pac.py b/qutebrowser/browser/network/pac.py
index fcca5d45d..54c1195af 100644
--- a/qutebrowser/browser/network/pac.py
+++ b/qutebrowser/browser/network/pac.py
@@ -277,6 +277,7 @@ class PACFetcher(QObject):
"""Fetch the proxy from the remote URL."""
assert self._manager is not None
self._reply = self._manager.get(QNetworkRequest(self._pac_url))
+ assert self._reply is not None
self._reply.finished.connect(self._finish)
@pyqtSlot()
diff --git a/qutebrowser/browser/network/proxy.py b/qutebrowser/browser/network/proxy.py
index 714823d2c..0351adf0e 100644
--- a/qutebrowser/browser/network/proxy.py
+++ b/qutebrowser/browser/network/proxy.py
@@ -21,7 +21,7 @@ from qutebrowser.qt.core import QUrl, pyqtSlot
from qutebrowser.qt.network import QNetworkProxy, QNetworkProxyFactory
from qutebrowser.config import config, configtypes
-from qutebrowser.utils import message, usertypes, urlutils, utils
+from qutebrowser.utils import message, usertypes, urlutils, utils, qtutils
from qutebrowser.misc import objects
from qutebrowser.browser.network import pac
@@ -51,7 +51,7 @@ def _warn_for_pac():
@pyqtSlot()
def shutdown():
QNetworkProxyFactory.setApplicationProxyFactory(
- None) # type: ignore[arg-type]
+ qtutils.allow_none(None))
class ProxyFactory(QNetworkProxyFactory):
diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py
index 4d08e914e..d101c616c 100644
--- a/qutebrowser/browser/webengine/notification.py
+++ b/qutebrowser/browser/webengine/notification.py
@@ -1108,7 +1108,9 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
if padding and self._quirks.no_padded_images:
return None
- bits = qimage.constBits().asstring(size)
+ bits_ptr = qimage.constBits()
+ assert bits_ptr is not None
+ bits = bits_ptr.asstring(size)
image_data.add(QByteArray(bits))
image_data.endStructure()
diff --git a/qutebrowser/browser/webengine/tabhistory.py b/qutebrowser/browser/webengine/tabhistory.py
index 30f3facdb..2848142ef 100644
--- a/qutebrowser/browser/webengine/tabhistory.py
+++ b/qutebrowser/browser/webengine/tabhistory.py
@@ -153,6 +153,8 @@ def serialize(items):
for item in items:
_serialize_item(item, stream)
- stream.device().reset()
+ dev = stream.device()
+ assert dev is not None
+ dev.reset()
qtutils.check_qdatastream(stream)
return stream, data, cur_user_data
diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py
index 9d58c0379..ade008143 100644
--- a/qutebrowser/browser/webengine/webview.py
+++ b/qutebrowser/browser/webengine/webview.py
@@ -54,7 +54,9 @@ class WebEngineView(QWebEngineView):
self._win_id = win_id
self._tabdata = tabdata
- theme_color = self.style().standardPalette().color(QPalette.ColorRole.Base)
+ style = self.style()
+ assert style is not None
+ theme_color = style.standardPalette().color(QPalette.ColorRole.Base)
if private:
assert webenginesettings.private_profile is not None
profile = webenginesettings.private_profile
diff --git a/qutebrowser/completion/completiondelegate.py b/qutebrowser/completion/completiondelegate.py
index e497e1204..cc5859ca6 100644
--- a/qutebrowser/completion/completiondelegate.py
+++ b/qutebrowser/completion/completiondelegate.py
@@ -291,6 +291,7 @@ class CompletionItemDelegate(QStyledItemDelegate):
self._opt = QStyleOptionViewItem(option)
self.initStyleOption(self._opt, index)
self._style = self._opt.widget.style()
+ assert self._style is not None
self._get_textdoc(index)
assert self._doc is not None
diff --git a/qutebrowser/completion/completionwidget.py b/qutebrowser/completion/completionwidget.py
index 01527e763..665757e89 100644
--- a/qutebrowser/completion/completionwidget.py
+++ b/qutebrowser/completion/completionwidget.py
@@ -156,6 +156,15 @@ class CompletionView(QTreeView):
assert isinstance(model, completionmodel.CompletionModel), model
return model
+ def _selection_model(self) -> QItemSelectionModel:
+ """Get the current selection model.
+
+ Ensures the model is not None.
+ """
+ model = self.selectionModel()
+ assert model is not None
+ return model
+
@pyqtSlot(str)
def _on_config_changed(self, option):
if option in ['completion.height', 'completion.shrink']:
@@ -169,7 +178,9 @@ class CompletionView(QTreeView):
column_widths = self._model().column_widths
pixel_widths = [(width * perc // 100) for perc in column_widths]
- delta = self.verticalScrollBar().sizeHint().width()
+ bar = self.verticalScrollBar()
+ assert bar is not None
+ delta = bar.sizeHint().width()
for i, width in reversed(list(enumerate(pixel_widths))):
if width > delta:
pixel_widths[i] -= delta
@@ -191,7 +202,7 @@ class CompletionView(QTreeView):
A QModelIndex.
"""
model = self._model()
- idx = self.selectionModel().currentIndex()
+ idx = self._selection_model().currentIndex()
if not idx.isValid():
# No item selected yet
if upwards:
@@ -223,7 +234,7 @@ class CompletionView(QTreeView):
Return:
A QModelIndex.
"""
- old_idx = self.selectionModel().currentIndex()
+ old_idx = self._selection_model().currentIndex()
idx = old_idx
model = self._model()
@@ -267,7 +278,7 @@ class CompletionView(QTreeView):
Return:
A QModelIndex.
"""
- idx = self.selectionModel().currentIndex()
+ idx = self._selection_model().currentIndex()
model = self._model()
if not idx.isValid():
return self._next_idx(upwards).sibling(0, 0)
@@ -323,7 +334,7 @@ class CompletionView(QTreeView):
if not self._active:
return
- selmodel = self.selectionModel()
+ selmodel = self._selection_model()
indices = {
'next': lambda: self._next_idx(upwards=False),
'prev': lambda: self._next_idx(upwards=True),
@@ -363,9 +374,10 @@ class CompletionView(QTreeView):
Args:
model: The model to use.
"""
- if self.model() is not None and model is not self.model():
- self.model().deleteLater()
- self.selectionModel().deleteLater()
+ old_model = self.model()
+ if old_model is not None and model is not old_model:
+ old_model.deleteLater()
+ self._selection_model().deleteLater()
self.setModel(model)
@@ -395,7 +407,7 @@ class CompletionView(QTreeView):
self.pattern = pattern
with debug.log_time(log.completion, 'Set pattern {}'.format(pattern)):
self._model().set_pattern(pattern)
- self.selectionModel().clear()
+ self._selection_model().clear()
self._maybe_update_geometry()
self._maybe_show()
@@ -415,7 +427,7 @@ class CompletionView(QTreeView):
def on_clear_completion_selection(self):
"""Clear the selection model when an item is activated."""
self.hide()
- selmod = self.selectionModel()
+ selmod = self._selection_model()
if selmod is not None:
selmod.clearSelection()
selmod.clearCurrentIndex()
@@ -426,14 +438,18 @@ class CompletionView(QTreeView):
confheight = str(config.val.completion.height)
if confheight.endswith('%'):
perc = int(confheight.rstrip('%'))
- height = self.window().height() * perc // 100
+ window = self.window()
+ assert window is not None
+ height = window.height() * perc // 100
else:
height = int(confheight)
# Shrink to content size if needed and shrinking is enabled
if config.val.completion.shrink:
+ bar = self.horizontalScrollBar()
+ assert bar is not None
contents_height = (
self.viewportSizeHint().height() +
- self.horizontalScrollBar().sizeHint().height())
+ bar.sizeHint().height())
if contents_height <= height:
height = contents_height
# The width isn't really relevant as we're expanding anyways.
diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py
index 2a13133ae..ac593cfae 100644
--- a/qutebrowser/config/configfiles.py
+++ b/qutebrowser/config/configfiles.py
@@ -108,7 +108,9 @@ class StateConfig(configparser.ConfigParser):
for sect, key in deleted_keys:
self[sect].pop(key, None)
- self['general']['qt_version'] = qVersion()
+ qt_version = qVersion()
+ assert qt_version is not None
+ self['general']['qt_version'] = qt_version
self['general']['qtwe_version'] = self._qtwe_version_str()
self['general']['chromium_version'] = self._chromium_version_str()
self['general']['version'] = qutebrowser.__version__
diff --git a/qutebrowser/keyinput/eventfilter.py b/qutebrowser/keyinput/eventfilter.py
index 3f8d2779f..40581b3c1 100644
--- a/qutebrowser/keyinput/eventfilter.py
+++ b/qutebrowser/keyinput/eventfilter.py
@@ -17,7 +17,7 @@
"""Global Qt event filter which dispatches key events."""
-from typing import cast
+from typing import cast, Optional
from qutebrowser.qt.core import pyqtSlot, QObject, QEvent
from qutebrowser.qt.gui import QKeyEvent, QWindow
@@ -75,7 +75,7 @@ class EventFilter(QObject):
# No window available yet, or not a MainWindow
return False
- def eventFilter(self, obj: QObject, event: QEvent) -> bool:
+ def eventFilter(self, obj: Optional[QObject], event: Optional[QEvent]) -> bool:
"""Handle an event.
Args:
@@ -85,6 +85,7 @@ class EventFilter(QObject):
Return:
True if the event should be filtered, False if it's passed through.
"""
+ assert event is not None
ev_type = event.type()
if self._log_qt_events:
diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py
index 26a2ae886..17772b2ea 100644
--- a/qutebrowser/mainwindow/prompt.py
+++ b/qutebrowser/mainwindow/prompt.py
@@ -303,6 +303,7 @@ class PromptContainer(QWidget):
item = self._layout.takeAt(0)
if item is not None:
widget = item.widget()
+ assert widget is not None
log.prompt.debug("Deleting old prompt {}".format(widget))
widget.hide()
widget.deleteLater()
@@ -366,6 +367,7 @@ class PromptContainer(QWidget):
item = self._layout.takeAt(0)
if item is not None:
widget = item.widget()
+ assert widget is not None
log.prompt.debug("Deleting prompt {}".format(widget))
widget.hide()
widget.deleteLater()
@@ -780,6 +782,7 @@ class FilenamePrompt(_BasePrompt):
# This duplicates some completion code, but I don't see a nicer way...
assert which in ['prev', 'next'], which
selmodel = self._file_view.selectionModel()
+ assert selmodel is not None
parent = self._file_view.rootIndex()
first_index = self._file_model.index(0, 0, parent)
diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py
index b9c78d623..68bacd0b0 100644
--- a/qutebrowser/mainwindow/statusbar/command.py
+++ b/qutebrowser/mainwindow/statusbar/command.py
@@ -264,13 +264,14 @@ class Command(misc.CommandLineEdit):
text = cast(str, text)
super().setText(text)
- def keyPressEvent(self, e: QKeyEvent) -> None:
+ def keyPressEvent(self, e: Optional[QKeyEvent]) -> None:
"""Override keyPressEvent to ignore Return key presses, and add Shift-Ins.
If this widget is focused, we are in passthrough key mode, and
Enter/Shift+Enter/etc. will cause QLineEdit to think it's finished
without command_accept to be called.
"""
+ assert e is not None
if machinery.IS_QT5: # FIXME:v4 needed for Qt 5 typing
shift = cast(Qt.KeyboardModifiers, Qt.KeyboardModifier.ShiftModifier)
else:
diff --git a/qutebrowser/mainwindow/statusbar/url.py b/qutebrowser/mainwindow/statusbar/url.py
index 54faf232d..7892b3e83 100644
--- a/qutebrowser/mainwindow/statusbar/url.py
+++ b/qutebrowser/mainwindow/statusbar/url.py
@@ -116,7 +116,9 @@ class UrlText(textbase.TextBase):
if old_urltype != self._urltype:
# We can avoid doing an unpolish here because the new style will
# always override the old one.
- self.style().polish(self)
+ style = self.style()
+ assert style is not None
+ style.polish(self)
@pyqtSlot(usertypes.LoadStatus)
def on_load_status_changed(self, status):
diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py
index da3392a7e..918434eae 100644
--- a/qutebrowser/mainwindow/tabbedbrowser.py
+++ b/qutebrowser/mainwindow/tabbedbrowser.py
@@ -249,7 +249,7 @@ class TabbedBrowser(QWidget):
self.search_options: Mapping[str, Any] = {}
self._local_marks: MutableMapping[QUrl, MutableMapping[str, QPoint]] = {}
self._global_marks: MutableMapping[str, Tuple[QPoint, QUrl]] = {}
- self.default_window_icon = self.widget.window().windowIcon()
+ self.default_window_icon = self._window().windowIcon()
self.is_private = private
self.tab_deque = TabDeque()
config.instance.changed.connect(self._on_config_changed)
@@ -302,11 +302,10 @@ class TabbedBrowser(QWidget):
widgets = []
for i in range(self.widget.count()):
widget = self.widget.widget(i)
- if widget is None:
- log.webview.debug( # type: ignore[unreachable]
- "Got None-widget in tabbedbrowser!")
- else:
+ if qtutils.is_not_none(widget):
widgets.append(widget)
+ else:
+ log.webview.debug("Got None-widget in tabbedbrowser!")
return widgets
def _update_window_title(self, field=None):
@@ -330,7 +329,8 @@ class TabbedBrowser(QWidget):
fields['id'] = self._win_id
title = title_format.format(**fields)
- self.widget.window().setWindowTitle(title)
+
+ self._window().setWindowTitle(title)
def _connect_tab_signals(self, tab):
"""Set up the needed signals for tab."""
@@ -396,6 +396,15 @@ class TabbedBrowser(QWidget):
assert isinstance(tab, browsertab.AbstractTab), tab
return tab
+ def _window(self) -> QWidget:
+ """Get the current window widget.
+
+ Note: This asserts if there is no window.
+ """
+ window = self.widget.window()
+ assert window is not None
+ return window
+
def _tab_by_idx(self, idx: int) -> Optional[browsertab.AbstractTab]:
"""Get a browser tab by index.
@@ -662,11 +671,12 @@ class TabbedBrowser(QWidget):
# Make sure the background tab has the correct initial size.
# With a foreground tab, it's going to be resized correctly by the
# layout anyways.
- tab.resize(self.widget.currentWidget().size())
+ current_widget = self._current_tab()
+ tab.resize(current_widget.size())
self.widget.tab_index_changed.emit(self.widget.currentIndex(),
self.widget.count())
# Refocus webview in case we lost it by spawning a bg tab
- self.widget.currentWidget().setFocus()
+ current_widget.setFocus()
else:
self.widget.setCurrentWidget(tab)
@@ -739,7 +749,7 @@ class TabbedBrowser(QWidget):
tab.data.keep_icon = False
elif (config.cache['tabs.tabs_are_windows'] and
tab.data.should_show_icon()):
- self.widget.window().setWindowIcon(self.default_window_icon)
+ self._window().setWindowIcon(self.default_window_icon)
@pyqtSlot()
def _on_load_status_changed(self, tab):
@@ -863,8 +873,9 @@ class TabbedBrowser(QWidget):
def on_mode_left(self, mode):
"""Give focus to current tab if command mode was left."""
widget = self.widget.currentWidget()
- if widget is None:
- return # type: ignore[unreachable]
+ if not qtutils.is_not_none(widget):
+ return
+
if mode in [usertypes.KeyMode.command] + modeman.PROMPT_MODES:
log.modes.debug("Left status-input mode, focusing {!r}".format(
widget))
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py
index fe9ce1e06..150c820a8 100644
--- a/qutebrowser/mainwindow/tabwidget.py
+++ b/qutebrowser/mainwindow/tabwidget.py
@@ -355,7 +355,9 @@ class TabWidget(QTabWidget):
self.setTabIcon(idx, icon)
if config.val.tabs.tabs_are_windows:
- self.window().setWindowIcon(tab.icon())
+ window = self.window()
+ assert window is not None
+ window.setWindowIcon(tab.icon())
def setTabIcon(self, idx: int, icon: QIcon) -> None:
"""Always show tab icons for pinned tabs in some circumstances."""
@@ -365,7 +367,9 @@ class TabWidget(QTabWidget):
config.cache['tabs.pinned.shrink'] and
not self.tab_bar().vertical and
tab is not None and tab.data.pinned):
- icon = self.style().standardIcon(QStyle.StandardPixmap.SP_FileIcon)
+ style = self.style()
+ assert style is not None
+ icon = style.standardIcon(QStyle.StandardPixmap.SP_FileIcon)
super().setTabIcon(idx, icon)
@@ -809,6 +813,12 @@ class TabBarStyle(QProxyStyle):
ICON_PADDING = 4
+ def _base_style(self) -> QStyle:
+ """Get the base style."""
+ style = self.baseStyle()
+ assert style is not None
+ return style
+
def _draw_indicator(self, layouts, opt, p):
"""Draw the tab indicator.
@@ -836,7 +846,7 @@ class TabBarStyle(QProxyStyle):
icon_state = (QIcon.State.On if opt.state & QStyle.StateFlag.State_Selected
else QIcon.State.Off)
icon = opt.icon.pixmap(opt.iconSize, icon_mode, icon_state)
- self.baseStyle().drawItemPixmap(p, layouts.icon, Qt.AlignmentFlag.AlignCenter, icon)
+ self._base_style().drawItemPixmap(p, layouts.icon, Qt.AlignmentFlag.AlignCenter, icon)
def drawControl(self, element, opt, p, widget=None):
"""Override drawControl to draw odd tabs in a different color.
@@ -853,7 +863,7 @@ class TabBarStyle(QProxyStyle):
if element not in [QStyle.ControlElement.CE_TabBarTab, QStyle.ControlElement.CE_TabBarTabShape,
QStyle.ControlElement.CE_TabBarTabLabel]:
# Let the real style draw it.
- self.baseStyle().drawControl(element, opt, p, widget)
+ self._base_style().drawControl(element, opt, p, widget)
return
layouts = self._tab_layout(opt)
@@ -876,7 +886,7 @@ class TabBarStyle(QProxyStyle):
self._draw_icon(layouts, opt, p)
alignment = (config.cache['tabs.title.alignment'] |
Qt.AlignmentFlag.AlignVCenter | Qt.TextFlag.TextHideMnemonic)
- self.baseStyle().drawItemText(
+ self._base_style().drawItemText(
p,
layouts.text,
int(alignment),
@@ -906,7 +916,7 @@ class TabBarStyle(QProxyStyle):
QStyle.PixelMetric.PM_TabBarScrollButtonWidth]:
return 0
else:
- return self.baseStyle().pixelMetric(metric, option, widget)
+ return self._base_style().pixelMetric(metric, option, widget)
def subElementRect(self, sr, opt, widget=None):
"""Override subElementRect to use our own _tab_layout implementation.
@@ -936,7 +946,7 @@ class TabBarStyle(QProxyStyle):
# style differences...
return QCommonStyle.subElementRect(self, sr, opt, widget)
else:
- return self.baseStyle().subElementRect(sr, opt, widget)
+ return self._base_style().subElementRect(sr, opt, widget)
def _tab_layout(self, opt):
"""Compute the text/icon rect from the opt rect.
@@ -983,7 +993,7 @@ class TabBarStyle(QProxyStyle):
text_rect.adjust(
icon_rect.width() + TabBarStyle.ICON_PADDING, 0, 0, 0)
- text_rect = self.baseStyle().visualRect(opt.direction, opt.rect, text_rect)
+ text_rect = self._base_style().visualRect(opt.direction, opt.rect, text_rect)
return Layouts(text=text_rect, icon=icon_rect,
indicator=indicator_rect)
@@ -1018,5 +1028,5 @@ class TabBarStyle(QProxyStyle):
icon_top = text_rect.center().y() + 1 - tab_icon_size.height() // 2
icon_rect = QRect(QPoint(text_rect.left(), icon_top), tab_icon_size)
- icon_rect = self.baseStyle().visualRect(opt.direction, opt.rect, icon_rect)
+ icon_rect = self._base_style().visualRect(opt.direction, opt.rect, icon_rect)
return icon_rect
diff --git a/qutebrowser/misc/consolewidget.py b/qutebrowser/misc/consolewidget.py
index 6d8d9916f..641798190 100644
--- a/qutebrowser/misc/consolewidget.py
+++ b/qutebrowser/misc/consolewidget.py
@@ -125,6 +125,7 @@ class ConsoleTextEdit(QTextEdit):
self.moveCursor(QTextCursor.MoveOperation.End)
self.insertPlainText(text)
scrollbar = self.verticalScrollBar()
+ assert scrollbar is not None
scrollbar.setValue(scrollbar.maximum())
diff --git a/qutebrowser/misc/guiprocess.py b/qutebrowser/misc/guiprocess.py
index a50849d29..9f3b272f6 100644
--- a/qutebrowser/misc/guiprocess.py
+++ b/qutebrowser/misc/guiprocess.py
@@ -27,7 +27,7 @@ from typing import Mapping, Sequence, Dict, Optional
from qutebrowser.qt.core import (pyqtSlot, pyqtSignal, QObject, QProcess,
QProcessEnvironment, QByteArray, QUrl, Qt)
-from qutebrowser.utils import message, log, utils, usertypes, version
+from qutebrowser.utils import message, log, utils, usertypes, version, qtutils
from qutebrowser.api import cmdutils, apitypes
from qutebrowser.completion.models import miscmodels
@@ -394,7 +394,7 @@ class GUIProcess(QObject):
log.procs.debug("Starting process.")
self._pre_start(cmd, args)
self._proc.start(
- self.resolved_cmd, # type: ignore[arg-type]
+ qtutils.allow_none(self.resolved_cmd),
args,
)
self._post_start()
diff --git a/qutebrowser/misc/ipc.py b/qutebrowser/misc/ipc.py
index fb1b1ac22..05d9a6a33 100644
--- a/qutebrowser/misc/ipc.py
+++ b/qutebrowser/misc/ipc.py
@@ -28,7 +28,7 @@ from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, Qt
from qutebrowser.qt.network import QLocalSocket, QLocalServer, QAbstractSocket
import qutebrowser
-from qutebrowser.utils import log, usertypes, error, standarddir, utils, debug
+from qutebrowser.utils import log, usertypes, error, standarddir, utils, debug, qtutils
from qutebrowser.qt import sip
@@ -260,8 +260,8 @@ class IPCServer(QObject):
id(self._socket)))
return
socket = self._server.nextPendingConnection()
- if socket is None:
- log.ipc.debug( # type: ignore[unreachable]
+ if not qtutils.is_not_none(socket):
+ log.ipc.debug(
"No new connection to handle.")
return
log.ipc.debug("Client connected (socket 0x{:x}).".format(id(socket)))
diff --git a/qutebrowser/misc/miscwidgets.py b/qutebrowser/misc/miscwidgets.py
index ba33da775..f41cb9df4 100644
--- a/qutebrowser/misc/miscwidgets.py
+++ b/qutebrowser/misc/miscwidgets.py
@@ -25,7 +25,7 @@ from qutebrowser.qt.widgets import (QLineEdit, QWidget, QHBoxLayout, QLabel,
from qutebrowser.qt.gui import QValidator, QPainter, QResizeEvent
from qutebrowser.config import config, configfiles
-from qutebrowser.utils import utils, log, usertypes, debug
+from qutebrowser.utils import utils, log, usertypes, debug, qtutils
from qutebrowser.misc import cmdhistory
from qutebrowser.browser import inspector
from qutebrowser.keyinput import keyutils, modeman
@@ -185,7 +185,10 @@ class _FoldArrow(QWidget):
elem = QStyle.PrimitiveElement.PE_IndicatorArrowRight
else:
elem = QStyle.PrimitiveElement.PE_IndicatorArrowDown
- self.style().drawPrimitive(elem, opt, painter, self)
+
+ style = self.style()
+ assert style is not None
+ style.drawPrimitive(elem, opt, painter, self)
def minimumSizeHint(self):
"""Return a sensible size."""
@@ -241,10 +244,10 @@ class WrapperLayout(QLayout):
if self._widget is None:
return
assert self._container is not None
- self._widget.setParent(None) # type: ignore[call-overload]
+ self._widget.setParent(qtutils.allow_none(None))
self._widget.deleteLater()
self._widget = None
- self._container.setFocusProxy(None) # type: ignore[arg-type]
+ self._container.setFocusProxy(qtutils.allow_none(None))
class FullscreenNotification(QLabel):
@@ -270,9 +273,17 @@ class FullscreenNotification(QLabel):
self.resize(self.sizeHint())
if config.val.content.fullscreen.window:
- geom = self.parentWidget().geometry()
+ parent = self.parentWidget()
+ assert parent is not None
+ geom = parent.geometry()
else:
- geom = self.window().windowHandle().screen().geometry()
+ window = self.window()
+ assert window is not None
+ handle = window.windowHandle()
+ assert handle is not None
+ screen = handle.screen()
+ assert screen is not None
+ geom = screen.geometry()
self.move((geom.width() - self.sizeHint().width()) // 2, 30)
def set_timeout(self, timeout):
@@ -327,6 +338,8 @@ class InspectorSplitter(QSplitter):
main_widget = self.widget(self._main_idx)
inspector_widget = self.widget(self._inspector_idx)
+ assert main_widget is not None
+ assert inspector_widget is not None
if not inspector_widget.isVisible():
raise inspector.Error("No inspector inside main window")
@@ -439,8 +452,9 @@ class InspectorSplitter(QSplitter):
self._preferred_size = sizes[self._inspector_idx]
self._save_preferred_size()
- def resizeEvent(self, e: QResizeEvent) -> None:
+ def resizeEvent(self, e: Optional[QResizeEvent]) -> None:
"""Window resize event."""
+ assert e is not None
super().resizeEvent(e)
if self.count() == 2:
self._adjust_size()
diff --git a/qutebrowser/misc/nativeeventfilter.py b/qutebrowser/misc/nativeeventfilter.py
index 4562ea82d..5fad3359c 100644
--- a/qutebrowser/misc/nativeeventfilter.py
+++ b/qutebrowser/misc/nativeeventfilter.py
@@ -20,7 +20,7 @@
This entire file is a giant WORKAROUND for https://bugreports.qt.io/browse/QTBUG-114334.
"""
-from typing import Tuple, Union, cast
+from typing import Tuple, Union, cast, Optional
import enum
import ctypes
import ctypes.util
@@ -150,11 +150,12 @@ class NativeEventFilter(QAbstractNativeEventFilter):
xcb.xcb_disconnect(conn)
def nativeEventFilter(
- self, evtype: Union[bytes, QByteArray], message: sip.voidptr
+ self, evtype: Union[bytes, QByteArray], message: Optional[sip.voidptr]
) -> Tuple[bool, _PointerRetType]:
"""Handle XCB events."""
# We're only installed when the platform plugin is xcb
assert evtype == b"xcb_generic_event_t", evtype
+ assert message is not None
# We cast to xcb_ge_generic_event_t, which overlaps with xcb_generic_event_t.
# .extension and .event_type will only make sense if this is an
diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py
index a8b436d79..82de30702 100644
--- a/qutebrowser/utils/debug.py
+++ b/qutebrowser/utils/debug.py
@@ -68,6 +68,7 @@ def log_signals(obj: QObject) -> QObject:
def connect_log_slot(obj: QObject) -> None:
"""Helper function to connect all signals to a logging slot."""
metaobj = obj.metaObject()
+ assert metaobj is not None
for i in range(metaobj.methodCount()):
meta_method = metaobj.method(i)
qtutils.ensure_valid(meta_method)
diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py
index 521f52b5b..5ac150702 100644
--- a/qutebrowser/utils/log.py
+++ b/qutebrowser/utils/log.py
@@ -31,9 +31,10 @@ import json
import inspect
import argparse
from typing import (TYPE_CHECKING, Any, Iterator, Mapping, MutableSequence,
- Optional, Set, Tuple, Union, TextIO, Literal, cast)
+ Optional, Set, Tuple, Union, TextIO, Literal, cast, Callable)
from qutebrowser.qt import core as qtcore
+from qutebrowser.qt import machinery
# Optional imports
try:
import colorama
@@ -234,6 +235,19 @@ def _init_py_warnings() -> None:
def disable_qt_msghandler() -> Iterator[None]:
"""Contextmanager which temporarily disables the Qt message handler."""
old_handler = qtcore.qInstallMessageHandler(None)
+ if machinery.IS_QT6:
+ # cast str to Optional[str] to be compatible with PyQt6 type hints for
+ # qInstallMessageHandler
+ old_handler = cast(
+ Optional[
+ Callable[
+ [qtcore.QtMsgType, qtcore.QMessageLogContext, Optional[str]],
+ None
+ ]
+ ],
+ old_handler,
+ )
+
try:
yield
finally:
@@ -379,7 +393,7 @@ def change_console_formatter(level: int) -> None:
def qt_message_handler(msg_type: qtcore.QtMsgType,
context: qtcore.QMessageLogContext,
- msg: str) -> None:
+ msg: Optional[str]) -> None:
"""Qt message handler to redirect qWarning etc. to the logging system.
Args:
diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py
index cc34057ef..781e43f08 100644
--- a/qutebrowser/utils/qtutils.py
+++ b/qutebrowser/utils/qtutils.py
@@ -32,7 +32,7 @@ import pathlib
import operator
import contextlib
from typing import (Any, AnyStr, TYPE_CHECKING, BinaryIO, IO, Iterator,
- Optional, Union, Tuple, Protocol, cast)
+ Optional, Union, Tuple, Protocol, cast, TypeVar)
from qutebrowser.qt import machinery, sip
from qutebrowser.qt.core import (qVersion, QEventLoop, QDataStream, QByteArray,
@@ -46,6 +46,7 @@ except ImportError: # pragma: no cover
if TYPE_CHECKING:
from qutebrowser.qt.webkit import QWebHistory
from qutebrowser.qt.webenginecore import QWebEngineHistory
+ from typing_extensions import TypeGuard # added in Python 3.10
from qutebrowser.misc import objects
from qutebrowser.utils import usertypes, utils
@@ -102,7 +103,11 @@ def version_check(version: str,
parsed = utils.VersionNumber.parse(version)
op = operator.eq if exact else operator.ge
- result = op(utils.VersionNumber.parse(qVersion()), parsed)
+
+ qversion = qVersion()
+ assert qversion is not None
+ result = op(utils.VersionNumber.parse(qversion), parsed)
+
if compiled and result:
# qVersion() ==/>= parsed, now check if QT_VERSION_STR ==/>= parsed.
result = op(utils.VersionNumber.parse(QT_VERSION_STR), parsed)
@@ -535,24 +540,58 @@ def interpolate_color(
if colorspace is None:
if percent == 100:
- return QColor(*end.getRgb())
+ r, g, b, a = end.getRgb()
+ assert r is not None
+ assert g is not None
+ assert b is not None
+ assert a is not None
+ return QColor(r, g, b, a)
else:
- return QColor(*start.getRgb())
+ r, g, b, a = start.getRgb()
+ assert r is not None
+ assert g is not None
+ assert b is not None
+ assert a is not None
+ return QColor(r, g, b, a)
out = QColor()
if colorspace == QColor.Spec.Rgb:
r1, g1, b1, a1 = start.getRgb()
r2, g2, b2, a2 = end.getRgb()
+ assert r1 is not None
+ assert g1 is not None
+ assert b1 is not None
+ assert a1 is not None
+ assert r2 is not None
+ assert g2 is not None
+ assert b2 is not None
+ assert a2 is not None
components = _get_color_percentage(r1, g1, b1, a1, r2, g2, b2, a2, percent)
out.setRgb(*components)
elif colorspace == QColor.Spec.Hsv:
h1, s1, v1, a1 = start.getHsv()
h2, s2, v2, a2 = end.getHsv()
+ assert h1 is not None
+ assert s1 is not None
+ assert v1 is not None
+ assert a1 is not None
+ assert h2 is not None
+ assert s2 is not None
+ assert v2 is not None
+ assert a2 is not None
components = _get_color_percentage(h1, s1, v1, a1, h2, s2, v2, a2, percent)
out.setHsv(*components)
elif colorspace == QColor.Spec.Hsl:
h1, s1, l1, a1 = start.getHsl()
h2, s2, l2, a2 = end.getHsl()
+ assert h1 is not None
+ assert s1 is not None
+ assert l1 is not None
+ assert a1 is not None
+ assert h2 is not None
+ assert s2 is not None
+ assert l2 is not None
+ assert a2 is not None
components = _get_color_percentage(h1, s1, l1, a1, h2, s2, l2, a2, percent)
out.setHsl(*components)
else:
@@ -611,3 +650,21 @@ def extract_enum_val(val: Union[sip.simplewrapper, int, enum.Enum]) -> int:
elif isinstance(val, sip.simplewrapper):
return int(val) # type: ignore[call-overload]
return val
+
+T = TypeVar("T")
+
+def is_not_none(obj: Optional[T]) -> "TypeGuard[T]":
+ """Check if a Qt object is None.
+
+ PyQt6 marks things as Optional[...], but PyQt5 doesn't.
+ By using this function, we can use the same type hints for both.
+ """
+ return obj is not None
+
+
+if machinery.IS_QT5:
+ def allow_none(obj: Optional[T]) -> T:
+ return cast(T, obj)
+else:
+ def allow_none(obj: Optional[T]) -> Optional[T]:
+ return obj
diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py
index 884a26376..762125c11 100644
--- a/qutebrowser/utils/standarddir.py
+++ b/qutebrowser/utils/standarddir.py
@@ -28,7 +28,7 @@ from typing import Iterator, Optional
from qutebrowser.qt.core import QStandardPaths
from qutebrowser.qt.widgets import QApplication
-from qutebrowser.utils import log, debug, utils, version
+from qutebrowser.utils import log, debug, utils, version, qtutils
# The cached locations
_locations = {}
@@ -65,7 +65,7 @@ def _unset_organization() -> Iterator[None]:
qapp = QApplication.instance()
if qapp is not None:
orgname = qapp.organizationName()
- qapp.setOrganizationName(None) # type: ignore[arg-type]
+ qapp.setOrganizationName(qtutils.allow_none(None))
try:
yield
finally:
diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py
index e00c9dab2..b3f03b256 100644
--- a/qutebrowser/utils/urlutils.py
+++ b/qutebrowser/utils/urlutils.py
@@ -179,9 +179,9 @@ def _get_search_url(txt: str) -> QUrl:
url = QUrl.fromUserInput(evaluated)
else:
url = QUrl.fromUserInput(config.val.url.searchengines[engine])
- url.setPath(None) # type: ignore[arg-type]
- url.setFragment(None) # type: ignore[arg-type]
- url.setQuery(None) # type: ignore[call-overload]
+ url.setPath(qtutils.allow_none(None))
+ url.setFragment(qtutils.allow_none(None))
+ url.setQuery(qtutils.allow_none(None))
qtutils.ensure_valid(url)
return url
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index 6b450aa29..dd3cf6ac3 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -519,6 +519,13 @@ def sanitize_filename(name: str,
return name
+def _clipboard() -> QClipboard:
+ """Get the QClipboard and make sure it's not None."""
+ clipboard = QApplication.clipboard()
+ assert clipboard is not None
+ return clipboard
+
+
def set_clipboard(data: str, selection: bool = False) -> None:
"""Set the clipboard to some given data."""
global fake_clipboard
@@ -530,7 +537,7 @@ def set_clipboard(data: str, selection: bool = False) -> None:
fake_clipboard = data
else:
mode = QClipboard.Mode.Selection if selection else QClipboard.Mode.Clipboard
- QApplication.clipboard().setText(data, mode=mode)
+ _clipboard().setText(data, mode=mode)
def get_clipboard(selection: bool = False, fallback: bool = False) -> str:
@@ -556,7 +563,7 @@ def get_clipboard(selection: bool = False, fallback: bool = False) -> str:
fake_clipboard = None
else:
mode = QClipboard.Mode.Selection if selection else QClipboard.Mode.Clipboard
- data = QApplication.clipboard().text(mode=mode)
+ data = _clipboard().text(mode=mode)
target = "Primary selection" if selection else "Clipboard"
if not data.strip():
@@ -568,7 +575,7 @@ def get_clipboard(selection: bool = False, fallback: bool = False) -> str:
def supports_selection() -> bool:
"""Check if the OS supports primary selection."""
- return QApplication.clipboard().supportsSelection()
+ return _clipboard().supportsSelection()
def open_file(filename: str, cmdline: str = None) -> None:
diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py
index 782261745..358e8e19b 100644
--- a/qutebrowser/utils/version.py
+++ b/qutebrowser/utils/version.py
@@ -886,7 +886,10 @@ def version_info() -> str:
if objects.qapp:
style = objects.qapp.style()
- lines.append('Style: {}'.format(style.metaObject().className()))
+ assert style is not None
+ metaobj = style.metaObject()
+ assert metaobj is not None
+ lines.append('Style: {}'.format(metaobj.className()))
lines.append('Platform plugin: {}'.format(objects.qapp.platformName()))
lines.append('OpenGL: {}'.format(opengl_info()))
@@ -1005,7 +1008,7 @@ def opengl_info() -> Optional[OpenGLInfo]: # pragma: no cover
vendor, version = override.split(', ', maxsplit=1)
return OpenGLInfo.parse(vendor=vendor, version=version)
- old_context = cast(Optional[QOpenGLContext], QOpenGLContext.currentContext())
+ old_context: Optional[QOpenGLContext] = QOpenGLContext.currentContext()
old_surface = None if old_context is None else old_context.surface()
surface = QOffscreenSurface()