qt6: Switch most tooling/linting to Qt 6

Only mypy missing now...
This commit is contained in:
Florian Bruhin 2023-06-24 00:28:05 +02:00
parent 0ac074575d
commit ffc06e58d6
18 changed files with 108 additions and 116 deletions

View File

@ -16,50 +16,50 @@ jobs:
include:
- os: macos-11
branch: master
toxenv: build-release-qt5
name: qt5-macos
- os: windows-2019
args: --64bit
branch: master
toxenv: build-release-qt5
name: qt5-windows-64bit
- os: windows-2019
args: --32bit
branch: master
toxenv: build-release-qt5
name: qt5-windows-32bit
- os: macos-11
args: --debug
branch: master
toxenv: build-release-qt5
name: qt5-macos-debug
- os: windows-2019
args: --64bit --debug
branch: master
toxenv: build-release-qt5
name: qt5-windows-64bit-debug
- os: windows-2019
args: --32bit --debug
branch: master
toxenv: build-release-qt5
name: qt5-windows-32bit-debug
- os: macos-11
toxenv: build-release
name: macos
- os: windows-2019
args: --64bit
branch: master
toxenv: build-release
name: windows-64bit
- os: windows-2019
args: --32bit
branch: master
toxenv: build-release
name: windows-32bit
- os: macos-11
args: --debug
branch: master
toxenv: build-release
name: macos-debug
- os: windows-2019
args: --64bit --debug
branch: master
toxenv: build-release
name: windows-64bit-debug
- os: windows-2019
args: --32bit --debug
branch: master
toxenv: build-release
name: windows-32bit-debug
- os: macos-11
toxenv: build-release-qt6
name: qt6-macos
- os: windows-2019
args: --64bit
toxenv: build-release-qt6
name: qt6-windows-64bit
- os: macos-11
args: --debug
toxenv: build-release-qt6
name: qt6-macos-debug
- os: windows-2019
args: --64bit --debug
toxenv: build-release-qt6
name: qt6-windows-64bit-debug
runs-on: "${{ matrix.os }}"
timeout-minutes: 45
steps:

View File

@ -1,6 +1,6 @@
[MASTER]
ignore=resources.py
extension-pkg-whitelist=PyQt5,sip
extension-pkg-whitelist=PyQt5,PyQt6,sip
load-plugins=qute_pylint.config,
pylint.extensions.docstyle,
pylint.extensions.emptystring,

View File

@ -82,7 +82,7 @@ def get_data_files():
def get_hidden_imports():
imports = [] if "PYINSTALLER_QT6" in os.environ else ['PyQt5.QtOpenGL']
imports = ["PyQt5.QtOpenGL"] if "PYINSTALLER_QT5" in os.environ else []
for info in loader.walk_components():
imports.append(info.name)
return imports

View File

@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
PyQt5==5.15.9
PyQt5-Qt5==5.15.2
PyQt5-sip==12.12.1
PyQtWebEngine==5.15.6
PyQtWebEngine-Qt5==5.15.2
PyQt6==6.5.1
PyQt6-Qt6==6.5.1
PyQt6-sip==13.5.1
PyQt6-WebEngine==6.5.0
PyQt6-WebEngine-Qt6==6.5.1

View File

@ -1,2 +1,4 @@
PyQt5
PyQtWebEngine
PyQt6
PyQt6-Qt6
PyQt6-WebEngine
PyQt6-WebEngine-Qt6

View File

@ -15,16 +15,15 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""QtWebKit specific part of the web element API."""
from typing import cast, TYPE_CHECKING, Iterator, List, Optional, Set
from qutebrowser.qt.core import QRect, Qt
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkit import QWebElement, QWebSettings
from qutebrowser.qt.webkitwidgets import QWebFrame
# pylint: enable=no-name-in-module
from qutebrowser.config import config
from qutebrowser.utils import log, utils, javascript, usertypes

View File

@ -15,14 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""QtWebKit specific part of history."""
import functools
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkit import QWebHistoryInterface
# pylint: enable=no-name-in-module
from qutebrowser.utils import debug
from qutebrowser.misc import debugcachestats

View File

@ -15,13 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""Customized QWebInspector for QtWebKit."""
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkit import QWebSettings
from qutebrowser.qt.webkitwidgets import QWebInspector, QWebPage
# pylint: enable=no-name-in-module
from qutebrowser.qt.widgets import QWidget
from qutebrowser.browser import inspector

View File

@ -15,9 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""Bridge from QWebSettings to our own settings.
Module attributes:
@ -30,8 +27,10 @@ import os.path
from qutebrowser.qt.core import QUrl
from qutebrowser.qt.gui import QFont
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkit import QWebSettings
from qutebrowser.qt.webkitwidgets import QWebPage
# pylint: enable=no-name-in-module
from qutebrowser.config import config, websettings
from qutebrowser.config.websettings import AttributeInfo as Attr

View File

@ -15,8 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""Wrapper over our (QtWebKit) WebView."""
@ -28,8 +26,10 @@ from typing import cast, Iterable, Optional
from qutebrowser.qt.core import pyqtSlot, Qt, QUrl, QPoint, QTimer, QSizeF, QSize
from qutebrowser.qt.gui import QIcon
from qutebrowser.qt.widgets import QWidget
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkitwidgets import QWebPage, QWebFrame
from qutebrowser.qt.webkit import QWebSettings, QWebHistory, QWebElement
# pylint: enable=no-name-in-module
from qutebrowser.qt.printsupport import QPrinter
from qutebrowser.browser import browsertab, shared

View File

@ -15,9 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""The main browser widgets."""
import html
@ -28,7 +25,9 @@ from qutebrowser.qt.gui import QDesktopServices
from qutebrowser.qt.network import QNetworkReply, QNetworkRequest
from qutebrowser.qt.widgets import QFileDialog
from qutebrowser.qt.printsupport import QPrintDialog
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkitwidgets import QWebPage, QWebFrame
# pylint: enable=no-name-in-module
from qutebrowser.config import websettings, config
from qutebrowser.browser import pdfjs, shared, downloads, greasemonkey

View File

@ -15,14 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""The main browser widgets."""
from qutebrowser.qt.core import pyqtSignal, Qt
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkit import QWebSettings
from qutebrowser.qt.webkitwidgets import QWebView, QWebPage
# pylint: enable=no-name-in-module
from qutebrowser.config import config, stylesheet
from qutebrowser.keyinput import modeman

View File

@ -37,9 +37,7 @@ from qutebrowser.qt import machinery
from qutebrowser.qt.core import Qt, QEvent
from qutebrowser.qt.gui import QKeySequence, QKeyEvent
if machinery.IS_QT6:
# FIXME:qt6 (lint) how come pylint isn't picking this up with both backends
# installed?
from qutebrowser.qt.core import QKeyCombination # pylint: disable=no-name-in-module
from qutebrowser.qt.core import QKeyCombination
else:
QKeyCombination = None # QKeyCombination was added in Qt 6

View File

@ -1,4 +1,4 @@
# pylint: disable=import-error,wildcard-import,unused-import
# pylint: disable=import-error,wildcard-import,unused-import,unused-wildcard-import
"""Wrapped Qt imports for Qt OpenGL.

View File

@ -136,7 +136,7 @@ def _smoke_test_run(
return subprocess.run(argv, check=True, capture_output=True)
def smoke_test(executable: pathlib.Path, debug: bool, qt6: bool) -> None:
def smoke_test(executable: pathlib.Path, debug: bool, qt5: bool) -> None:
"""Try starting the given qutebrowser executable."""
stdout_whitelist = []
stderr_whitelist = [
@ -176,7 +176,7 @@ def smoke_test(executable: pathlib.Path, debug: bool, qt6: bool) -> None:
r'ContextResult::kTransientFailure: Failed to send '
r'.*CreateCommandBuffer\.'),
])
if qt6:
if not qt5:
stderr_whitelist.extend([
# FIXME:qt6 Qt 6.3 on macOS
r'[0-9:]* WARNING: Incompatible version of OpenSSL',
@ -257,10 +257,10 @@ def verify_windows_exe(exe_path: pathlib.Path) -> None:
assert pe.verify_checksum()
def patch_mac_app(qt6: bool) -> None:
def patch_mac_app(qt5: bool) -> None:
"""Patch .app to save some space and make it signable."""
dist_path = pathlib.Path('dist')
ver = '6' if qt6 else '5'
ver = '5' if qt5 else '6'
app_path = dist_path / 'qutebrowser.app'
contents_path = app_path / 'Contents'
@ -280,7 +280,7 @@ def patch_mac_app(qt6: bool) -> None:
file_path.unlink()
file_path.symlink_to(target)
if qt6:
if not qt5:
# Symlinking QtWebEngineCore.framework does not seem to work with Qt 6.
# Also, the symlinking/moving before signing doesn't seem to be required.
return
@ -333,7 +333,7 @@ def _mac_bin_path(base: pathlib.Path) -> pathlib.Path:
def build_mac(
*,
gh_token: Optional[str],
qt6: bool,
qt5: bool,
skip_packaging: bool,
debug: bool,
) -> List[Artifact]:
@ -348,20 +348,20 @@ def build_mac(
shutil.rmtree(d, ignore_errors=True)
utils.print_title("Updating 3rdparty content")
update_3rdparty.run(ace=False, pdfjs=True, legacy_pdfjs=not qt6, fancy_dmg=False,
update_3rdparty.run(ace=False, pdfjs=True, legacy_pdfjs=qt5, fancy_dmg=False,
gh_token=gh_token)
utils.print_title("Building .app via pyinstaller")
call_tox(f'pyinstaller-64bit{"-qt6" if qt6 else ""}', '-r', debug=debug)
call_tox(f'pyinstaller-64bit{"-qt5" if qt5 else ""}', '-r', debug=debug)
utils.print_title("Patching .app")
patch_mac_app(qt6=qt6)
patch_mac_app(qt5=qt5)
utils.print_title("Re-signing .app")
sign_mac_app()
dist_path = pathlib.Path("dist")
utils.print_title("Running pre-dmg smoke test")
smoke_test(_mac_bin_path(dist_path), debug=debug, qt6=qt6)
smoke_test(_mac_bin_path(dist_path), debug=debug, qt5=qt5)
if skip_packaging:
return []
@ -371,7 +371,7 @@ def build_mac(
subprocess.run(['make', '-f', dmg_makefile_path], check=True)
suffix = "-debug" if debug else ""
suffix += "-qt6" if qt6 else ""
suffix += "-qt5" if qt5 else ""
dmg_path = dist_path / f'qutebrowser-{qutebrowser.__version__}{suffix}.dmg'
pathlib.Path('qutebrowser.dmg').rename(dmg_path)
@ -383,7 +383,7 @@ def build_mac(
subprocess.run(['hdiutil', 'attach', dmg_path,
'-mountpoint', tmp_path], check=True)
try:
smoke_test(_mac_bin_path(tmp_path), debug=debug, qt6=qt6)
smoke_test(_mac_bin_path(tmp_path), debug=debug, qt5=qt5)
finally:
print("Waiting 10s for dmg to be detachable...")
time.sleep(10)
@ -422,7 +422,7 @@ def _get_windows_python_path(x64: bool) -> pathlib.Path:
def _build_windows_single(
*, x64: bool,
qt6: bool,
qt5: bool,
skip_packaging: bool,
debug: bool,
) -> List[Artifact]:
@ -437,9 +437,9 @@ def _build_windows_single(
python = _get_windows_python_path(x64=x64)
suffix = "64bit" if x64 else "32bit"
if qt6:
if qt5:
# FIXME:qt6 does this regress 391623d5ec983ecfc4512c7305c4b7a293ac3872?
suffix += "-qt6"
suffix += "-qt5"
call_tox(f'pyinstaller-{suffix}', '-r', python=python, debug=debug)
out_pyinstaller = dist_path / "qutebrowser"
@ -450,7 +450,7 @@ def _build_windows_single(
verify_windows_exe(exe_path)
utils.print_title(f"Running {human_arch} smoke test")
smoke_test(exe_path, debug=debug, qt6=qt6)
smoke_test(exe_path, debug=debug, qt5=qt5)
if skip_packaging:
return []
@ -463,7 +463,7 @@ def _build_windows_single(
desc_arch=human_arch,
desc_suffix='' if x64 else ' (only for 32-bit Windows!)',
debug=debug,
qt6=qt6,
qt5=qt5,
)
@ -472,12 +472,12 @@ def build_windows(
skip_packaging: bool,
only_32bit: bool,
only_64bit: bool,
qt6: bool,
qt5: bool,
debug: bool,
) -> List[Artifact]:
"""Build windows executables/setups."""
utils.print_title("Updating 3rdparty content")
update_3rdparty.run(nsis=True, ace=False, pdfjs=True, legacy_pdfjs=not qt6,
update_3rdparty.run(nsis=True, ace=False, pdfjs=True, legacy_pdfjs=qt5,
fancy_dmg=False, gh_token=gh_token)
utils.print_title("Building Windows binaries")
@ -493,14 +493,14 @@ def build_windows(
x64=True,
skip_packaging=skip_packaging,
debug=debug,
qt6=qt6,
qt5=qt5,
)
if not only_64bit and not qt6:
if not only_64bit and not qt5:
artifacts += _build_windows_single(
x64=False,
skip_packaging=skip_packaging,
debug=debug,
qt6=qt6,
qt5=qt5,
)
return artifacts
@ -514,7 +514,7 @@ def _package_windows_single(
desc_suffix: str,
filename_arch: str,
debug: bool,
qt6: bool,
qt5: bool,
) -> List[Artifact]:
"""Build the given installer/zip for windows."""
artifacts = []
@ -532,8 +532,8 @@ def _package_windows_single(
]
if debug:
name_parts.append('debug')
if qt6:
name_parts.append('qt6')
if qt5:
name_parts.append('qt5')
name = '-'.join(name_parts) + '.exe'
artifacts.append(Artifact(
@ -552,8 +552,8 @@ def _package_windows_single(
]
if debug:
zip_name_parts.append('debug')
if qt6:
zip_name_parts.append('qt6')
if qt5:
zip_name_parts.append('qt5')
zip_name = '-'.join(zip_name_parts) + '.zip'
zip_path = dist_path / zip_name
@ -738,8 +738,8 @@ def main() -> None:
help="Skip Windows 32 bit build.", dest='only_64bit')
parser.add_argument('--debug', action='store_true', required=False,
help="Build a debug build.")
parser.add_argument('--qt6', action='store_true', required=False,
help="Build against PyQt6")
parser.add_argument('--qt5', action='store_true', required=False,
help="Build against PyQt5")
args = parser.parse_args()
utils.change_cwd()
@ -768,14 +768,14 @@ def main() -> None:
skip_packaging=args.skip_packaging,
only_32bit=args.only_32bit,
only_64bit=args.only_64bit,
qt6=args.qt6,
qt5=args.qt5,
debug=args.debug,
)
elif IS_MACOS:
artifacts = build_mac(
gh_token=gh_token,
skip_packaging=args.skip_packaging,
qt6=args.qt6,
qt5=args.qt5,
debug=args.debug,
)
else:

View File

@ -15,9 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""Tests for webelement.tabhistory."""
import dataclasses
@ -26,7 +23,9 @@ from typing import Any
import pytest
pytest.importorskip('qutebrowser.qt.webkit')
from qutebrowser.qt.core import QUrl, QPoint
# pylint: disable=no-name-in-module
from qutebrowser.qt.webkit import QWebHistory
# pylint: enable=no-name-in-module
from qutebrowser.browser.webkit import tabhistory
from qutebrowser.misc.sessions import TabHistoryItem as Item

View File

@ -15,9 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
# FIXME:qt6 (lint)
# pylint: disable=no-name-in-module
"""Check how Qt behaves when trying to execute JS."""
@ -29,7 +26,7 @@ def test_simple_js_webkit(webview, js_enabled, expected):
"""With QtWebKit, evaluateJavaScript works when JS is on."""
# If we get there (because of the webview fixture) we can be certain
# QtWebKit is available
from qutebrowser.qt.webkit import QWebSettings
from qutebrowser.qt.webkit import QWebSettings # pylint: disable=no-name-in-module
webview.settings().setAttribute(QWebSettings.WebAttribute.JavascriptEnabled, js_enabled)
result = webview.page().mainFrame().evaluateJavaScript('1 + 1')
assert result == expected
@ -40,7 +37,7 @@ def test_element_js_webkit(webview, js_enabled, expected):
"""With QtWebKit, evaluateJavaScript on an element works with JS off."""
# If we get there (because of the webview fixture) we can be certain
# QtWebKit is available
from qutebrowser.qt.webkit import QWebSettings
from qutebrowser.qt.webkit import QWebSettings # pylint: disable=no-name-in-module
webview.settings().setAttribute(QWebSettings.WebAttribute.JavascriptEnabled, js_enabled)
elem = webview.page().mainFrame().documentElement()
result = elem.evaluateJavaScript('1 + 1')

31
tox.ini
View File

@ -11,10 +11,10 @@ minversion = 3.20
[testenv]
setenv =
PYTEST_QT_API=pyqt5
QUTE_QT_WRAPPER=PyQt5
pyqt{62,63,64,65}: PYTEST_QT_API=pyqt6
pyqt{62,63,64,65}: QUTE_QT_WRAPPER=PyQt6
PYTEST_QT_API=pyqt6
QUTE_QT_WRAPPER=PyQt6
pyqt{515,5152}: PYTEST_QT_API=pyqt5
pyqt{515,5152}: QUTE_QT_WRAPPER=PyQt5
cov: PYTEST_ADDOPTS=--cov --cov-report xml --cov-report=html --cov-report=
py312: VIRTUALENV_PIP=23.1.2
py312: PIP_REQUIRE_VIRTUALENV=0
@ -110,6 +110,7 @@ deps =
-r{toxinidir}/misc/requirements/requirements-tests.txt
-r{toxinidir}/misc/requirements/requirements-pylint.txt
-r{toxinidir}/misc/requirements/requirements-pyqt.txt
-r{toxinidir}/misc/requirements/requirements-pyqt-5.txt
commands =
{envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no {posargs}
{envpython} scripts/dev/run_pylint_on_tests.py {toxinidir} --output-format=colorized --reports=no {posargs}
@ -178,19 +179,19 @@ commands =
{envpython} scripts/dev/check_doc_changes.py {posargs}
{envpython} scripts/asciidoc2html.py {posargs}
[testenv:pyinstaller-{64bit,32bit}{,-qt6}]
[testenv:pyinstaller-{64bit,32bit}{,-qt5}]
basepython = {env:PYTHON:python3}
passenv =
APPDATA
HOME
PYINSTALLER_DEBUG
setenv =
qt6: PYINSTALLER_QT6=true
qt5: PYINSTALLER_QT5=true
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/misc/requirements/requirements-pyinstaller.txt
!qt6: -r{toxinidir}/misc/requirements/requirements-pyqt.txt
qt6: -r{toxinidir}/misc/requirements/requirements-pyqt-6.txt
!qt5: -r{toxinidir}/misc/requirements/requirements-pyqt-6.txt
qt5: -r{toxinidir}/misc/requirements/requirements-pyqt-5.txt
commands =
{envbindir}/pyinstaller --noconfirm misc/qutebrowser.spec
@ -261,21 +262,21 @@ deps =
commands =
{envpython} -m sphinx -jauto -W --color {posargs} {toxinidir}/doc/extapi/ {toxinidir}/doc/extapi/_build/
[testenv:build-release{,-qt6}]
[testenv:build-release{,-qt5}]
basepython = {env:PYTHON:python3}
passenv = *
# Override default PyQt5 from [testenv]
# Override default PyQt6 from [testenv]
setenv =
qt6: QUTE_QT_WRAPPER=PyQt6
qt5: QUTE_QT_WRAPPER=PyQt5
usedevelop = true
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/misc/requirements/requirements-tox.txt
-r{toxinidir}/misc/requirements/requirements-docs.txt
!qt6: -r{toxinidir}/misc/requirements/requirements-pyqt.txt
qt6: -r{toxinidir}/misc/requirements/requirements-pyqt-6.txt
!qt5: -r{toxinidir}/misc/requirements/requirements-pyqt.txt
qt5: -r{toxinidir}/misc/requirements/requirements-pyqt-5.txt
-r{toxinidir}/misc/requirements/requirements-dev.txt
-r{toxinidir}/misc/requirements/requirements-pyinstaller.txt
commands =
!qt6: {envpython} {toxinidir}/scripts/dev/build_release.py {posargs}
qt6: {envpython} {toxinidir}/scripts/dev/build_release.py --qt6 {posargs}
!qt5: {envpython} {toxinidir}/scripts/dev/build_release.py {posargs}
qt5: {envpython} {toxinidir}/scripts/dev/build_release.py --qt5 {posargs}