Merge remote-tracking branch 'origin/pr/7789'
This commit is contained in:
commit
273230eb07
|
|
@ -56,7 +56,8 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
[[ ${{ matrix.testenv }} == eslint ]] && npm install -g eslint
|
[[ ${{ matrix.testenv }} == eslint ]] && npm install -g eslint
|
||||||
[[ ${{ matrix.testenv }} == docs ]] && sudo apt-get update && sudo apt-get install --no-install-recommends asciidoc
|
[[ ${{ matrix.testenv }} == docs ]] && sudo apt-get update && sudo apt-get install --no-install-recommends asciidoc libegl1-mesa
|
||||||
|
[[ ${{ matrix.testenv }} == vulture || ${{ matrix.testenv }} == pylint ]] && sudo apt-get update && sudo apt-get install --no-install-recommends libegl1-mesa
|
||||||
if [[ ${{ matrix.testenv }} == shellcheck ]]; then
|
if [[ ${{ matrix.testenv }} == shellcheck ]]; then
|
||||||
scversion="stable"
|
scversion="stable"
|
||||||
bindir="$HOME/.local/bin"
|
bindir="$HOME/.local/bin"
|
||||||
|
|
@ -89,17 +90,16 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- testenv: py
|
- testenv: py-qt5
|
||||||
image: archlinux-webkit
|
image: archlinux-webkit
|
||||||
- testenv: py
|
- testenv: py-qt5
|
||||||
image: archlinux-webengine
|
image: archlinux-webengine
|
||||||
- testenv: py-qt6
|
- testenv: py-qt5
|
||||||
|
image: archlinux-webengine-unstable
|
||||||
|
- testenv: py
|
||||||
image: archlinux-webengine-qt6
|
image: archlinux-webengine-qt6
|
||||||
- testenv: py
|
- testenv: py
|
||||||
image: archlinux-webengine-unstable
|
image: archlinux-webengine-unstable-qt6
|
||||||
args: ""
|
|
||||||
# - testenv: py
|
|
||||||
# image: archlinux-webengine-unstable-qt6 # FIXME:qt6.5 activate
|
|
||||||
container:
|
container:
|
||||||
image: "qutebrowser/ci:${{ matrix.image }}"
|
image: "qutebrowser/ci:${{ matrix.image }}"
|
||||||
env:
|
env:
|
||||||
|
|
@ -115,9 +115,9 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up problem matchers
|
- name: Set up problem matchers
|
||||||
run: "python scripts/dev/ci/problemmatchers.py py38 ${{ runner.temp }}"
|
run: "python scripts/dev/ci/problemmatchers.py tests ${{ runner.temp }}"
|
||||||
- name: Run tox
|
- name: Run tox
|
||||||
run: "dbus-run-session -- tox -e ${{ matrix.testenv }} -- ${{ matrix.args }}"
|
run: "dbus-run-session -- tox -e ${{ matrix.testenv }}"
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ jobs:
|
||||||
- archlinux-webkit
|
- archlinux-webkit
|
||||||
- archlinux-webengine
|
- archlinux-webengine
|
||||||
- archlinux-webengine-unstable
|
- archlinux-webengine-unstable
|
||||||
|
- archlinux-webengine-unstable-qt6
|
||||||
- archlinux-webengine-qt6
|
- archlinux-webengine-qt6
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
|
||||||
|
|
@ -16,50 +16,50 @@ jobs:
|
||||||
include:
|
include:
|
||||||
- os: macos-11
|
- os: macos-11
|
||||||
branch: master
|
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
|
toxenv: build-release
|
||||||
name: macos
|
name: macos
|
||||||
- os: windows-2019
|
- os: windows-2019
|
||||||
args: --64bit
|
args: --64bit
|
||||||
branch: master
|
|
||||||
toxenv: build-release
|
toxenv: build-release
|
||||||
name: windows-64bit
|
name: windows-64bit
|
||||||
- os: windows-2019
|
|
||||||
args: --32bit
|
|
||||||
branch: master
|
|
||||||
toxenv: build-release
|
|
||||||
name: windows-32bit
|
|
||||||
|
|
||||||
- os: macos-11
|
- os: macos-11
|
||||||
args: --debug
|
args: --debug
|
||||||
branch: master
|
|
||||||
toxenv: build-release
|
toxenv: build-release
|
||||||
name: macos-debug
|
name: macos-debug
|
||||||
- os: windows-2019
|
- os: windows-2019
|
||||||
args: --64bit --debug
|
args: --64bit --debug
|
||||||
branch: master
|
|
||||||
toxenv: build-release
|
toxenv: build-release
|
||||||
name: windows-64bit-debug
|
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 }}"
|
runs-on: "${{ matrix.os }}"
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[MASTER]
|
[MASTER]
|
||||||
ignore=resources.py
|
ignore=resources.py
|
||||||
extension-pkg-whitelist=PyQt5,sip
|
extension-pkg-whitelist=PyQt5,PyQt6,sip
|
||||||
load-plugins=qute_pylint.config,
|
load-plugins=qute_pylint.config,
|
||||||
pylint.extensions.docstyle,
|
pylint.extensions.docstyle,
|
||||||
pylint.extensions.emptystring,
|
pylint.extensions.emptystring,
|
||||||
|
|
@ -58,8 +58,8 @@ disable=locally-disabled,
|
||||||
missing-type-doc,
|
missing-type-doc,
|
||||||
missing-param-doc,
|
missing-param-doc,
|
||||||
useless-param-doc,
|
useless-param-doc,
|
||||||
wrong-import-order, # FIXME:qt6 (lint)
|
wrong-import-order, # doesn't work with qutebrowser.qt, even with known-third-party set
|
||||||
ungrouped-imports, # FIXME:qt6 (lint)
|
ungrouped-imports, # ditto
|
||||||
|
|
||||||
[BASIC]
|
[BASIC]
|
||||||
function-rgx=[a-z_][a-z0-9_]{2,50}$
|
function-rgx=[a-z_][a-z0-9_]{2,50}$
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,17 @@ breaking changes (such as renamed commands) can happen in minor releases.
|
||||||
v3.0.0 (unreleased)
|
v3.0.0 (unreleased)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
Major changes
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- qutebrowser now supports Qt 6 and uses it by default. Qt 5.15 is used as a
|
||||||
|
fallback if Qt 6 is unavailable. This behavior can be customized in three ways
|
||||||
|
(in order of precedence):
|
||||||
|
* Via `--qt-wrapper PyQt5` or `--qt-wrapper PyQt6` command-line arguments.
|
||||||
|
* Via the `QUTE_QT_WRAPPER` environment variable, set to `PyQt6` or `PyQt5`.
|
||||||
|
* For packagers wanting to provide packages specific to a Qt version,
|
||||||
|
patch `qutebrowser/qt/machinery.py` and set `_WRAPPER_OVERRIDE`.
|
||||||
|
|
||||||
Added
|
Added
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ def get_data_files():
|
||||||
|
|
||||||
|
|
||||||
def get_hidden_imports():
|
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():
|
for info in loader.walk_components():
|
||||||
imports.append(info.name)
|
imports.append(info.name)
|
||||||
return imports
|
return imports
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||||
|
|
||||||
PyQt5==5.15.9
|
PyQt6==6.5.1
|
||||||
PyQt5-Qt5==5.15.2
|
PyQt6-Qt6==6.5.1
|
||||||
PyQt5-sip==12.12.1
|
PyQt6-sip==13.5.1
|
||||||
PyQtWebEngine==5.15.6
|
PyQt6-WebEngine==6.5.0
|
||||||
PyQtWebEngine-Qt5==5.15.2
|
PyQt6-WebEngine-Qt6==6.5.1
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,4 @@
|
||||||
PyQt5
|
PyQt6
|
||||||
PyQtWebEngine
|
PyQt6-Qt6
|
||||||
|
PyQt6-WebEngine
|
||||||
|
PyQt6-WebEngine-Qt6
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ from json import dumps
|
||||||
from os import environ, path
|
from os import environ, path
|
||||||
from sys import argv, exit
|
from sys import argv, exit
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication, QInputDialog, QLineEdit
|
from PyQt6.QtWidgets import QApplication, QInputDialog, QLineEdit
|
||||||
from requests import get, post
|
from requests import get, post
|
||||||
from requests.auth import HTTPBasicAuth
|
from requests.auth import HTTPBasicAuth
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ def get_text(name, info):
|
||||||
None,
|
None,
|
||||||
"add-nextcloud-bookmarks userscript",
|
"add-nextcloud-bookmarks userscript",
|
||||||
"Please enter {}".format(info),
|
"Please enter {}".format(info),
|
||||||
QLineEdit.Password,
|
QLineEdit.EchoMode.Password,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
text, ok = QInputDialog.getText(
|
text, ok = QInputDialog.getText(
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import configparser
|
||||||
from os import environ, path
|
from os import environ, path
|
||||||
from sys import argv, exit
|
from sys import argv, exit
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication, QInputDialog, QLineEdit
|
from PyQt6.QtWidgets import QApplication, QInputDialog, QLineEdit
|
||||||
from requests import post
|
from requests import post
|
||||||
from requests.auth import HTTPBasicAuth
|
from requests.auth import HTTPBasicAuth
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ def get_text(name, info):
|
||||||
None,
|
None,
|
||||||
"add-nextcloud-cookbook userscript",
|
"add-nextcloud-cookbook userscript",
|
||||||
"Please enter {}".format(info),
|
"Please enter {}".format(info),
|
||||||
QLineEdit.Password,
|
QLineEdit.EchoMode.Password,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
text, ok = QInputDialog.getText(
|
text, ok = QInputDialog.getText(
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ you do not do this, you will get 'element not editable' errors.
|
||||||
If keepass takes a while to open the DB, you might want to consider reducing
|
If keepass takes a while to open the DB, you might want to consider reducing
|
||||||
the number of transform rounds in your database settings.
|
the number of transform rounds in your database settings.
|
||||||
|
|
||||||
Dependencies: pykeepass (in python3), PyQt5. Without pykeepass, you will get an
|
Dependencies: pykeepass (in python3), PyQt6. Without pykeepass, you will get an
|
||||||
exit code of 100.
|
exit code of 100.
|
||||||
|
|
||||||
********************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!******************
|
********************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!******************
|
||||||
|
|
@ -64,8 +64,8 @@ import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt5.QtCore import QUrl
|
from PyQt6.QtCore import QUrl
|
||||||
from PyQt5.QtWidgets import QApplication, QInputDialog, QLineEdit
|
from PyQt6.QtWidgets import QApplication, QInputDialog, QLineEdit
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pykeepass
|
import pykeepass
|
||||||
|
|
@ -152,7 +152,7 @@ def get_password():
|
||||||
text, ok = QInputDialog.getText(
|
text, ok = QInputDialog.getText(
|
||||||
None, "KeePass DB Password",
|
None, "KeePass DB Password",
|
||||||
"Please enter your KeePass Master Password",
|
"Please enter your KeePass Master Password",
|
||||||
QLineEdit.Password)
|
QLineEdit.EchoMode.Password)
|
||||||
if not ok:
|
if not ok:
|
||||||
stderr('Password Prompt Rejected.')
|
stderr('Password Prompt Rejected.')
|
||||||
sys.exit(ExitCodes.USER_QUIT)
|
sys.exit(ExitCodes.USER_QUIT)
|
||||||
|
|
|
||||||
|
|
@ -367,6 +367,14 @@ def _open_special_pages(args):
|
||||||
os.environ.get("QTWEBENGINE_DISABLE_SANDBOX") == "1"
|
os.environ.get("QTWEBENGINE_DISABLE_SANDBOX") == "1"
|
||||||
),
|
),
|
||||||
'qute://warning/sandboxing'),
|
'qute://warning/sandboxing'),
|
||||||
|
|
||||||
|
('qt5-warning-shown',
|
||||||
|
(
|
||||||
|
machinery.IS_QT5 and
|
||||||
|
machinery.INFO.reason == machinery.SelectionReason.auto and
|
||||||
|
objects.backend != usertypes.Backend.QtWebKit,
|
||||||
|
),
|
||||||
|
'qute://warning/qt5'),
|
||||||
]
|
]
|
||||||
|
|
||||||
if 'quickstart-done' not in general_sect:
|
if 'quickstart-done' not in general_sect:
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ Module attributes:
|
||||||
_HANDLERS: The handlers registered via decorators.
|
_HANDLERS: The handlers registered via decorators.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
import html
|
import html
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
@ -583,6 +584,12 @@ def qute_warning(url: QUrl) -> _HandlerRet:
|
||||||
elif path == '/sandboxing':
|
elif path == '/sandboxing':
|
||||||
src = jinja.render('warning-sandboxing.html',
|
src = jinja.render('warning-sandboxing.html',
|
||||||
title='Qt 6 macOS sandboxing warning')
|
title='Qt 6 macOS sandboxing warning')
|
||||||
|
elif path == '/qt5':
|
||||||
|
is_venv = hasattr(sys, 'real_prefix') or sys.base_prefix != sys.prefix
|
||||||
|
src = jinja.render('warning-qt5.html',
|
||||||
|
title='Switch to Qt 6',
|
||||||
|
is_venv=is_venv,
|
||||||
|
prefix=sys.prefix)
|
||||||
else:
|
else:
|
||||||
raise NotFoundError("Invalid warning page {}".format(path))
|
raise NotFoundError("Invalid warning page {}".format(path))
|
||||||
return 'text/html', src
|
return 'text/html', src
|
||||||
|
|
|
||||||
|
|
@ -400,7 +400,8 @@ class WebEngineCaret(browsertab.AbstractCaret):
|
||||||
# https://bugreports.qt.io/browse/QTBUG-53134
|
# https://bugreports.qt.io/browse/QTBUG-53134
|
||||||
# Even on Qt 5.10 selectedText() seems to work poorly, see
|
# Even on Qt 5.10 selectedText() seems to work poorly, see
|
||||||
# https://github.com/qutebrowser/qutebrowser/issues/3523
|
# https://github.com/qutebrowser/qutebrowser/issues/3523
|
||||||
# FIXME:qt6 Reevaluate?
|
# With Qt 6.2-6.5, there still seem to be issues (especially with
|
||||||
|
# multi-line text)
|
||||||
self._tab.run_js_async(javascript.assemble('caret', 'getSelection'),
|
self._tab.run_js_async(javascript.assemble('caret', 'getSelection'),
|
||||||
callback)
|
callback)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,16 +15,15 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# 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."""
|
"""QtWebKit specific part of the web element API."""
|
||||||
|
|
||||||
from typing import cast, TYPE_CHECKING, Iterator, List, Optional, Set
|
from typing import cast, TYPE_CHECKING, Iterator, List, Optional, Set
|
||||||
|
|
||||||
from qutebrowser.qt.core import QRect, Qt
|
from qutebrowser.qt.core import QRect, Qt
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkit import QWebElement, QWebSettings
|
from qutebrowser.qt.webkit import QWebElement, QWebSettings
|
||||||
from qutebrowser.qt.webkitwidgets import QWebFrame
|
from qutebrowser.qt.webkitwidgets import QWebFrame
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
|
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.utils import log, utils, javascript, usertypes
|
from qutebrowser.utils import log, utils, javascript, usertypes
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,13 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# 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."""
|
"""QtWebKit specific part of history."""
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkit import QWebHistoryInterface
|
from qutebrowser.qt.webkit import QWebHistoryInterface
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
|
|
||||||
from qutebrowser.utils import debug
|
from qutebrowser.utils import debug
|
||||||
from qutebrowser.misc import debugcachestats
|
from qutebrowser.misc import debugcachestats
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,13 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# FIXME:qt6 (lint)
|
|
||||||
# pylint: disable=no-name-in-module
|
|
||||||
|
|
||||||
"""Customized QWebInspector for QtWebKit."""
|
"""Customized QWebInspector for QtWebKit."""
|
||||||
|
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkit import QWebSettings
|
from qutebrowser.qt.webkit import QWebSettings
|
||||||
from qutebrowser.qt.webkitwidgets import QWebInspector, QWebPage
|
from qutebrowser.qt.webkitwidgets import QWebInspector, QWebPage
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
from qutebrowser.qt.widgets import QWidget
|
from qutebrowser.qt.widgets import QWidget
|
||||||
|
|
||||||
from qutebrowser.browser import inspector
|
from qutebrowser.browser import inspector
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# 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.
|
"""Bridge from QWebSettings to our own settings.
|
||||||
|
|
||||||
Module attributes:
|
Module attributes:
|
||||||
|
|
@ -30,8 +27,10 @@ import os.path
|
||||||
|
|
||||||
from qutebrowser.qt.core import QUrl
|
from qutebrowser.qt.core import QUrl
|
||||||
from qutebrowser.qt.gui import QFont
|
from qutebrowser.qt.gui import QFont
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkit import QWebSettings
|
from qutebrowser.qt.webkit import QWebSettings
|
||||||
from qutebrowser.qt.webkitwidgets import QWebPage
|
from qutebrowser.qt.webkitwidgets import QWebPage
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
|
|
||||||
from qutebrowser.config import config, websettings
|
from qutebrowser.config import config, websettings
|
||||||
from qutebrowser.config.websettings import AttributeInfo as Attr
|
from qutebrowser.config.websettings import AttributeInfo as Attr
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# 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."""
|
"""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.core import pyqtSlot, Qt, QUrl, QPoint, QTimer, QSizeF, QSize
|
||||||
from qutebrowser.qt.gui import QIcon
|
from qutebrowser.qt.gui import QIcon
|
||||||
from qutebrowser.qt.widgets import QWidget
|
from qutebrowser.qt.widgets import QWidget
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkitwidgets import QWebPage, QWebFrame
|
from qutebrowser.qt.webkitwidgets import QWebPage, QWebFrame
|
||||||
from qutebrowser.qt.webkit import QWebSettings, QWebHistory, QWebElement
|
from qutebrowser.qt.webkit import QWebSettings, QWebHistory, QWebElement
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
from qutebrowser.qt.printsupport import QPrinter
|
from qutebrowser.qt.printsupport import QPrinter
|
||||||
|
|
||||||
from qutebrowser.browser import browsertab, shared
|
from qutebrowser.browser import browsertab, shared
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# FIXME:qt6 (lint)
|
|
||||||
# pylint: disable=no-name-in-module
|
|
||||||
|
|
||||||
"""The main browser widgets."""
|
"""The main browser widgets."""
|
||||||
|
|
||||||
import html
|
import html
|
||||||
|
|
@ -28,7 +25,9 @@ from qutebrowser.qt.gui import QDesktopServices
|
||||||
from qutebrowser.qt.network import QNetworkReply, QNetworkRequest
|
from qutebrowser.qt.network import QNetworkReply, QNetworkRequest
|
||||||
from qutebrowser.qt.widgets import QFileDialog
|
from qutebrowser.qt.widgets import QFileDialog
|
||||||
from qutebrowser.qt.printsupport import QPrintDialog
|
from qutebrowser.qt.printsupport import QPrintDialog
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkitwidgets import QWebPage, QWebFrame
|
from qutebrowser.qt.webkitwidgets import QWebPage, QWebFrame
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
|
|
||||||
from qutebrowser.config import websettings, config
|
from qutebrowser.config import websettings, config
|
||||||
from qutebrowser.browser import pdfjs, shared, downloads, greasemonkey
|
from qutebrowser.browser import pdfjs, shared, downloads, greasemonkey
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,13 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# FIXME:qt6 (lint)
|
|
||||||
# pylint: disable=no-name-in-module
|
|
||||||
|
|
||||||
"""The main browser widgets."""
|
"""The main browser widgets."""
|
||||||
|
|
||||||
from qutebrowser.qt.core import pyqtSignal, Qt
|
from qutebrowser.qt.core import pyqtSignal, Qt
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkit import QWebSettings
|
from qutebrowser.qt.webkit import QWebSettings
|
||||||
from qutebrowser.qt.webkitwidgets import QWebView, QWebPage
|
from qutebrowser.qt.webkitwidgets import QWebView, QWebPage
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
|
|
||||||
from qutebrowser.config import config, stylesheet
|
from qutebrowser.config import config, stylesheet
|
||||||
from qutebrowser.keyinput import modeman
|
from qutebrowser.keyinput import modeman
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
{% extends "styled.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
<span class="note">Note this warning will only appear once. Use <span class="mono">:open
|
||||||
|
qute://warning/qt5</span> to show it again at a later time.</span>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
qutebrowser <b>now supports Qt 6</b>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
However, in your environment, <b>Qt 6 is not installed</b>. Thus, qutebrowser is still using Qt 5 instead.
|
||||||
|
|
||||||
|
Qt 5.15 based on a very old Chromium version (83 or 87, from mid/late 2020).
|
||||||
|
</p>
|
||||||
|
{% if is_venv %}
|
||||||
|
<p>
|
||||||
|
You are using a virtualenv. If you want to use Qt 6, you need to create a new
|
||||||
|
virtualenv with PyQt6 installed.
|
||||||
|
|
||||||
|
If using <span class="mono">mkvenv.py</span>, <b>rerun the script</b> to create a
|
||||||
|
new virtualenv with Qt 6.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<p>
|
||||||
|
<span class="note">Python installation prefix: <span class="mono">{{ prefix }}</span></span>
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -37,9 +37,7 @@ from qutebrowser.qt import machinery
|
||||||
from qutebrowser.qt.core import Qt, QEvent
|
from qutebrowser.qt.core import Qt, QEvent
|
||||||
from qutebrowser.qt.gui import QKeySequence, QKeyEvent
|
from qutebrowser.qt.gui import QKeySequence, QKeyEvent
|
||||||
if machinery.IS_QT6:
|
if machinery.IS_QT6:
|
||||||
# FIXME:qt6 (lint) how come pylint isn't picking this up with both backends
|
from qutebrowser.qt.core import QKeyCombination
|
||||||
# installed?
|
|
||||||
from qutebrowser.qt.core import QKeyCombination # pylint: disable=no-name-in-module
|
|
||||||
else:
|
else:
|
||||||
QKeyCombination = None # QKeyCombination was added in Qt 6
|
QKeyCombination = None # QKeyCombination was added in Qt 6
|
||||||
|
|
||||||
|
|
@ -349,7 +347,7 @@ def _unset_modifier_bits(
|
||||||
https://github.com/python/cpython/issues/105497
|
https://github.com/python/cpython/issues/105497
|
||||||
"""
|
"""
|
||||||
if machinery.IS_QT5:
|
if machinery.IS_QT5:
|
||||||
return cast(_ModifierType, modifiers & ~mask)
|
return Qt.KeyboardModifiers(modifiers & ~mask) # can lose type if it's 0
|
||||||
else:
|
else:
|
||||||
return Qt.KeyboardModifier(modifiers.value & ~mask.value)
|
return Qt.KeyboardModifier(modifiers.value & ~mask.value)
|
||||||
|
|
||||||
|
|
@ -369,11 +367,14 @@ class KeyInfo:
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
"""Run some validation on the key/modifier values."""
|
"""Run some validation on the key/modifier values."""
|
||||||
# This is mainly useful while porting from Qt 5 to 6.
|
# This changed with Qt 6, and e.g. to_qt() relies on this.
|
||||||
# FIXME:qt6 do we want to remove or keep this (and fix the remaining
|
if machinery.IS_QT5:
|
||||||
# issues) when done?
|
modifier_classes = (Qt.KeyboardModifier, Qt.KeyboardModifiers)
|
||||||
# assert isinstance(self.key, Qt.Key), self.key
|
elif machinery.IS_QT6:
|
||||||
# assert isinstance(self.modifiers, Qt.KeyboardModifier), self.modifiers
|
modifier_classes = Qt.KeyboardModifier
|
||||||
|
assert isinstance(self.key, Qt.Key), self.key
|
||||||
|
assert isinstance(self.modifiers, modifier_classes), self.modifiers
|
||||||
|
|
||||||
_assert_plain_key(self.key)
|
_assert_plain_key(self.key)
|
||||||
_assert_plain_modifier(self.modifiers)
|
_assert_plain_modifier(self.modifiers)
|
||||||
|
|
||||||
|
|
@ -488,16 +489,7 @@ class KeyInfo:
|
||||||
if machinery.IS_QT5:
|
if machinery.IS_QT5:
|
||||||
return int(self.key) | int(self.modifiers)
|
return int(self.key) | int(self.modifiers)
|
||||||
else:
|
else:
|
||||||
try:
|
return QKeyCombination(self.modifiers, self.key)
|
||||||
# FIXME:qt6 We might want to consider only supporting KeyInfo to be
|
|
||||||
# instanciated with a real Qt.Key, not with ints. See __post_init__.
|
|
||||||
key = Qt.Key(self.key)
|
|
||||||
except ValueError as e:
|
|
||||||
# WORKAROUND for
|
|
||||||
# https://www.riverbankcomputing.com/pipermail/pyqt/2022-April/044607.html
|
|
||||||
raise InvalidKeyError(e)
|
|
||||||
|
|
||||||
return QKeyCombination(self.modifiers, key)
|
|
||||||
|
|
||||||
def with_stripped_modifiers(self, modifiers: Qt.KeyboardModifier) -> "KeyInfo":
|
def with_stripped_modifiers(self, modifiers: Qt.KeyboardModifier) -> "KeyInfo":
|
||||||
mods = _unset_modifier_bits(self.modifiers, modifiers)
|
mods = _unset_modifier_bits(self.modifiers, modifiers)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ https://github.com/python-qt-tools/PyQt5-stubs/blob/5.15.6.0/PyQt5-stubs/QtCore.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
# pylint: disable=invalid-name,missing-class-docstring,too-many-arguments,redefined-builtin,unused-argument,import-error
|
# pylint: disable=invalid-name,missing-class-docstring,too-many-arguments,redefined-builtin,unused-argument,no-name-in-module
|
||||||
|
|
||||||
import typing
|
import typing
|
||||||
from PyQt6.QtCore import QObject, pyqtSignal
|
from PyQt6.QtCore import QObject, pyqtSignal
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,16 @@
|
||||||
"""Qt wrapper selection.
|
"""Qt wrapper selection.
|
||||||
|
|
||||||
Contains selection logic and globals for Qt wrapper selection.
|
Contains selection logic and globals for Qt wrapper selection.
|
||||||
|
|
||||||
|
All other files in this package are intended to be simple wrappers around Qt imports.
|
||||||
|
Depending on what is set in this module, they import from PyQt5 or PyQt6.
|
||||||
|
|
||||||
|
The import wrappers are intended to be as thin as possible. They will not unify
|
||||||
|
API-level differences between Qt 5 and Qt 6. This is best handled by the calling code,
|
||||||
|
which has a better picture of what changed between APIs and how to best handle it.
|
||||||
|
|
||||||
|
What they *will* do is handle simple 1:1 renames of classes, or moves between
|
||||||
|
modules (where they aim to always expose the Qt 6 API). See e.g. webenginecore.py.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# NOTE: No qutebrowser or PyQt import should be done here (at import time),
|
# NOTE: No qutebrowser or PyQt import should be done here (at import time),
|
||||||
|
|
@ -20,11 +30,11 @@ from typing import Optional, Dict
|
||||||
|
|
||||||
from qutebrowser.utils import log
|
from qutebrowser.utils import log
|
||||||
|
|
||||||
# Packagers: Patch the line below to change the default wrapper for Qt 6 packages, e.g.:
|
# Packagers: Patch the line below to enforce a Qt wrapper, e.g.:
|
||||||
# sed -i 's/_DEFAULT_WRAPPER = "PyQt5"/_DEFAULT_WRAPPER = "PyQt6"/' qutebrowser/qt/machinery.py
|
# sed -i 's/_WRAPPER_OVERRIDE = .*/_WRAPPER_OVERRIDE = "PyQt6"/' qutebrowser/qt/machinery.py
|
||||||
#
|
#
|
||||||
# Users: Set the QUTE_QT_WRAPPER environment variable to change the default wrapper.
|
# Users: Set the QUTE_QT_WRAPPER environment variable to change the default wrapper.
|
||||||
_DEFAULT_WRAPPER = "PyQt5"
|
_WRAPPER_OVERRIDE = None
|
||||||
|
|
||||||
WRAPPERS = [
|
WRAPPERS = [
|
||||||
"PyQt6",
|
"PyQt6",
|
||||||
|
|
@ -80,6 +90,9 @@ class SelectionReason(enum.Enum):
|
||||||
#: The wrapper was faked/patched out (e.g. in tests).
|
#: The wrapper was faked/patched out (e.g. in tests).
|
||||||
fake = "fake"
|
fake = "fake"
|
||||||
|
|
||||||
|
#: The wrapper was overridden by patching _WRAPPER_OVERRIDE.
|
||||||
|
override = "override"
|
||||||
|
|
||||||
#: The reason was not set.
|
#: The reason was not set.
|
||||||
unknown = "unknown"
|
unknown = "unknown"
|
||||||
|
|
||||||
|
|
@ -152,7 +165,7 @@ def _select_wrapper(args: Optional[argparse.Namespace]) -> SelectionInfo:
|
||||||
|
|
||||||
- If --qt-wrapper is given, use that.
|
- If --qt-wrapper is given, use that.
|
||||||
- Otherwise, if the QUTE_QT_WRAPPER environment variable is set, use that.
|
- Otherwise, if the QUTE_QT_WRAPPER environment variable is set, use that.
|
||||||
- Otherwise, use PyQt5 (FIXME:qt6 autoselect).
|
- Otherwise, try the wrappers in WRAPPER in order (PyQt6 -> PyQt5)
|
||||||
"""
|
"""
|
||||||
# If any Qt wrapper has been imported before this, something strange might
|
# If any Qt wrapper has been imported before this, something strange might
|
||||||
# be happening.
|
# be happening.
|
||||||
|
|
@ -170,15 +183,17 @@ def _select_wrapper(args: Optional[argparse.Namespace]) -> SelectionInfo:
|
||||||
if env_wrapper == "auto":
|
if env_wrapper == "auto":
|
||||||
return _autoselect_wrapper()
|
return _autoselect_wrapper()
|
||||||
elif env_wrapper not in WRAPPERS:
|
elif env_wrapper not in WRAPPERS:
|
||||||
raise Error(f"Unknown wrapper {env_wrapper} set via {env_var}, "
|
raise Error(
|
||||||
f"allowed: {', '.join(WRAPPERS)}")
|
f"Unknown wrapper {env_wrapper} set via {env_var}, "
|
||||||
|
f"allowed: {', '.join(WRAPPERS)}"
|
||||||
|
)
|
||||||
return SelectionInfo(wrapper=env_wrapper, reason=SelectionReason.env)
|
return SelectionInfo(wrapper=env_wrapper, reason=SelectionReason.env)
|
||||||
|
|
||||||
# FIXME:qt6 Go back to the auto-detection once ready
|
if _WRAPPER_OVERRIDE is not None:
|
||||||
# FIXME:qt6 Make sure to still consider _DEFAULT_WRAPPER for packagers
|
assert _WRAPPER_OVERRIDE in WRAPPERS # type: ignore[unreachable]
|
||||||
# (rename to _WRAPPER_OVERRIDE since our sed command is broken anyways then?)
|
return SelectionInfo(wrapper=_WRAPPER_OVERRIDE, reason=SelectionReason.override)
|
||||||
# return _autoselect_wrapper()
|
|
||||||
return SelectionInfo(wrapper=_DEFAULT_WRAPPER, reason=SelectionReason.default)
|
return _autoselect_wrapper()
|
||||||
|
|
||||||
|
|
||||||
# Values are set in init(). If you see a NameError here, it means something tried to
|
# Values are set in init(). If you see a NameError here, it means something tried to
|
||||||
|
|
@ -219,8 +234,7 @@ def _set_globals(info: SelectionInfo) -> None:
|
||||||
Those are split into multiple global variables because that way we can teach mypy
|
Those are split into multiple global variables because that way we can teach mypy
|
||||||
about them via --always-true and --always-false, see tox.ini.
|
about them via --always-true and --always-false, see tox.ini.
|
||||||
"""
|
"""
|
||||||
global INFO, USE_PYQT5, USE_PYQT6, USE_PYSIDE6, IS_QT5, IS_QT6, \
|
global INFO, USE_PYQT5, USE_PYQT6, USE_PYSIDE6, IS_QT5, IS_QT6, IS_PYQT, IS_PYSIDE, _initialized
|
||||||
IS_PYQT, IS_PYSIDE, _initialized
|
|
||||||
|
|
||||||
assert info.wrapper is not None, info
|
assert info.wrapper is not None, info
|
||||||
assert not _initialized
|
assert not _initialized
|
||||||
|
|
|
||||||
|
|
@ -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.
|
"""Wrapped Qt imports for Qt OpenGL.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ except ImportError:
|
||||||
sys.exit(100)
|
sys.exit(100)
|
||||||
check_python_version()
|
check_python_version()
|
||||||
|
|
||||||
import argparse # FIXME:qt6 (lint): disable=wrong-import-order
|
import argparse
|
||||||
from qutebrowser.misc import earlyinit
|
from qutebrowser.misc import earlyinit
|
||||||
from qutebrowser.qt import machinery
|
from qutebrowser.qt import machinery
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ def _smoke_test_run(
|
||||||
return subprocess.run(argv, check=True, capture_output=True)
|
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."""
|
"""Try starting the given qutebrowser executable."""
|
||||||
stdout_whitelist = []
|
stdout_whitelist = []
|
||||||
stderr_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'ContextResult::kTransientFailure: Failed to send '
|
||||||
r'.*CreateCommandBuffer\.'),
|
r'.*CreateCommandBuffer\.'),
|
||||||
])
|
])
|
||||||
if qt6:
|
if not qt5:
|
||||||
stderr_whitelist.extend([
|
stderr_whitelist.extend([
|
||||||
# FIXME:qt6 Qt 6.3 on macOS
|
# FIXME:qt6 Qt 6.3 on macOS
|
||||||
r'[0-9:]* WARNING: Incompatible version of OpenSSL',
|
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()
|
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."""
|
"""Patch .app to save some space and make it signable."""
|
||||||
dist_path = pathlib.Path('dist')
|
dist_path = pathlib.Path('dist')
|
||||||
ver = '6' if qt6 else '5'
|
ver = '5' if qt5 else '6'
|
||||||
app_path = dist_path / 'qutebrowser.app'
|
app_path = dist_path / 'qutebrowser.app'
|
||||||
|
|
||||||
contents_path = app_path / 'Contents'
|
contents_path = app_path / 'Contents'
|
||||||
|
|
@ -280,7 +280,7 @@ def patch_mac_app(qt6: bool) -> None:
|
||||||
file_path.unlink()
|
file_path.unlink()
|
||||||
file_path.symlink_to(target)
|
file_path.symlink_to(target)
|
||||||
|
|
||||||
if qt6:
|
if not qt5:
|
||||||
# Symlinking QtWebEngineCore.framework does not seem to work with Qt 6.
|
# Symlinking QtWebEngineCore.framework does not seem to work with Qt 6.
|
||||||
# Also, the symlinking/moving before signing doesn't seem to be required.
|
# Also, the symlinking/moving before signing doesn't seem to be required.
|
||||||
return
|
return
|
||||||
|
|
@ -333,7 +333,7 @@ def _mac_bin_path(base: pathlib.Path) -> pathlib.Path:
|
||||||
def build_mac(
|
def build_mac(
|
||||||
*,
|
*,
|
||||||
gh_token: Optional[str],
|
gh_token: Optional[str],
|
||||||
qt6: bool,
|
qt5: bool,
|
||||||
skip_packaging: bool,
|
skip_packaging: bool,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
) -> List[Artifact]:
|
) -> List[Artifact]:
|
||||||
|
|
@ -348,20 +348,20 @@ def build_mac(
|
||||||
shutil.rmtree(d, ignore_errors=True)
|
shutil.rmtree(d, ignore_errors=True)
|
||||||
|
|
||||||
utils.print_title("Updating 3rdparty content")
|
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)
|
gh_token=gh_token)
|
||||||
|
|
||||||
utils.print_title("Building .app via pyinstaller")
|
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")
|
utils.print_title("Patching .app")
|
||||||
patch_mac_app(qt6=qt6)
|
patch_mac_app(qt5=qt5)
|
||||||
utils.print_title("Re-signing .app")
|
utils.print_title("Re-signing .app")
|
||||||
sign_mac_app()
|
sign_mac_app()
|
||||||
|
|
||||||
dist_path = pathlib.Path("dist")
|
dist_path = pathlib.Path("dist")
|
||||||
|
|
||||||
utils.print_title("Running pre-dmg smoke test")
|
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:
|
if skip_packaging:
|
||||||
return []
|
return []
|
||||||
|
|
@ -371,7 +371,7 @@ def build_mac(
|
||||||
subprocess.run(['make', '-f', dmg_makefile_path], check=True)
|
subprocess.run(['make', '-f', dmg_makefile_path], check=True)
|
||||||
|
|
||||||
suffix = "-debug" if debug else ""
|
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'
|
dmg_path = dist_path / f'qutebrowser-{qutebrowser.__version__}{suffix}.dmg'
|
||||||
pathlib.Path('qutebrowser.dmg').rename(dmg_path)
|
pathlib.Path('qutebrowser.dmg').rename(dmg_path)
|
||||||
|
|
||||||
|
|
@ -383,7 +383,7 @@ def build_mac(
|
||||||
subprocess.run(['hdiutil', 'attach', dmg_path,
|
subprocess.run(['hdiutil', 'attach', dmg_path,
|
||||||
'-mountpoint', tmp_path], check=True)
|
'-mountpoint', tmp_path], check=True)
|
||||||
try:
|
try:
|
||||||
smoke_test(_mac_bin_path(tmp_path), debug=debug, qt6=qt6)
|
smoke_test(_mac_bin_path(tmp_path), debug=debug, qt5=qt5)
|
||||||
finally:
|
finally:
|
||||||
print("Waiting 10s for dmg to be detachable...")
|
print("Waiting 10s for dmg to be detachable...")
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
|
|
@ -422,7 +422,7 @@ def _get_windows_python_path(x64: bool) -> pathlib.Path:
|
||||||
|
|
||||||
def _build_windows_single(
|
def _build_windows_single(
|
||||||
*, x64: bool,
|
*, x64: bool,
|
||||||
qt6: bool,
|
qt5: bool,
|
||||||
skip_packaging: bool,
|
skip_packaging: bool,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
) -> List[Artifact]:
|
) -> List[Artifact]:
|
||||||
|
|
@ -437,9 +437,9 @@ def _build_windows_single(
|
||||||
|
|
||||||
python = _get_windows_python_path(x64=x64)
|
python = _get_windows_python_path(x64=x64)
|
||||||
suffix = "64bit" if x64 else "32bit"
|
suffix = "64bit" if x64 else "32bit"
|
||||||
if qt6:
|
if qt5:
|
||||||
# FIXME:qt6 does this regress 391623d5ec983ecfc4512c7305c4b7a293ac3872?
|
# FIXME:qt6 does this regress 391623d5ec983ecfc4512c7305c4b7a293ac3872?
|
||||||
suffix += "-qt6"
|
suffix += "-qt5"
|
||||||
call_tox(f'pyinstaller-{suffix}', '-r', python=python, debug=debug)
|
call_tox(f'pyinstaller-{suffix}', '-r', python=python, debug=debug)
|
||||||
|
|
||||||
out_pyinstaller = dist_path / "qutebrowser"
|
out_pyinstaller = dist_path / "qutebrowser"
|
||||||
|
|
@ -450,7 +450,7 @@ def _build_windows_single(
|
||||||
verify_windows_exe(exe_path)
|
verify_windows_exe(exe_path)
|
||||||
|
|
||||||
utils.print_title(f"Running {human_arch} smoke test")
|
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:
|
if skip_packaging:
|
||||||
return []
|
return []
|
||||||
|
|
@ -463,7 +463,7 @@ def _build_windows_single(
|
||||||
desc_arch=human_arch,
|
desc_arch=human_arch,
|
||||||
desc_suffix='' if x64 else ' (only for 32-bit Windows!)',
|
desc_suffix='' if x64 else ' (only for 32-bit Windows!)',
|
||||||
debug=debug,
|
debug=debug,
|
||||||
qt6=qt6,
|
qt5=qt5,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -472,12 +472,12 @@ def build_windows(
|
||||||
skip_packaging: bool,
|
skip_packaging: bool,
|
||||||
only_32bit: bool,
|
only_32bit: bool,
|
||||||
only_64bit: bool,
|
only_64bit: bool,
|
||||||
qt6: bool,
|
qt5: bool,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
) -> List[Artifact]:
|
) -> List[Artifact]:
|
||||||
"""Build windows executables/setups."""
|
"""Build windows executables/setups."""
|
||||||
utils.print_title("Updating 3rdparty content")
|
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)
|
fancy_dmg=False, gh_token=gh_token)
|
||||||
|
|
||||||
utils.print_title("Building Windows binaries")
|
utils.print_title("Building Windows binaries")
|
||||||
|
|
@ -493,14 +493,14 @@ def build_windows(
|
||||||
x64=True,
|
x64=True,
|
||||||
skip_packaging=skip_packaging,
|
skip_packaging=skip_packaging,
|
||||||
debug=debug,
|
debug=debug,
|
||||||
qt6=qt6,
|
qt5=qt5,
|
||||||
)
|
)
|
||||||
if not only_64bit and not qt6:
|
if not only_64bit and not qt5:
|
||||||
artifacts += _build_windows_single(
|
artifacts += _build_windows_single(
|
||||||
x64=False,
|
x64=False,
|
||||||
skip_packaging=skip_packaging,
|
skip_packaging=skip_packaging,
|
||||||
debug=debug,
|
debug=debug,
|
||||||
qt6=qt6,
|
qt5=qt5,
|
||||||
)
|
)
|
||||||
|
|
||||||
return artifacts
|
return artifacts
|
||||||
|
|
@ -514,7 +514,7 @@ def _package_windows_single(
|
||||||
desc_suffix: str,
|
desc_suffix: str,
|
||||||
filename_arch: str,
|
filename_arch: str,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
qt6: bool,
|
qt5: bool,
|
||||||
) -> List[Artifact]:
|
) -> List[Artifact]:
|
||||||
"""Build the given installer/zip for windows."""
|
"""Build the given installer/zip for windows."""
|
||||||
artifacts = []
|
artifacts = []
|
||||||
|
|
@ -532,8 +532,8 @@ def _package_windows_single(
|
||||||
]
|
]
|
||||||
if debug:
|
if debug:
|
||||||
name_parts.append('debug')
|
name_parts.append('debug')
|
||||||
if qt6:
|
if qt5:
|
||||||
name_parts.append('qt6')
|
name_parts.append('qt5')
|
||||||
name = '-'.join(name_parts) + '.exe'
|
name = '-'.join(name_parts) + '.exe'
|
||||||
|
|
||||||
artifacts.append(Artifact(
|
artifacts.append(Artifact(
|
||||||
|
|
@ -552,8 +552,8 @@ def _package_windows_single(
|
||||||
]
|
]
|
||||||
if debug:
|
if debug:
|
||||||
zip_name_parts.append('debug')
|
zip_name_parts.append('debug')
|
||||||
if qt6:
|
if qt5:
|
||||||
zip_name_parts.append('qt6')
|
zip_name_parts.append('qt5')
|
||||||
zip_name = '-'.join(zip_name_parts) + '.zip'
|
zip_name = '-'.join(zip_name_parts) + '.zip'
|
||||||
|
|
||||||
zip_path = dist_path / zip_name
|
zip_path = dist_path / zip_name
|
||||||
|
|
@ -738,8 +738,8 @@ def main() -> None:
|
||||||
help="Skip Windows 32 bit build.", dest='only_64bit')
|
help="Skip Windows 32 bit build.", dest='only_64bit')
|
||||||
parser.add_argument('--debug', action='store_true', required=False,
|
parser.add_argument('--debug', action='store_true', required=False,
|
||||||
help="Build a debug build.")
|
help="Build a debug build.")
|
||||||
parser.add_argument('--qt6', action='store_true', required=False,
|
parser.add_argument('--qt5', action='store_true', required=False,
|
||||||
help="Build against PyQt6")
|
help="Build against PyQt5")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
utils.change_cwd()
|
utils.change_cwd()
|
||||||
|
|
||||||
|
|
@ -768,14 +768,14 @@ def main() -> None:
|
||||||
skip_packaging=args.skip_packaging,
|
skip_packaging=args.skip_packaging,
|
||||||
only_32bit=args.only_32bit,
|
only_32bit=args.only_32bit,
|
||||||
only_64bit=args.only_64bit,
|
only_64bit=args.only_64bit,
|
||||||
qt6=args.qt6,
|
qt5=args.qt5,
|
||||||
debug=args.debug,
|
debug=args.debug,
|
||||||
)
|
)
|
||||||
elif IS_MACOS:
|
elif IS_MACOS:
|
||||||
artifacts = build_mac(
|
artifacts = build_mac(
|
||||||
gh_token=gh_token,
|
gh_token=gh_token,
|
||||||
skip_packaging=args.skip_packaging,
|
skip_packaging=args.skip_packaging,
|
||||||
qt6=args.qt6,
|
qt5=args.qt5,
|
||||||
debug=args.debug,
|
debug=args.debug,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import subprocess
|
||||||
import tokenize
|
import tokenize
|
||||||
import traceback
|
import traceback
|
||||||
import pathlib
|
import pathlib
|
||||||
from typing import List, Iterator, Optional
|
from typing import List, Iterator, Optional, Tuple
|
||||||
|
|
||||||
REPO_ROOT = pathlib.Path(__file__).resolve().parents[2]
|
REPO_ROOT = pathlib.Path(__file__).resolve().parents[2]
|
||||||
sys.path.insert(0, str(REPO_ROOT))
|
sys.path.insert(0, str(REPO_ROOT))
|
||||||
|
|
@ -152,6 +152,24 @@ def _check_spelling_file(path, fobj, patterns):
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
|
|
||||||
|
def _check_spelling_all(
|
||||||
|
args: argparse.Namespace,
|
||||||
|
ignored: List[pathlib.Path],
|
||||||
|
patterns: List[Tuple[re.Pattern, str]],
|
||||||
|
) -> Optional[bool]:
|
||||||
|
try:
|
||||||
|
ok = True
|
||||||
|
for path in _get_files(verbose=args.verbose, ignored=ignored):
|
||||||
|
with tokenize.open(str(path)) as f:
|
||||||
|
if not _check_spelling_file(path, f, patterns):
|
||||||
|
ok = False
|
||||||
|
print()
|
||||||
|
return ok
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_spelling(args: argparse.Namespace) -> Optional[bool]:
|
def check_spelling(args: argparse.Namespace) -> Optional[bool]:
|
||||||
"""Check commonly misspelled words."""
|
"""Check commonly misspelled words."""
|
||||||
# Words which I often misspell
|
# Words which I often misspell
|
||||||
|
|
@ -273,25 +291,13 @@ def check_spelling(args: argparse.Namespace) -> Optional[bool]:
|
||||||
hint_data / 'ace' / 'ace.js',
|
hint_data / 'ace' / 'ace.js',
|
||||||
hint_data / 'bootstrap' / 'bootstrap.css',
|
hint_data / 'bootstrap' / 'bootstrap.css',
|
||||||
]
|
]
|
||||||
|
return _check_spelling_all(args=args, ignored=ignored, patterns=patterns)
|
||||||
try:
|
|
||||||
ok = True
|
|
||||||
for path in _get_files(verbose=args.verbose, ignored=ignored):
|
|
||||||
with tokenize.open(path) as f:
|
|
||||||
if not _check_spelling_file(path, f, patterns):
|
|
||||||
ok = False
|
|
||||||
print()
|
|
||||||
return ok
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def check_pyqt_imports(args: argparse.Namespace) -> Optional[bool]:
|
def check_pyqt_imports(args: argparse.Namespace) -> Optional[bool]:
|
||||||
"""Check for direct PyQt imports."""
|
"""Check for direct PyQt imports."""
|
||||||
ignored = [
|
ignored = [
|
||||||
pathlib.Path("qutebrowser", "qt"),
|
pathlib.Path("qutebrowser", "qt"),
|
||||||
# FIXME:qt6 fix those too?
|
|
||||||
pathlib.Path("misc", "userscripts"),
|
pathlib.Path("misc", "userscripts"),
|
||||||
pathlib.Path("scripts"),
|
pathlib.Path("scripts"),
|
||||||
]
|
]
|
||||||
|
|
@ -305,18 +311,7 @@ def check_pyqt_imports(args: argparse.Namespace) -> Optional[bool]:
|
||||||
"Use 'import qutebrowser.qt.MODULE' instead",
|
"Use 'import qutebrowser.qt.MODULE' instead",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
# FIXME:qt6 unify this with check_spelling somehow?
|
return _check_spelling_all(args=args, ignored=ignored, patterns=patterns)
|
||||||
try:
|
|
||||||
ok = True
|
|
||||||
for path in _get_files(verbose=args.verbose, ignored=ignored):
|
|
||||||
with tokenize.open(str(path)) as f:
|
|
||||||
if not _check_spelling_file(path, f, patterns):
|
|
||||||
ok = False
|
|
||||||
print()
|
|
||||||
return ok
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def check_vcs_conflict(args: argparse.Namespace) -> Optional[bool]:
|
def check_vcs_conflict(args: argparse.Namespace) -> Optional[bool]:
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ def whitelist_generator(): # noqa: C901
|
||||||
yield 'qutebrowser.misc.sql.SqliteErrorCode.CONSTRAINT'
|
yield 'qutebrowser.misc.sql.SqliteErrorCode.CONSTRAINT'
|
||||||
yield 'qutebrowser.misc.throttle.Throttle.set_delay'
|
yield 'qutebrowser.misc.throttle.Throttle.set_delay'
|
||||||
yield 'qutebrowser.misc.guiprocess.GUIProcess.stderr'
|
yield 'qutebrowser.misc.guiprocess.GUIProcess.stderr'
|
||||||
yield 'qutebrowser.qt.machinery._autoselect_wrapper' # FIXME:qt6
|
|
||||||
|
|
||||||
# Qt attributes
|
# Qt attributes
|
||||||
yield 'PyQt5.QtWebKit.QWebPage.ErrorPageExtensionReturn().baseUrl'
|
yield 'PyQt5.QtWebKit.QWebPage.ErrorPageExtensionReturn().baseUrl'
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt5.QtCore import (QT_VERSION_STR, PYQT_VERSION_STR, qVersion,
|
from PyQt6.QtCore import (QT_VERSION_STR, PYQT_VERSION_STR, qVersion,
|
||||||
QStandardPaths, QCoreApplication)
|
QStandardPaths, QCoreApplication)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@
|
||||||
Use python3 -m scripts.keytester to launch it.
|
Use python3 -m scripts.keytester to launch it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
from qutebrowser.qt.widgets import QApplication
|
||||||
|
|
||||||
from qutebrowser.misc import miscwidgets
|
from qutebrowser.misc import miscwidgets
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ def get_lib_path(executable, name, required=True):
|
||||||
raise ValueError("Unexpected output: {!r}".format(output))
|
raise ValueError("Unexpected output: {!r}".format(output))
|
||||||
|
|
||||||
|
|
||||||
def link_pyqt(executable, venv_path, *, version='5'):
|
def link_pyqt(executable, venv_path, *, version):
|
||||||
"""Symlink the systemwide PyQt/sip into the venv.
|
"""Symlink the systemwide PyQt/sip into the venv.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,7 @@ def pyqt_versions() -> List[str]:
|
||||||
|
|
||||||
def _is_qt6_version(version: str) -> bool:
|
def _is_qt6_version(version: str) -> bool:
|
||||||
"""Check if the given version is Qt 6."""
|
"""Check if the given version is Qt 6."""
|
||||||
# FIXME:qt6 Adjust once auto = Qt 6
|
return version in ["auto", "6"] or version.startswith("6.")
|
||||||
return version == "6" or version.startswith("6.")
|
|
||||||
|
|
||||||
|
|
||||||
def run_venv(
|
def run_venv(
|
||||||
|
|
@ -228,7 +227,7 @@ def requirements_file(name: str) -> pathlib.Path:
|
||||||
|
|
||||||
def pyqt_requirements_file(version: str) -> pathlib.Path:
|
def pyqt_requirements_file(version: str) -> pathlib.Path:
|
||||||
"""Get the filename of the requirements file for the given PyQt version."""
|
"""Get the filename of the requirements file for the given PyQt version."""
|
||||||
name = 'pyqt' if version == 'auto' else 'pyqt-{}'.format(version)
|
name = 'pyqt-6' if version == 'auto' else f'pyqt-{version}'
|
||||||
return requirements_file(name)
|
return requirements_file(name)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -439,7 +438,7 @@ def run_qt_smoke_test_single(
|
||||||
def run_qt_smoke_test(venv_dir: pathlib.Path, *, pyqt_version: str) -> None:
|
def run_qt_smoke_test(venv_dir: pathlib.Path, *, pyqt_version: str) -> None:
|
||||||
"""Make sure the Qt installation works."""
|
"""Make sure the Qt installation works."""
|
||||||
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-104415
|
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-104415
|
||||||
no_debug = pyqt_version in ("6.3", "6") and sys.platform == "darwin"
|
no_debug = pyqt_version == "6.3" and sys.platform == "darwin"
|
||||||
if no_debug:
|
if no_debug:
|
||||||
try:
|
try:
|
||||||
run_qt_smoke_test_single(venv_dir, debug=False, pyqt_version=pyqt_version)
|
run_qt_smoke_test_single(venv_dir, debug=False, pyqt_version=pyqt_version)
|
||||||
|
|
@ -505,6 +504,9 @@ def install_pyqt(venv_dir, args):
|
||||||
install_pyqt_binary(venv_dir, args.pyqt_version)
|
install_pyqt_binary(venv_dir, args.pyqt_version)
|
||||||
if args.pyqt_snapshot:
|
if args.pyqt_snapshot:
|
||||||
install_pyqt_shapshot(venv_dir, args.pyqt_snapshot.split(','))
|
install_pyqt_shapshot(venv_dir, args.pyqt_snapshot.split(','))
|
||||||
|
# Workaround until pyqt 6.5.2 is released on pypi
|
||||||
|
elif args.pyqt_version in ("6.5", "6", "auto"):
|
||||||
|
install_pyqt_shapshot(venv_dir, ["PyQt6-Qt6", "PyQt6-WebEngine-Qt6"])
|
||||||
elif args.pyqt_type == 'source':
|
elif args.pyqt_type == 'source':
|
||||||
install_pyqt_source(venv_dir, args.pyqt_version)
|
install_pyqt_source(venv_dir, args.pyqt_version)
|
||||||
elif args.pyqt_type == 'link':
|
elif args.pyqt_type == 'link':
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
"""Show information about the OpenGL setup."""
|
"""Show information about the OpenGL setup."""
|
||||||
|
|
||||||
from PyQt5.QtGui import (QOpenGLContext, QOpenGLVersionProfile,
|
from PyQt6.QtGui import QOpenGLContext, QOffscreenSurface, QGuiApplication
|
||||||
QOffscreenSurface, QGuiApplication)
|
from PyQt6.QtOpenGL import QOpenGLVersionProfile, QOpenGLVersionFunctionsFactory
|
||||||
|
|
||||||
app = QGuiApplication([])
|
app = QGuiApplication([])
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ print(f"GLES: {ctx.isOpenGLES()}")
|
||||||
vp = QOpenGLVersionProfile()
|
vp = QOpenGLVersionProfile()
|
||||||
vp.setVersion(2, 0)
|
vp.setVersion(2, 0)
|
||||||
|
|
||||||
vf = ctx.versionFunctions(vp)
|
vf = QOpenGLVersionFunctionsFactory.get(vp, ctx)
|
||||||
print(f"Vendor: {vf.glGetString(vf.GL_VENDOR)}")
|
print(f"Vendor: {vf.glGetString(vf.GL_VENDOR)}")
|
||||||
print(f"Renderer: {vf.glGetString(vf.GL_RENDERER)}")
|
print(f"Renderer: {vf.glGetString(vf.GL_RENDERER)}")
|
||||||
print(f"Version: {vf.glGetString(vf.GL_VERSION)}")
|
print(f"Version: {vf.glGetString(vf.GL_VERSION)}")
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# FIXME:qt6 (lint)
|
|
||||||
# pylint: disable=no-name-in-module
|
|
||||||
|
|
||||||
"""Tests for webelement.tabhistory."""
|
"""Tests for webelement.tabhistory."""
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
|
@ -26,7 +23,9 @@ from typing import Any
|
||||||
import pytest
|
import pytest
|
||||||
pytest.importorskip('qutebrowser.qt.webkit')
|
pytest.importorskip('qutebrowser.qt.webkit')
|
||||||
from qutebrowser.qt.core import QUrl, QPoint
|
from qutebrowser.qt.core import QUrl, QPoint
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
from qutebrowser.qt.webkit import QWebHistory
|
from qutebrowser.qt.webkit import QWebHistory
|
||||||
|
# pylint: enable=no-name-in-module
|
||||||
|
|
||||||
from qutebrowser.browser.webkit import tabhistory
|
from qutebrowser.browser.webkit import tabhistory
|
||||||
from qutebrowser.misc.sessions import TabHistoryItem as Item
|
from qutebrowser.misc.sessions import TabHistoryItem as Item
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
# 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."""
|
"""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."""
|
"""With QtWebKit, evaluateJavaScript works when JS is on."""
|
||||||
# If we get there (because of the webview fixture) we can be certain
|
# If we get there (because of the webview fixture) we can be certain
|
||||||
# QtWebKit is available
|
# 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)
|
webview.settings().setAttribute(QWebSettings.WebAttribute.JavascriptEnabled, js_enabled)
|
||||||
result = webview.page().mainFrame().evaluateJavaScript('1 + 1')
|
result = webview.page().mainFrame().evaluateJavaScript('1 + 1')
|
||||||
assert result == expected
|
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."""
|
"""With QtWebKit, evaluateJavaScript on an element works with JS off."""
|
||||||
# If we get there (because of the webview fixture) we can be certain
|
# If we get there (because of the webview fixture) we can be certain
|
||||||
# QtWebKit is available
|
# 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)
|
webview.settings().setAttribute(QWebSettings.WebAttribute.JavascriptEnabled, js_enabled)
|
||||||
elem = webview.page().mainFrame().documentElement()
|
elem = webview.page().mainFrame().documentElement()
|
||||||
result = elem.evaluateJavaScript('1 + 1')
|
result = elem.evaluateJavaScript('1 + 1')
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import dataclasses
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from qutebrowser.qt.core import Qt
|
from qutebrowser.qt.core import Qt
|
||||||
|
from qutebrowser.keyinput import keyutils
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(order=True)
|
@dataclasses.dataclass(order=True)
|
||||||
|
|
@ -606,7 +607,7 @@ KEYS = [
|
||||||
|
|
||||||
Key('unknown', 'Unknown', qtest=False),
|
Key('unknown', 'Unknown', qtest=False),
|
||||||
# 0x0 is used by Qt for unknown keys...
|
# 0x0 is used by Qt for unknown keys...
|
||||||
Key(attribute='', name='nil', member=0x0, qtest=False),
|
Key(attribute='', name='nil', member=keyutils._NIL_KEY, qtest=False),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ class TestHandle:
|
||||||
assert not prompt_keyparser._count
|
assert not prompt_keyparser._count
|
||||||
|
|
||||||
def test_invalid_key(self, prompt_keyparser):
|
def test_invalid_key(self, prompt_keyparser):
|
||||||
keys = [Qt.Key.Key_B, 0x0]
|
keys = [Qt.Key.Key_B, keyutils._NIL_KEY]
|
||||||
for key in keys:
|
for key in keys:
|
||||||
info = keyutils.KeyInfo(key, Qt.KeyboardModifier.NoModifier)
|
info = keyutils.KeyInfo(key, Qt.KeyboardModifier.NoModifier)
|
||||||
prompt_keyparser.handle(info.to_event())
|
prompt_keyparser.handle(info.to_event())
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,16 @@ from qutebrowser.keyinput import keyutils
|
||||||
from qutebrowser.utils import utils
|
from qutebrowser.utils import utils
|
||||||
|
|
||||||
|
|
||||||
|
pyqt_enum_workaround_skip = pytest.mark.skipif(
|
||||||
|
isinstance(keyutils._NIL_KEY, int),
|
||||||
|
reason="Can't create QKey for unknown keys with this PyQt version"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
OE_KEY = Qt.Key(ord('Œ'))
|
||||||
|
except ValueError:
|
||||||
|
OE_KEY = None # affected tests skipped
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=key_data.KEYS, ids=lambda k: k.attribute)
|
@pytest.fixture(params=key_data.KEYS, ids=lambda k: k.attribute)
|
||||||
def qt_key(request):
|
def qt_key(request):
|
||||||
"""Get all existing keys from key_data.py.
|
"""Get all existing keys from key_data.py.
|
||||||
|
|
@ -156,10 +166,14 @@ class TestKeyToString:
|
||||||
(Qt.Key.Key_A,
|
(Qt.Key.Key_A,
|
||||||
Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier | Qt.KeyboardModifier.MetaModifier | Qt.KeyboardModifier.ShiftModifier,
|
Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier | Qt.KeyboardModifier.MetaModifier | Qt.KeyboardModifier.ShiftModifier,
|
||||||
'<Meta+Ctrl+Alt+Shift+a>'),
|
'<Meta+Ctrl+Alt+Shift+a>'),
|
||||||
(ord('Œ'), Qt.KeyboardModifier.NoModifier, '<Œ>'),
|
|
||||||
(ord('Œ'), Qt.KeyboardModifier.ShiftModifier, '<Shift+Œ>'),
|
pytest.param(OE_KEY, Qt.KeyboardModifier.NoModifier, '<Œ>',
|
||||||
(ord('Œ'), Qt.KeyboardModifier.GroupSwitchModifier, '<AltGr+Œ>'),
|
marks=pyqt_enum_workaround_skip),
|
||||||
(ord('Œ'), Qt.KeyboardModifier.GroupSwitchModifier | Qt.KeyboardModifier.ShiftModifier, '<AltGr+Shift+Œ>'),
|
pytest.param(OE_KEY, Qt.KeyboardModifier.ShiftModifier, '<Shift+Œ>',
|
||||||
|
marks=pyqt_enum_workaround_skip),
|
||||||
|
pytest.param(OE_KEY, Qt.KeyboardModifier.GroupSwitchModifier, '<AltGr+Œ>',
|
||||||
|
marks=pyqt_enum_workaround_skip),
|
||||||
|
pytest.param(OE_KEY, Qt.KeyboardModifier.GroupSwitchModifier | Qt.KeyboardModifier.ShiftModifier, '<AltGr+Shift+Œ>'),
|
||||||
|
|
||||||
(Qt.Key.Key_Shift, Qt.KeyboardModifier.ShiftModifier, '<Shift>'),
|
(Qt.Key.Key_Shift, Qt.KeyboardModifier.ShiftModifier, '<Shift>'),
|
||||||
(Qt.Key.Key_Shift, Qt.KeyboardModifier.ShiftModifier | Qt.KeyboardModifier.ControlModifier, '<Ctrl+Shift>'),
|
(Qt.Key.Key_Shift, Qt.KeyboardModifier.ShiftModifier | Qt.KeyboardModifier.ControlModifier, '<Ctrl+Shift>'),
|
||||||
|
|
@ -212,10 +226,10 @@ def test_surrogates(key, modifiers, text, expected, pyqt_enum_workaround):
|
||||||
([Qt.Key.Key_Shift, 0x29df6], '<Shift><𩷶>'),
|
([Qt.Key.Key_Shift, 0x29df6], '<Shift><𩷶>'),
|
||||||
([0x1f468, 0x200d, 0x1f468, 0x200d, 0x1f466], '<👨><><👨><><👦>'),
|
([0x1f468, 0x200d, 0x1f468, 0x200d, 0x1f466], '<👨><><👨><><👦>'),
|
||||||
])
|
])
|
||||||
def test_surrogate_sequences(keys, expected, pyqt_enum_workaround):
|
@pyqt_enum_workaround_skip
|
||||||
infos = [keyutils.KeyInfo(key) for key in keys]
|
def test_surrogate_sequences(keys, expected):
|
||||||
with pyqt_enum_workaround(keyutils.KeyParseError):
|
infos = [keyutils.KeyInfo(Qt.Key(key)) for key in keys]
|
||||||
seq = keyutils.KeySequence(*infos)
|
seq = keyutils.KeySequence(*infos)
|
||||||
assert str(seq) == expected
|
assert str(seq) == expected
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -590,7 +604,8 @@ def test_key_info_to_qt():
|
||||||
(Qt.Key.Key_Return, False),
|
(Qt.Key.Key_Return, False),
|
||||||
(Qt.Key.Key_Enter, False),
|
(Qt.Key.Key_Enter, False),
|
||||||
(Qt.Key.Key_Space, False),
|
(Qt.Key.Key_Space, False),
|
||||||
(0x0, False), # Used by Qt for unknown keys
|
# Used by Qt for unknown keys
|
||||||
|
pytest.param(keyutils._NIL_KEY, False, marks=pyqt_enum_workaround_skip),
|
||||||
|
|
||||||
(Qt.Key.Key_ydiaeresis, True),
|
(Qt.Key.Key_ydiaeresis, True),
|
||||||
(Qt.Key.Key_X, True),
|
(Qt.Key.Key_X, True),
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import html
|
||||||
import argparse
|
import argparse
|
||||||
import typing
|
import typing
|
||||||
from typing import Any, Optional, List, Dict, Union
|
from typing import Any, Optional, List, Dict, Union
|
||||||
|
import dataclasses
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
@ -214,7 +215,7 @@ def modules():
|
||||||
reason=machinery.SelectionReason.auto,
|
reason=machinery.SelectionReason.auto,
|
||||||
outcomes={
|
outcomes={
|
||||||
"PyQt6": "ImportError: Fake ImportError for PyQt6.",
|
"PyQt6": "ImportError: Fake ImportError for PyQt6.",
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
id="import-error",
|
id="import-error",
|
||||||
),
|
),
|
||||||
|
|
@ -230,111 +231,157 @@ def test_autoselect(
|
||||||
assert machinery._autoselect_wrapper() == expected
|
assert machinery._autoselect_wrapper() == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@dataclasses.dataclass
|
||||||
"args, env, expected",
|
class SelectWrapperCase:
|
||||||
[
|
name: str
|
||||||
# Defaults with no overrides
|
expected: machinery.SelectionInfo
|
||||||
(
|
args: Optional[argparse.Namespace] = None
|
||||||
None,
|
env: Optional[str] = None
|
||||||
None,
|
override: Optional[str] = None
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt5", reason=machinery.SelectionReason.default
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper=None),
|
|
||||||
None,
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt5", reason=machinery.SelectionReason.default
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper=None),
|
|
||||||
"",
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt5", reason=machinery.SelectionReason.default
|
|
||||||
),
|
|
||||||
),
|
|
||||||
# Only argument given
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper="PyQt6"),
|
|
||||||
None,
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt6", reason=machinery.SelectionReason.cli
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper="PyQt5"),
|
|
||||||
None,
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt5", reason=machinery.SelectionReason.cli
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper="PyQt5"),
|
|
||||||
"",
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt5", reason=machinery.SelectionReason.cli
|
|
||||||
),
|
|
||||||
),
|
|
||||||
# Only environment variable given
|
|
||||||
(
|
|
||||||
None,
|
|
||||||
"PyQt6",
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt6", reason=machinery.SelectionReason.env
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
None,
|
|
||||||
"PyQt5",
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt5", reason=machinery.SelectionReason.env
|
|
||||||
),
|
|
||||||
),
|
|
||||||
# Both given
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper="PyQt5"),
|
|
||||||
"PyQt6",
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt5", reason=machinery.SelectionReason.cli
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper="PyQt6"),
|
|
||||||
"PyQt5",
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt6", reason=machinery.SelectionReason.cli
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
argparse.Namespace(qt_wrapper="PyQt6"),
|
|
||||||
"PyQt6",
|
|
||||||
machinery.SelectionInfo(
|
|
||||||
wrapper="PyQt6", reason=machinery.SelectionReason.cli
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_select_wrapper(
|
|
||||||
args: Optional[argparse.Namespace],
|
|
||||||
env: Optional[str],
|
|
||||||
expected: machinery.SelectionInfo,
|
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
|
||||||
undo_init: None,
|
|
||||||
):
|
|
||||||
if env is None:
|
|
||||||
monkeypatch.delenv("QUTE_QT_WRAPPER", raising=False)
|
|
||||||
else:
|
|
||||||
monkeypatch.setenv("QUTE_QT_WRAPPER", env)
|
|
||||||
|
|
||||||
assert machinery._select_wrapper(args) == expected
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
def test_select_wrapper_after_qt_import(monkeypatch: pytest.MonkeyPatch):
|
class TestSelectWrapper:
|
||||||
monkeypatch.setitem(sys.modules, "PyQt6", None)
|
@pytest.mark.parametrize(
|
||||||
with pytest.warns(UserWarning, match="PyQt6 already imported"):
|
"tc",
|
||||||
machinery._select_wrapper(args=None)
|
[
|
||||||
|
# Only argument given
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt6-arg",
|
||||||
|
args=argparse.Namespace(qt_wrapper="PyQt6"),
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt6", reason=machinery.SelectionReason.cli
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt5-arg",
|
||||||
|
args=argparse.Namespace(qt_wrapper="PyQt5"),
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt5", reason=machinery.SelectionReason.cli
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt6-arg-empty-env",
|
||||||
|
args=argparse.Namespace(qt_wrapper="PyQt5"),
|
||||||
|
env="",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt5", reason=machinery.SelectionReason.cli
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Only environment variable given
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt6-env",
|
||||||
|
env="PyQt6",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt6", reason=machinery.SelectionReason.env
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt5-env",
|
||||||
|
env="PyQt5",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt5", reason=machinery.SelectionReason.env
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Both given
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt5-arg-pyqt6-env",
|
||||||
|
args=argparse.Namespace(qt_wrapper="PyQt5"),
|
||||||
|
env="PyQt6",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt5", reason=machinery.SelectionReason.cli
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt6-arg-pyqt5-env",
|
||||||
|
args=argparse.Namespace(qt_wrapper="PyQt6"),
|
||||||
|
env="PyQt5",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt6", reason=machinery.SelectionReason.cli
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SelectWrapperCase(
|
||||||
|
"pyqt6-arg-pyqt6-env",
|
||||||
|
args=argparse.Namespace(qt_wrapper="PyQt6"),
|
||||||
|
env="PyQt6",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt6", reason=machinery.SelectionReason.cli
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Override
|
||||||
|
SelectWrapperCase(
|
||||||
|
"override-only",
|
||||||
|
override="PyQt6",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt6", reason=machinery.SelectionReason.override
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SelectWrapperCase(
|
||||||
|
"override-arg",
|
||||||
|
args=argparse.Namespace(qt_wrapper="PyQt5"),
|
||||||
|
override="PyQt6",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt5", reason=machinery.SelectionReason.cli
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SelectWrapperCase(
|
||||||
|
"override-env",
|
||||||
|
env="PyQt5",
|
||||||
|
override="PyQt6",
|
||||||
|
expected=machinery.SelectionInfo(
|
||||||
|
wrapper="PyQt5", reason=machinery.SelectionReason.env
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ids=str,
|
||||||
|
)
|
||||||
|
def test_select(self, tc: SelectWrapperCase, monkeypatch: pytest.MonkeyPatch):
|
||||||
|
if tc.env is None:
|
||||||
|
monkeypatch.delenv("QUTE_QT_WRAPPER", raising=False)
|
||||||
|
else:
|
||||||
|
monkeypatch.setenv("QUTE_QT_WRAPPER", tc.env)
|
||||||
|
|
||||||
|
if tc.override is not None:
|
||||||
|
monkeypatch.setattr(machinery, "_WRAPPER_OVERRIDE", tc.override)
|
||||||
|
|
||||||
|
assert machinery._select_wrapper(tc.args) == tc.expected
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"args, env",
|
||||||
|
[
|
||||||
|
(None, None),
|
||||||
|
(argparse.Namespace(qt_wrapper=None), None),
|
||||||
|
(argparse.Namespace(qt_wrapper=None), ""),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_autoselect_by_default(
|
||||||
|
self,
|
||||||
|
args: Optional[argparse.Namespace],
|
||||||
|
env: Optional[str],
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
):
|
||||||
|
"""Test that the default behavior is to autoselect a wrapper.
|
||||||
|
|
||||||
|
Autoselection itself is tested further down.
|
||||||
|
"""
|
||||||
|
if env is None:
|
||||||
|
monkeypatch.delenv("QUTE_QT_WRAPPER", raising=False)
|
||||||
|
else:
|
||||||
|
monkeypatch.setenv("QUTE_QT_WRAPPER", env)
|
||||||
|
|
||||||
|
assert machinery._select_wrapper(args).reason == machinery.SelectionReason.auto
|
||||||
|
|
||||||
|
def test_after_qt_import(self, monkeypatch: pytest.MonkeyPatch):
|
||||||
|
monkeypatch.setitem(sys.modules, "PyQt6", None)
|
||||||
|
with pytest.warns(UserWarning, match="PyQt6 already imported"):
|
||||||
|
machinery._select_wrapper(args=None)
|
||||||
|
|
||||||
|
def test_invalid_override(self, monkeypatch: pytest.MonkeyPatch):
|
||||||
|
monkeypatch.setattr(machinery, "_WRAPPER_OVERRIDE", "invalid")
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
|
machinery._select_wrapper(args=None)
|
||||||
|
|
||||||
|
|
||||||
class TestInit:
|
class TestInit:
|
||||||
|
|
@ -359,15 +406,34 @@ class TestInit:
|
||||||
):
|
):
|
||||||
machinery.init(args=empty_args)
|
machinery.init(args=empty_args)
|
||||||
|
|
||||||
|
@pytest.fixture(params=["auto", "", None])
|
||||||
|
def qt_auto_env(
|
||||||
|
self,
|
||||||
|
request: pytest.FixtureRequest,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
):
|
||||||
|
"""Trigger wrapper autoselection via environment variable.
|
||||||
|
|
||||||
|
Autoselection should be used in three scenarios:
|
||||||
|
|
||||||
|
- The environment variable is set to "auto".
|
||||||
|
- The environment variable is set to an empty string.
|
||||||
|
- The environment variable is not set at all.
|
||||||
|
|
||||||
|
We run test_none_available_*() for all three scenarios.
|
||||||
|
"""
|
||||||
|
if request.param is None:
|
||||||
|
monkeypatch.delenv("QUTE_QT_WRAPPER", raising=False)
|
||||||
|
else:
|
||||||
|
monkeypatch.setenv("QUTE_QT_WRAPPER", request.param)
|
||||||
|
|
||||||
def test_none_available_implicit(
|
def test_none_available_implicit(
|
||||||
self,
|
self,
|
||||||
stubs: Any,
|
stubs: Any,
|
||||||
modules: Dict[str, bool],
|
modules: Dict[str, bool],
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
undo_init: None,
|
qt_auto_env: None,
|
||||||
):
|
):
|
||||||
# FIXME:qt6 Also try without this once auto is default
|
|
||||||
monkeypatch.setenv("QUTE_QT_WRAPPER", "auto")
|
|
||||||
stubs.ImportFake(modules, monkeypatch).patch()
|
stubs.ImportFake(modules, monkeypatch).patch()
|
||||||
|
|
||||||
message_lines = [
|
message_lines = [
|
||||||
|
|
@ -391,10 +457,8 @@ class TestInit:
|
||||||
modules: Dict[str, bool],
|
modules: Dict[str, bool],
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
empty_args: argparse.Namespace,
|
empty_args: argparse.Namespace,
|
||||||
undo_init: None,
|
qt_auto_env: None,
|
||||||
):
|
):
|
||||||
# FIXME:qt6 Also try without this once auto is default
|
|
||||||
monkeypatch.setenv("QUTE_QT_WRAPPER", "auto")
|
|
||||||
stubs.ImportFake(modules, monkeypatch).patch()
|
stubs.ImportFake(modules, monkeypatch).patch()
|
||||||
|
|
||||||
info = machinery.init(args=empty_args)
|
info = machinery.init(args=empty_args)
|
||||||
|
|
@ -403,7 +467,7 @@ class TestInit:
|
||||||
reason=machinery.SelectionReason.auto,
|
reason=machinery.SelectionReason.auto,
|
||||||
outcomes={
|
outcomes={
|
||||||
"PyQt6": "ImportError: Fake ImportError for PyQt6.",
|
"PyQt6": "ImportError: Fake ImportError for PyQt6.",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
@ -422,7 +486,6 @@ class TestInit:
|
||||||
true_vars: str,
|
true_vars: str,
|
||||||
explicit: bool,
|
explicit: bool,
|
||||||
empty_args: argparse.Namespace,
|
empty_args: argparse.Namespace,
|
||||||
undo_init: None,
|
|
||||||
):
|
):
|
||||||
info = machinery.SelectionInfo(
|
info = machinery.SelectionInfo(
|
||||||
wrapper=selected_wrapper,
|
wrapper=selected_wrapper,
|
||||||
|
|
|
||||||
41
tox.ini
41
tox.ini
|
|
@ -11,10 +11,10 @@ minversion = 3.20
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv =
|
setenv =
|
||||||
PYTEST_QT_API=pyqt5
|
PYTEST_QT_API=pyqt6
|
||||||
QUTE_QT_WRAPPER=PyQt5
|
QUTE_QT_WRAPPER=PyQt6
|
||||||
pyqt{62,63,64,65}: PYTEST_QT_API=pyqt6
|
pyqt{515,5152}: PYTEST_QT_API=pyqt5
|
||||||
pyqt{62,63,64,65}: QUTE_QT_WRAPPER=PyQt6
|
pyqt{515,5152}: QUTE_QT_WRAPPER=PyQt5
|
||||||
cov: PYTEST_ADDOPTS=--cov --cov-report xml --cov-report=html --cov-report=
|
cov: PYTEST_ADDOPTS=--cov --cov-report xml --cov-report=html --cov-report=
|
||||||
py312: VIRTUALENV_PIP=23.2
|
py312: VIRTUALENV_PIP=23.2
|
||||||
py312: PIP_REQUIRE_VIRTUALENV=0
|
py312: PIP_REQUIRE_VIRTUALENV=0
|
||||||
|
|
@ -56,10 +56,10 @@ commands =
|
||||||
{envpython} -bb -m pytest {posargs:tests}
|
{envpython} -bb -m pytest {posargs:tests}
|
||||||
cov: {envpython} scripts/dev/check_coverage.py {posargs}
|
cov: {envpython} scripts/dev/check_coverage.py {posargs}
|
||||||
|
|
||||||
[testenv:py-qt6]
|
[testenv:py-qt5]
|
||||||
setenv =
|
setenv =
|
||||||
PYTEST_QT_API=pyqt6
|
PYTEST_QT_API=pyqt5
|
||||||
QUTE_QT_WRAPPER=PyQt6
|
QUTE_QT_WRAPPER=PyQt5
|
||||||
|
|
||||||
[testenv:bleeding]
|
[testenv:bleeding]
|
||||||
basepython = {env:PYTHON:python3}
|
basepython = {env:PYTHON:python3}
|
||||||
|
|
@ -112,6 +112,7 @@ deps =
|
||||||
-r{toxinidir}/misc/requirements/requirements-tests.txt
|
-r{toxinidir}/misc/requirements/requirements-tests.txt
|
||||||
-r{toxinidir}/misc/requirements/requirements-pylint.txt
|
-r{toxinidir}/misc/requirements/requirements-pylint.txt
|
||||||
-r{toxinidir}/misc/requirements/requirements-pyqt.txt
|
-r{toxinidir}/misc/requirements/requirements-pyqt.txt
|
||||||
|
-r{toxinidir}/misc/requirements/requirements-pyqt-5.txt
|
||||||
commands =
|
commands =
|
||||||
{envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no {posargs}
|
{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}
|
{envpython} scripts/dev/run_pylint_on_tests.py {toxinidir} --output-format=colorized --reports=no {posargs}
|
||||||
|
|
@ -180,19 +181,19 @@ commands =
|
||||||
{envpython} scripts/dev/check_doc_changes.py {posargs}
|
{envpython} scripts/dev/check_doc_changes.py {posargs}
|
||||||
{envpython} scripts/asciidoc2html.py {posargs}
|
{envpython} scripts/asciidoc2html.py {posargs}
|
||||||
|
|
||||||
[testenv:pyinstaller-{64bit,32bit}{,-qt6}]
|
[testenv:pyinstaller-{64bit,32bit}{,-qt5}]
|
||||||
basepython = {env:PYTHON:python3}
|
basepython = {env:PYTHON:python3}
|
||||||
passenv =
|
passenv =
|
||||||
APPDATA
|
APPDATA
|
||||||
HOME
|
HOME
|
||||||
PYINSTALLER_DEBUG
|
PYINSTALLER_DEBUG
|
||||||
setenv =
|
setenv =
|
||||||
qt6: PYINSTALLER_QT6=true
|
qt5: PYINSTALLER_QT5=true
|
||||||
deps =
|
deps =
|
||||||
-r{toxinidir}/requirements.txt
|
-r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/misc/requirements/requirements-pyinstaller.txt
|
-r{toxinidir}/misc/requirements/requirements-pyinstaller.txt
|
||||||
!qt6: -r{toxinidir}/misc/requirements/requirements-pyqt.txt
|
!qt5: -r{toxinidir}/misc/requirements/requirements-pyqt-6.txt
|
||||||
qt6: -r{toxinidir}/misc/requirements/requirements-pyqt-6.txt
|
qt5: -r{toxinidir}/misc/requirements/requirements-pyqt-5.txt
|
||||||
commands =
|
commands =
|
||||||
{envbindir}/pyinstaller --noconfirm misc/qutebrowser.spec
|
{envbindir}/pyinstaller --noconfirm misc/qutebrowser.spec
|
||||||
|
|
||||||
|
|
@ -246,9 +247,7 @@ commands =
|
||||||
basepython = {env:PYTHON:python3}
|
basepython = {env:PYTHON:python3}
|
||||||
passenv = {[testenv:mypy-pyqt6]passenv}
|
passenv = {[testenv:mypy-pyqt6]passenv}
|
||||||
deps = {[testenv:mypy-pyqt6]deps}
|
deps = {[testenv:mypy-pyqt6]deps}
|
||||||
setenv =
|
setenv = {[testenv:mypy-pyqt6]setenv}
|
||||||
pyqt6: QUTE_CONSTANTS_ARGS=--always-true=USE_PYQT6 --always-false=USE_PYQT5 --always-false=USE_PYSIDE2 --always-false=USE_PYSIDE6 --always-false=IS_QT5 --always-true=IS_QT6
|
|
||||||
pyqt5: QUTE_CONSTANTS_ARGS=--always-false=USE_PYQT6 --always-true=USE_PYQT5 --always-false=USE_PYSIDE2 --always-false=USE_PYSIDE6 --always-true=IS_QT5 --always-false=IS_QT6
|
|
||||||
commands =
|
commands =
|
||||||
{envpython} -m mypy --cobertura-xml-report {envtmpdir} {env:QUTE_CONSTANTS_ARGS} qutebrowser tests {posargs}
|
{envpython} -m mypy --cobertura-xml-report {envtmpdir} {env:QUTE_CONSTANTS_ARGS} qutebrowser tests {posargs}
|
||||||
{envdir}/bin/diff-cover --fail-under=100 --compare-branch={env:DIFF_BRANCH:origin/{env:GITHUB_BASE_REF:master}} {envtmpdir}/cobertura.xml
|
{envdir}/bin/diff-cover --fail-under=100 --compare-branch={env:DIFF_BRANCH:origin/{env:GITHUB_BASE_REF:master}} {envtmpdir}/cobertura.xml
|
||||||
|
|
@ -264,21 +263,21 @@ deps =
|
||||||
commands =
|
commands =
|
||||||
{envpython} -m sphinx -jauto -W --color {posargs} {toxinidir}/doc/extapi/ {toxinidir}/doc/extapi/_build/
|
{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}
|
basepython = {env:PYTHON:python3}
|
||||||
passenv = *
|
passenv = *
|
||||||
# Override default PyQt5 from [testenv]
|
# Override default PyQt6 from [testenv]
|
||||||
setenv =
|
setenv =
|
||||||
qt6: QUTE_QT_WRAPPER=PyQt6
|
qt5: QUTE_QT_WRAPPER=PyQt5
|
||||||
usedevelop = true
|
usedevelop = true
|
||||||
deps =
|
deps =
|
||||||
-r{toxinidir}/requirements.txt
|
-r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/misc/requirements/requirements-tox.txt
|
-r{toxinidir}/misc/requirements/requirements-tox.txt
|
||||||
-r{toxinidir}/misc/requirements/requirements-docs.txt
|
-r{toxinidir}/misc/requirements/requirements-docs.txt
|
||||||
!qt6: -r{toxinidir}/misc/requirements/requirements-pyqt.txt
|
!qt5: -r{toxinidir}/misc/requirements/requirements-pyqt.txt
|
||||||
qt6: -r{toxinidir}/misc/requirements/requirements-pyqt-6.txt
|
qt5: -r{toxinidir}/misc/requirements/requirements-pyqt-5.txt
|
||||||
-r{toxinidir}/misc/requirements/requirements-dev.txt
|
-r{toxinidir}/misc/requirements/requirements-dev.txt
|
||||||
-r{toxinidir}/misc/requirements/requirements-pyinstaller.txt
|
-r{toxinidir}/misc/requirements/requirements-pyinstaller.txt
|
||||||
commands =
|
commands =
|
||||||
!qt6: {envpython} {toxinidir}/scripts/dev/build_release.py {posargs}
|
!qt5: {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 --qt5 {posargs}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue