summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2023-11-22 09:17:43 +0100
committerFlorian Bruhin <me@the-compiler.org>2023-11-22 09:17:43 +0100
commitab198177bdd492cdb926651dfbc30256f01fc6af (patch)
treea9649263c7338133dbc2e52e8c2aef6ab828056f
parent7b6cda95fb70a177bfaf7c4cee89e82cf485d938 (diff)
parent723a5db8f2986197e8179b4cc2143da2410b0a66 (diff)
downloadqutebrowser-ab198177bdd492cdb926651dfbc30256f01fc6af.tar.gz
qutebrowser-ab198177bdd492cdb926651dfbc30256f01fc6af.zip
Merge branch 'main' into pakjoy
-rw-r--r--.bumpversion.cfg2
-rw-r--r--.github/workflows/ci.yml28
-rw-r--r--.github/workflows/nightly.yml6
-rw-r--r--.github/workflows/release.yml6
-rw-r--r--README.asciidoc2
-rw-r--r--doc/backers.asciidoc8
-rw-r--r--doc/changelog.asciidoc2
-rw-r--r--doc/contributing.asciidoc51
-rw-r--r--misc/org.qutebrowser.qutebrowser.appdata.xml1
-rw-r--r--misc/qutebrowser.spec6
-rw-r--r--misc/requirements/requirements-dev.txt16
-rw-r--r--misc/requirements/requirements-flake8.txt4
-rw-r--r--misc/requirements/requirements-mypy.txt12
-rw-r--r--misc/requirements/requirements-pyinstaller.txt5
-rw-r--r--misc/requirements/requirements-pyinstaller.txt-raw2
-rw-r--r--misc/requirements/requirements-pylint.txt14
-rw-r--r--misc/requirements/requirements-pyqt-6.6.txt7
-rw-r--r--misc/requirements/requirements-pyqt-6.6.txt-raw4
-rw-r--r--misc/requirements/requirements-pyqt-6.txt8
-rw-r--r--misc/requirements/requirements-pyqt.txt8
-rw-r--r--misc/requirements/requirements-pyroma.txt10
-rw-r--r--misc/requirements/requirements-sphinx.txt10
-rw-r--r--misc/requirements/requirements-tests.txt28
-rw-r--r--misc/requirements/requirements-tox.txt10
-rw-r--r--misc/requirements/requirements-yamllint.txt2
-rw-r--r--qutebrowser/__init__.py2
-rw-r--r--qutebrowser/browser/browsertab.py13
-rw-r--r--qutebrowser/browser/webengine/webengineinspector.py16
-rw-r--r--qutebrowser/browser/webengine/webenginesettings.py21
-rw-r--r--qutebrowser/browser/webengine/webenginetab.py5
-rw-r--r--qutebrowser/browser/webengine/webview.py48
-rw-r--r--qutebrowser/extensions/loader.py28
-rw-r--r--qutebrowser/utils/qtutils.py32
-rw-r--r--qutebrowser/utils/version.py6
-rw-r--r--requirements.txt4
-rw-r--r--scripts/dev/ci/problemmatchers.py8
-rw-r--r--tests/end2end/fixtures/quteprocess.py3
-rw-r--r--tests/end2end/test_invocations.py84
-rw-r--r--tests/unit/extensions/test_loader.py8
-rw-r--r--tox.ini5
40 files changed, 329 insertions, 206 deletions
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 8b83ca8bf..051e07b87 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 3.0.1
+current_version = 3.0.2
commit = True
message = Release v{new_version}
tag = True
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9d7963ea7..c2babf437 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -48,7 +48,7 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
node-version: '16.x'
if: "matrix.testenv == 'eslint'"
@@ -157,28 +157,28 @@ jobs:
- testenv: py310-pyqt65
os: ubuntu-22.04
python: "3.10"
- ### PyQt 6.5 (Python 3.11)
- - testenv: py311-pyqt65
+ ### PyQt 6.6 (Python 3.11)
+ - testenv: py311-pyqt66
os: ubuntu-22.04
python: "3.11"
- ### PyQt 6.5 (Python 3.12)
- - testenv: py312-pyqt65
+ ### PyQt 6.6 (Python 3.12)
+ - testenv: py312-pyqt66
os: ubuntu-22.04
- python: "3.12-dev"
- ### macOS Big Sur: PyQt 5.15 (Python 3.9 to match PyInstaller env)
- - testenv: py39-pyqt515
+ python: "3.12"
+ ### macOS Big Sur
+ - testenv: py311-pyqt66
os: macos-11
- python: "3.9"
+ python: "3.11"
args: "tests/unit" # Only run unit tests on macOS
### macOS Monterey
- - testenv: py39-pyqt515
+ - testenv: py311-pyqt66
os: macos-12
- python: "3.9"
+ python: "3.11"
args: "tests/unit" # Only run unit tests on macOS
- ### Windows: PyQt 5.15 (Python 3.9 to match PyInstaller env)
- - testenv: py39-pyqt515
+ ### Windows
+ - testenv: py311-pyqt66
os: windows-2019
- python: "3.9"
+ python: "3.11"
runs-on: "${{ matrix.os }}"
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 76332e8ba..433cd3c0b 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -15,24 +15,19 @@ jobs:
matrix:
include:
- os: macos-11
- branch: main
toxenv: build-release-qt5
name: qt5-macos
- os: windows-2019
- branch: main
toxenv: build-release-qt5
name: qt5-windows
- os: macos-11
args: --debug
- branch: main
toxenv: build-release-qt5
name: qt5-macos-debug
- os: windows-2019
args: --debug
- branch: main
toxenv: build-release-qt5
name: qt5-windows-debug
-
- os: macos-11
toxenv: build-release
name: macos
@@ -52,7 +47,6 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
- ref: "${{ matrix.branch }}"
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v4
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 786f9742c..fd3bc5cd8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -34,7 +34,7 @@ jobs:
contents: write # To push release commit/tag
steps:
- name: Find release branch
- uses: actions/github-script@v6
+ uses: actions/github-script@v7
id: find-branch
with:
script: |
@@ -84,7 +84,7 @@ jobs:
id: bump
run: "tox -e update-version -- ${{ github.event.inputs.release_type }}"
- name: Check milestone
- uses: actions/github-script@v6
+ uses: actions/github-script@v7
with:
script: |
const milestones = await github.paginate(github.rest.issues.listMilestones, {
@@ -178,7 +178,7 @@ jobs:
contents: write # To change release
steps:
- name: Publish final release
- uses: actions/github-script@v6
+ uses: actions/github-script@v7
with:
script: |
await github.rest.repos.updateRelease({
diff --git a/README.asciidoc b/README.asciidoc
index 2b6bdfdd6..364f8fa62 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -227,7 +227,7 @@ Active
https://tridactyl.xyz/[Tridactyl],
https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/[Vimium-FF]
* Addons for Firefox and Chrome:
- https://github.com/brookhong/Surfingkeys[Surfingkeys],
+ https://github.com/brookhong/Surfingkeys[Surfingkeys] (https://github.com/brookhong/Surfingkeys/issues/1796[somewhat sketchy]...),
https://lydell.github.io/LinkHints/[Link Hints] (hinting only),
https://github.com/ueokande/vimmatic[Vimmatic]
diff --git a/doc/backers.asciidoc b/doc/backers.asciidoc
index bdabb5f96..81ccc14ab 100644
--- a/doc/backers.asciidoc
+++ b/doc/backers.asciidoc
@@ -1,6 +1,14 @@
Crowdfunding backers
====================
+2019+
+-----
+
+Since late 2019, qutebrowser is taking recurring donations via
+https://github.com/sponsors/The-Compiler/[GitHub Sponsors] and
+https://liberapay.com/The-Compiler/[Liberapay]. You can find Sponsors/Patrons
+who opted to be listed as public on the respective pages. **Thank you!**
+
2017
----
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index db4014be5..a799deaab 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -16,7 +16,7 @@ breaking changes (such as renamed commands) can happen in minor releases.
// `Security` to invite users to upgrade in case of vulnerabilities.
[[v3.0.2]]
-v3.0.2 (unreleased)
+v3.0.2 (2023-10-19)
-------------------
Fixed
diff --git a/doc/contributing.asciidoc b/doc/contributing.asciidoc
index 0be2655c5..144117677 100644
--- a/doc/contributing.asciidoc
+++ b/doc/contributing.asciidoc
@@ -575,35 +575,46 @@ Chrome URLs
~~~~~~~~~~~
With the QtWebEngine backend, qutebrowser supports several chrome:// urls which
-can be useful for debugging:
+can be useful for debugging.
-- chrome://accessibility/
-- chrome://appcache-internals/
-- chrome://blob-internals/
-- chrome://conversion-internals/ (QtWebEngine 5.15.3+)
-- chrome://crash/ (crashes the current renderer process!)
+Info pages:
+
+- chrome://device-log/ (QtWebEngine >= 6.3)
- chrome://gpu/
-- chrome://gpuclean/ (crashes the current renderer process!)
-- chrome://gpucrash/ (crashes qutebrowser!)
-- chrome://gpuhang/ (hangs qutebrowser!)
+- chrome://sandbox/ (Linux only)
+
+Misc. / Debugging pages:
+
+- chrome://dino/
- chrome://histograms/
+- chrome://network-errors/
+- chrome://tracing/ (QtWebEngine >= 5.15.3)
+- chrome://ukm/ (QtWebEngine >= 5.15.3)
+- chrome://user-actions/ (QtWebEngine >= 5.15.3)
+- chrome://webrtc-logs/ (QtWebEngine >= 5.15.3)
+
+Internals pages:
+
+- chrome://accessibility/
+- chrome://appcache-internals/ (QtWebEngine < 6.4)
+- chrome://attribution-internals/ (QtWebEngine >= 6.4)
+- chrome://blob-internals/
+- chrome://conversion-internals/ (QtWebEngine >= 5.15.3 and < 6.4)
- chrome://indexeddb-internals/
-- chrome://kill/ (kills the current renderer process!)
- chrome://media-internals/
-- chrome://net-internals/ (QtWebEngine 5.15.4+)
-- chrome://network-errors/
-- chrome://ppapiflashcrash/
-- chrome://ppapiflashhang/
+- chrome://net-internals/ (QtWebEngine >= 5.15.4)
- chrome://process-internals/
- chrome://quota-internals/
-- chrome://sandbox/ (Linux only)
- chrome://serviceworker-internals/
-- chrome://taskscheduler-internals/ (removed in QtWebEngine 5.14)
-- chrome://tracing/ (QtWebEngine 5.15.3+)
-- chrome://ukm/ (QtWebEngine 5.15.3+)
-- chrome://user-actions/ (QtWebEngine 5.15.3+)
- chrome://webrtc-internals/
-- chrome://webrtc-logs/ (QtWebEngine 5.15.3+)
+
+Crash/hang pages:
+
+- chrome://crash/ (crashes the current renderer process!)
+- chrome://gpuclean/ (crashes the current renderer process!)
+- chrome://gpucrash/ (crashes qutebrowser!)
+- chrome://gpuhang/ (hangs qutebrowser!)
+- chrome://kill/ (kills the current renderer process!)
QtWebEngine internals
~~~~~~~~~~~~~~~~~~~~~
diff --git a/misc/org.qutebrowser.qutebrowser.appdata.xml b/misc/org.qutebrowser.qutebrowser.appdata.xml
index 6dabaa36b..477a8194c 100644
--- a/misc/org.qutebrowser.qutebrowser.appdata.xml
+++ b/misc/org.qutebrowser.qutebrowser.appdata.xml
@@ -44,6 +44,7 @@
</content_rating>
<releases>
<!-- Add new releases here -->
+<release version="3.0.2" date="2023-10-19"/>
<release version="3.0.1" date="2023-10-19"/>
<release version="3.0.0" date="2023-08-18"/>
<release version="2.5.4" date="2023-03-13"/>
diff --git a/misc/qutebrowser.spec b/misc/qutebrowser.spec
index ecb9da68e..652f69bfb 100644
--- a/misc/qutebrowser.spec
+++ b/misc/qutebrowser.spec
@@ -100,6 +100,11 @@ else:
DEBUG = os.environ.get('PYINSTALLER_DEBUG', '').lower() in ['1', 'true']
+if DEBUG:
+ options = options = [('v', None, 'OPTION')]
+else:
+ options = []
+
a = Analysis(['../qutebrowser/__main__.py'],
@@ -117,6 +122,7 @@ pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
+ options,
exclude_binaries=True,
name='qutebrowser',
icon=icon,
diff --git a/misc/requirements/requirements-dev.txt b/misc/requirements/requirements-dev.txt
index 65adceac5..df7c7b847 100644
--- a/misc/requirements/requirements-dev.txt
+++ b/misc/requirements/requirements-dev.txt
@@ -2,19 +2,19 @@
build==1.0.3
bump2version==1.0.1
-certifi==2023.7.22
+certifi==2023.11.17
cffi==1.16.0
-charset-normalizer==3.3.0
-cryptography==41.0.4
+charset-normalizer==3.3.2
+cryptography==41.0.5
docutils==0.20.1
github3.py==4.0.1
hunter==3.6.1
idna==3.4
importlib-metadata==6.8.0
-importlib-resources==6.1.0
+importlib-resources==6.1.1
jaraco.classes==3.3.0
jeepney==0.8.0
-keyring==24.2.0
+keyring==24.3.0
manhole==1.8.0
markdown-it-py==3.0.0
mdurl==0.1.2
@@ -24,7 +24,7 @@ packaging==23.2
pkginfo==1.9.6
ply==3.11
pycparser==2.21
-Pygments==2.16.1
+Pygments==2.17.1
PyJWT==2.8.0
Pympler==1.0.1
pyproject_hooks==1.0.0
@@ -34,7 +34,7 @@ readme-renderer==42.0
requests==2.31.0
requests-toolbelt==1.0.0
rfc3986==2.0.0
-rich==13.6.0
+rich==13.7.0
SecretStorage==3.3.3
sip==6.7.12
six==1.16.0
@@ -42,5 +42,5 @@ tomli==2.0.1
twine==4.0.2
typing_extensions==4.8.0
uritemplate==4.1.1
-# urllib3==2.0.6
+# urllib3==2.1.0
zipp==3.17.0
diff --git a/misc/requirements/requirements-flake8.txt b/misc/requirements/requirements-flake8.txt
index 95a9cb382..6995f7ac5 100644
--- a/misc/requirements/requirements-flake8.txt
+++ b/misc/requirements/requirements-flake8.txt
@@ -3,10 +3,10 @@
attrs==23.1.0
flake8==6.1.0
flake8-bugbear==23.9.16
-flake8-builtins==2.1.0
+flake8-builtins==2.2.0
flake8-comprehensions==3.14.0
flake8-debugger==4.1.2
-flake8-deprecated==2.1.0
+flake8-deprecated==2.2.1
flake8-docstrings==1.7.0
flake8-future-import==0.4.7
flake8-plugin-utils==1.3.3
diff --git a/misc/requirements/requirements-mypy.txt b/misc/requirements/requirements-mypy.txt
index 418611aae..f1d5c8bdf 100644
--- a/misc/requirements/requirements-mypy.txt
+++ b/misc/requirements/requirements-mypy.txt
@@ -1,21 +1,21 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
chardet==5.2.0
-diff_cover==8.0.0
-importlib-resources==6.1.0
+diff_cover==8.0.1
+importlib-resources==6.1.1
Jinja2==3.1.2
lxml==4.9.3
MarkupSafe==2.1.3
-mypy==1.6.0
+mypy==1.7.0
mypy-extensions==1.0.0
pluggy==1.3.0
-Pygments==2.16.1
+Pygments==2.17.1
PyQt5-stubs==5.15.6.0
tomli==2.0.1
types-colorama==0.4.15.12
types-docutils==0.20.0.3
-types-Pygments==2.16.0.0
+types-Pygments==2.16.0.1
types-PyYAML==6.0.12.12
-types-setuptools==68.2.0.0
+types-setuptools==68.2.0.1
typing_extensions==4.8.0
zipp==3.17.0
diff --git a/misc/requirements/requirements-pyinstaller.txt b/misc/requirements/requirements-pyinstaller.txt
index 84f35ea61..d1a2c18c9 100644
--- a/misc/requirements/requirements-pyinstaller.txt
+++ b/misc/requirements/requirements-pyinstaller.txt
@@ -1,5 +1,8 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
altgraph==0.17.4
-pyinstaller @ git+https://github.com/pyinstaller/pyinstaller.git@79f62ef29822169ae00cd4271390d0e3175476ad
+importlib-metadata==6.8.0
+packaging==23.2
+pyinstaller==6.2.0
pyinstaller-hooks-contrib==2023.10
+zipp==3.17.0
diff --git a/misc/requirements/requirements-pyinstaller.txt-raw b/misc/requirements/requirements-pyinstaller.txt-raw
index 7b4c8c84c..ef376ca83 100644
--- a/misc/requirements/requirements-pyinstaller.txt-raw
+++ b/misc/requirements/requirements-pyinstaller.txt-raw
@@ -1 +1 @@
-pyinstaller @ git+https://github.com/pyinstaller/pyinstaller.git@79f62ef29822169ae00cd4271390d0e3175476ad
+pyinstaller
diff --git a/misc/requirements/requirements-pylint.txt b/misc/requirements/requirements-pylint.txt
index a3821428a..7d4dc69b7 100644
--- a/misc/requirements/requirements-pylint.txt
+++ b/misc/requirements/requirements-pylint.txt
@@ -1,26 +1,26 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
astroid==3.0.1
-certifi==2023.7.22
+certifi==2023.11.17
cffi==1.16.0
-charset-normalizer==3.3.0
-cryptography==41.0.4
+charset-normalizer==3.3.2
+cryptography==41.0.5
dill==0.3.7
github3.py==4.0.1
idna==3.4
isort==5.12.0
mccabe==0.7.0
pefile==2023.2.7
-platformdirs==3.11.0
+platformdirs==4.0.0
pycparser==2.21
PyJWT==2.8.0
-pylint==3.0.1
+pylint==3.0.2
python-dateutil==2.8.2
./scripts/dev/pylint_checkers
requests==2.31.0
six==1.16.0
tomli==2.0.1
-tomlkit==0.12.1
+tomlkit==0.12.3
typing_extensions==4.8.0
uritemplate==4.1.1
-# urllib3==2.0.6
+# urllib3==2.1.0
diff --git a/misc/requirements/requirements-pyqt-6.6.txt b/misc/requirements/requirements-pyqt-6.6.txt
new file mode 100644
index 000000000..0a9c72e25
--- /dev/null
+++ b/misc/requirements/requirements-pyqt-6.6.txt
@@ -0,0 +1,7 @@
+# This file is automatically generated by scripts/dev/recompile_requirements.py
+
+PyQt6==6.6.0
+PyQt6-Qt6==6.6.0
+PyQt6-sip==13.6.0
+PyQt6-WebEngine==6.6.0
+PyQt6-WebEngine-Qt6==6.6.0
diff --git a/misc/requirements/requirements-pyqt-6.6.txt-raw b/misc/requirements/requirements-pyqt-6.6.txt-raw
new file mode 100644
index 000000000..7cfe6d34c
--- /dev/null
+++ b/misc/requirements/requirements-pyqt-6.6.txt-raw
@@ -0,0 +1,4 @@
+PyQt6 >= 6.6, < 6.7
+PyQt6-Qt6 >= 6.6, < 6.7
+PyQt6-WebEngine >= 6.6, < 6.7
+PyQt6-WebEngine-Qt6 >= 6.6, < 6.7
diff --git a/misc/requirements/requirements-pyqt-6.txt b/misc/requirements/requirements-pyqt-6.txt
index 5dca9ab74..0a9c72e25 100644
--- a/misc/requirements/requirements-pyqt-6.txt
+++ b/misc/requirements/requirements-pyqt-6.txt
@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-PyQt6==6.5.3
-PyQt6-Qt6==6.5.3
+PyQt6==6.6.0
+PyQt6-Qt6==6.6.0
PyQt6-sip==13.6.0
-PyQt6-WebEngine==6.5.0
-PyQt6-WebEngine-Qt6==6.5.3
+PyQt6-WebEngine==6.6.0
+PyQt6-WebEngine-Qt6==6.6.0
diff --git a/misc/requirements/requirements-pyqt.txt b/misc/requirements/requirements-pyqt.txt
index 5dca9ab74..0a9c72e25 100644
--- a/misc/requirements/requirements-pyqt.txt
+++ b/misc/requirements/requirements-pyqt.txt
@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-PyQt6==6.5.3
-PyQt6-Qt6==6.5.3
+PyQt6==6.6.0
+PyQt6-Qt6==6.6.0
PyQt6-sip==13.6.0
-PyQt6-WebEngine==6.5.0
-PyQt6-WebEngine-Qt6==6.5.3
+PyQt6-WebEngine==6.6.0
+PyQt6-WebEngine-Qt6==6.6.0
diff --git a/misc/requirements/requirements-pyroma.txt b/misc/requirements/requirements-pyroma.txt
index 72dc5545c..b80f5f63a 100644
--- a/misc/requirements/requirements-pyroma.txt
+++ b/misc/requirements/requirements-pyroma.txt
@@ -1,17 +1,17 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
build==1.0.3
-certifi==2023.7.22
-charset-normalizer==3.3.0
+certifi==2023.11.17
+charset-normalizer==3.3.2
docutils==0.20.1
idna==3.4
importlib-metadata==6.8.0
packaging==23.2
-Pygments==2.16.1
+Pygments==2.17.1
pyproject_hooks==1.0.0
pyroma==4.2
requests==2.31.0
tomli==2.0.1
-trove-classifiers==2023.9.19
-urllib3==2.0.6
+trove-classifiers==2023.11.14
+urllib3==2.1.0
zipp==3.17.0
diff --git a/misc/requirements/requirements-sphinx.txt b/misc/requirements/requirements-sphinx.txt
index afc173af6..5de9398fb 100644
--- a/misc/requirements/requirements-sphinx.txt
+++ b/misc/requirements/requirements-sphinx.txt
@@ -1,9 +1,9 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
alabaster==0.7.13
-Babel==2.13.0
-certifi==2023.7.22
-charset-normalizer==3.3.0
+Babel==2.13.1
+certifi==2023.11.17
+charset-normalizer==3.3.2
docutils==0.20.1
idna==3.4
imagesize==1.4.1
@@ -11,7 +11,7 @@ importlib-metadata==6.8.0
Jinja2==3.1.2
MarkupSafe==2.1.3
packaging==23.2
-Pygments==2.16.1
+Pygments==2.17.1
pytz==2023.3.post1
requests==2.31.0
snowballstemmer==2.2.0
@@ -22,5 +22,5 @@ sphinxcontrib-htmlhelp==2.0.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
-urllib3==2.0.6
+urllib3==2.1.0
zipp==3.17.0
diff --git a/misc/requirements/requirements-tests.txt b/misc/requirements/requirements-tests.txt
index b772d87f8..86e13960a 100644
--- a/misc/requirements/requirements-tests.txt
+++ b/misc/requirements/requirements-tests.txt
@@ -2,25 +2,25 @@
attrs==23.1.0
beautifulsoup4==4.12.2
-blinker==1.6.3
-certifi==2023.7.22
-charset-normalizer==3.3.0
+blinker==1.7.0
+certifi==2023.11.17
+charset-normalizer==3.3.2
cheroot==10.0.0
click==8.1.7
coverage==7.3.2
exceptiongroup==1.1.3
execnet==2.0.2
-filelock==3.12.4
+filelock==3.13.1
Flask==3.0.0
hunter==3.6.1
-hypothesis==6.88.0
+hypothesis==6.90.0
idna==3.4
importlib-metadata==6.8.0
iniconfig==2.0.0
itsdangerous==2.1.2
-jaraco.functools==3.9.0
+jaraco.functools==4.0.0
# Jinja2==3.1.2
-Mako==1.2.4
+Mako==1.3.0
manhole==1.8.0
# MarkupSafe==2.1.3
more-itertools==10.1.0
@@ -29,17 +29,17 @@ parse==1.19.1
parse-type==0.6.2
pluggy==1.3.0
py-cpuinfo==9.0.0
-Pygments==2.16.1
-pytest==7.4.2
+Pygments==2.17.1
+pytest==7.4.3
pytest-bdd==7.0.0
pytest-benchmark==4.0.0
pytest-cov==4.1.0
pytest-instafail==0.5.0
-pytest-mock==3.11.1
+pytest-mock==3.12.0
pytest-qt==4.2.0
pytest-repeat==0.9.3
pytest-rerunfailures==12.0
-pytest-xdist==3.3.1
+pytest-xdist==3.4.0
pytest-xvfb==3.0.0
PyVirtualDisplay==3.0
requests==2.31.0
@@ -47,11 +47,11 @@ requests-file==1.5.1
six==1.16.0
sortedcontainers==2.4.0
soupsieve==2.5
-tldextract==5.0.0
+tldextract==5.1.1
toml==0.10.2
tomli==2.0.1
typing_extensions==4.8.0
-urllib3==2.0.6
+urllib3==2.1.0
vulture==2.10
-Werkzeug==3.0.0
+Werkzeug==3.0.1
zipp==3.17.0
diff --git a/misc/requirements/requirements-tox.txt b/misc/requirements/requirements-tox.txt
index 4c719ce5b..0b1b5277d 100644
--- a/misc/requirements/requirements-tox.txt
+++ b/misc/requirements/requirements-tox.txt
@@ -1,17 +1,17 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-cachetools==5.3.1
+cachetools==5.3.2
chardet==5.2.0
colorama==0.4.6
distlib==0.3.7
-filelock==3.12.4
+filelock==3.13.1
packaging==23.2
-pip==23.3
+pip==23.3.1
platformdirs==3.11.0
pluggy==1.3.0
pyproject-api==1.6.1
setuptools==68.2.2
tomli==2.0.1
tox==4.11.3
-virtualenv==20.24.5
-wheel==0.41.2
+virtualenv==20.24.6
+wheel==0.41.3
diff --git a/misc/requirements/requirements-yamllint.txt b/misc/requirements/requirements-yamllint.txt
index fd9ea256f..32589d26f 100644
--- a/misc/requirements/requirements-yamllint.txt
+++ b/misc/requirements/requirements-yamllint.txt
@@ -2,4 +2,4 @@
pathspec==0.11.2
PyYAML==6.0.1
-yamllint==1.32.0
+yamllint==1.33.0
diff --git a/qutebrowser/__init__.py b/qutebrowser/__init__.py
index 6a1a21806..522545e12 100644
--- a/qutebrowser/__init__.py
+++ b/qutebrowser/__init__.py
@@ -11,7 +11,7 @@ __copyright__ = "Copyright 2014-2021 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
-__version__ = "3.0.1"
+__version__ = "3.0.2"
__version_info__ = tuple(int(part) for part in __version__.split('.'))
__description__ = "A keyboard-driven, vim-like browser based on Python and Qt."
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index 1312275dc..4d14c9cd7 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
-"""Base class for a wrapper over QWebView/QWebEngineView."""
+"""Base class for a wrapper over WebView/WebEngineView."""
import enum
import pathlib
@@ -22,10 +22,9 @@ from qutebrowser.qt.network import QNetworkAccessManager
if TYPE_CHECKING:
from qutebrowser.qt.webkit import QWebHistory, QWebHistoryItem
- from qutebrowser.qt.webkitwidgets import QWebPage, QWebView
+ from qutebrowser.qt.webkitwidgets import QWebPage
from qutebrowser.qt.webenginecore import (
QWebEngineHistory, QWebEngineHistoryItem, QWebEnginePage)
- from qutebrowser.qt.webenginewidgets import QWebEngineView
from qutebrowser.keyinput import modeman
from qutebrowser.config import config, websettings
@@ -38,10 +37,12 @@ from qutebrowser.qt import sip
if TYPE_CHECKING:
from qutebrowser.browser import webelem
from qutebrowser.browser.inspector import AbstractWebInspector
+ from qutebrowser.browser.webengine.webview import WebEngineView
+ from qutebrowser.browser.webkit.webview import WebView
tab_id_gen = itertools.count(0)
-_WidgetType = Union["QWebView", "QWebEngineView"]
+_WidgetType = Union["WebView", "WebEngineView"]
def create(win_id: int,
@@ -964,7 +965,7 @@ class AbstractTabPrivate:
class AbstractTab(QWidget):
- """An adapter for QWebView/QWebEngineView representing a single tab."""
+ """An adapter for WebView/WebEngineView representing a single tab."""
#: Signal emitted when a website requests to close this tab.
window_close_requested = pyqtSignal()
@@ -1058,7 +1059,7 @@ class AbstractTab(QWidget):
self.before_load_started.connect(self._on_before_load_started)
- def _set_widget(self, widget: Union["QWebView", "QWebEngineView"]) -> None:
+ def _set_widget(self, widget: _WidgetType) -> None:
# pylint: disable=protected-access
self._widget = widget
# FIXME:v4 ignore needed for QtWebKit
diff --git a/qutebrowser/browser/webengine/webengineinspector.py b/qutebrowser/browser/webengine/webengineinspector.py
index 64ef24319..d37f41ba5 100644
--- a/qutebrowser/browser/webengine/webengineinspector.py
+++ b/qutebrowser/browser/webengine/webengineinspector.py
@@ -35,14 +35,19 @@ class WebEngineInspectorView(QWebEngineView):
See WebEngineView.createWindow for details.
"""
- inspected_page = self.page().inspectedPage()
+ our_page = self.page()
+ assert our_page is not None
+ inspected_page = our_page.inspectedPage()
+ assert inspected_page is not None
if machinery.IS_QT5:
view = inspected_page.view()
assert isinstance(view, QWebEngineView), view
return view.createWindow(wintype)
else: # Qt 6
newpage = inspected_page.createWindow(wintype)
- return webview.WebEngineView.forPage(newpage)
+ ret = webview.WebEngineView.forPage(newpage)
+ assert ret is not None
+ return ret
class WebEngineInspector(inspector.AbstractWebInspector):
@@ -88,16 +93,17 @@ class WebEngineInspector(inspector.AbstractWebInspector):
def inspect(self, page: QWebEnginePage) -> None:
if not self._widget:
view = WebEngineInspectorView()
- inspector_page = QWebEnginePage(
+ new_page = QWebEnginePage(
page.profile(),
self
)
- inspector_page.windowCloseRequested.connect(self._on_window_close_requested)
- view.setPage(inspector_page)
+ new_page.windowCloseRequested.connect(self._on_window_close_requested)
+ view.setPage(new_page)
self._settings = webenginesettings.WebEngineSettings(view.settings())
self._set_widget(view)
inspector_page = self._widget.page()
+ assert inspector_page is not None
assert inspector_page.profile() == page.profile()
inspector_page.setInspectedPage(page)
diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py
index 168fb8280..e1aa7c52e 100644
--- a/qutebrowser/browser/webengine/webenginesettings.py
+++ b/qutebrowser/browser/webengine/webenginesettings.py
@@ -51,8 +51,12 @@ class _SettingsWrapper:
For read operations, the default profile value is always used.
"""
+ def _default_profile_settings(self):
+ assert default_profile is not None
+ return default_profile.settings()
+
def _settings(self):
- yield default_profile.settings()
+ yield self._default_profile_settings()
if private_profile:
yield private_profile.settings()
@@ -77,19 +81,19 @@ class _SettingsWrapper:
settings.setUnknownUrlSchemePolicy(policy)
def testAttribute(self, attribute):
- return default_profile.settings().testAttribute(attribute)
+ return self._default_profile_settings().testAttribute(attribute)
def fontSize(self, fonttype):
- return default_profile.settings().fontSize(fonttype)
+ return self._default_profile_settings().fontSize(fonttype)
def fontFamily(self, which):
- return default_profile.settings().fontFamily(which)
+ return self._default_profile_settings().fontFamily(which)
def defaultTextEncoding(self):
- return default_profile.settings().defaultTextEncoding()
+ return self._default_profile_settings().defaultTextEncoding()
def unknownUrlSchemePolicy(self):
- return default_profile.settings().unknownUrlSchemePolicy()
+ return self._default_profile_settings().unknownUrlSchemePolicy()
class WebEngineSettings(websettings.AbstractSettings):
@@ -342,7 +346,10 @@ def _init_user_agent_str(ua):
def init_user_agent():
- _init_user_agent_str(QWebEngineProfile.defaultProfile().httpUserAgent())
+ """Make the default WebEngine user agent available via parsed_user_agent."""
+ actual_default_profile = QWebEngineProfile.defaultProfile()
+ assert actual_default_profile is not None
+ _init_user_agent_str(actual_default_profile.httpUserAgent())
def _init_profile(profile: QWebEngineProfile) -> None:
diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py
index 9f1d04b63..1c712db5e 100644
--- a/qutebrowser/browser/webengine/webenginetab.py
+++ b/qutebrowser/browser/webengine/webenginetab.py
@@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
-"""Wrapper over a QWebEngineView."""
+"""Wrapper over a WebEngineView."""
import math
import struct
@@ -15,7 +15,6 @@ from typing import cast, Union, Optional
from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, Qt, QPoint, QPointF, QTimer, QUrl,
QObject, QByteArray)
from qutebrowser.qt.network import QAuthenticator
-from qutebrowser.qt.webenginewidgets import QWebEngineView
from qutebrowser.qt.webenginecore import QWebEnginePage, QWebEngineScript, QWebEngineHistory
from qutebrowser.config import config
@@ -1267,7 +1266,7 @@ class WebEngineTab(browsertab.AbstractTab):
abort_questions = pyqtSignal()
- _widget: QWebEngineView
+ _widget: webview.WebEngineView
search: WebEngineSearch
audio: WebEngineAudio
printing: WebEnginePrinting
diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py
index 3c63c59e4..a6f2ae113 100644
--- a/qutebrowser/browser/webengine/webview.py
+++ b/qutebrowser/browser/webengine/webview.py
@@ -5,13 +5,16 @@
"""The main browser widget for QtWebEngine."""
import mimetypes
-from typing import List, Iterable
+from typing import List, Iterable, Optional
from qutebrowser.qt import machinery
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QUrl
from qutebrowser.qt.gui import QPalette
from qutebrowser.qt.webenginewidgets import QWebEngineView
-from qutebrowser.qt.webenginecore import QWebEnginePage, QWebEngineCertificateError
+from qutebrowser.qt.webenginecore import (
+ QWebEnginePage, QWebEngineCertificateError, QWebEngineSettings,
+ QWebEngineHistory,
+)
from qutebrowser.browser import shared
from qutebrowser.browser.webengine import webenginesettings, certificateerror
@@ -129,6 +132,25 @@ class WebEngineView(QWebEngineView):
return
super().contextMenuEvent(ev)
+ def page(self) -> "WebEnginePage":
+ """Return the page for this view."""
+ maybe_page = super().page()
+ assert maybe_page is not None
+ assert isinstance(maybe_page, WebEnginePage)
+ return maybe_page
+
+ def settings(self) -> "QWebEngineSettings":
+ """Return the settings for this view."""
+ maybe_settings = super().settings()
+ assert maybe_settings is not None
+ return maybe_settings
+
+ def history(self) -> "QWebEngineHistory":
+ """Return the history for this view."""
+ maybe_history = super().history()
+ assert maybe_history is not None
+ return maybe_history
+
def extra_suffixes_workaround(upstream_mimetypes):
"""Return any extra suffixes for mimetypes in upstream_mimetypes.
@@ -294,22 +316,28 @@ class WebEnginePage(QWebEnginePage):
def chooseFiles(
self,
mode: QWebEnginePage.FileSelectionMode,
- old_files: Iterable[str],
- accepted_mimetypes: Iterable[str],
+ old_files: Iterable[Optional[str]],
+ accepted_mimetypes: Iterable[Optional[str]],
) -> List[str]:
"""Override chooseFiles to (optionally) invoke custom file uploader."""
- extra_suffixes = extra_suffixes_workaround(accepted_mimetypes)
+ accepted_mimetypes_filtered = [m for m in accepted_mimetypes if m is not None]
+ old_files_filtered = [f for f in old_files if f is not None]
+ extra_suffixes = extra_suffixes_workaround(accepted_mimetypes_filtered)
if extra_suffixes:
log.webview.debug(
"adding extra suffixes to filepicker: "
- f"before={accepted_mimetypes} "
+ f"before={accepted_mimetypes_filtered} "
f"added={extra_suffixes}",
)
- accepted_mimetypes = list(accepted_mimetypes) + list(extra_suffixes)
+ accepted_mimetypes_filtered = list(
+ accepted_mimetypes_filtered
+ ) + list(extra_suffixes)
handler = config.val.fileselect.handler
if handler == "default":
- return super().chooseFiles(mode, old_files, accepted_mimetypes)
+ return super().chooseFiles(
+ mode, old_files_filtered, accepted_mimetypes_filtered,
+ )
assert handler == "external", handler
try:
qb_mode = _QB_FILESELECTION_MODES[mode]
@@ -317,6 +345,8 @@ class WebEnginePage(QWebEnginePage):
log.webview.warning(
f"Got file selection mode {mode}, but we don't support that!"
)
- return super().chooseFiles(mode, old_files, accepted_mimetypes)
+ return super().chooseFiles(
+ mode, old_files_filtered, accepted_mimetypes_filtered,
+ )
return shared.choose_file(qb_mode=qb_mode)
diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py
index 7ccdabc88..b5b232c5a 100644
--- a/qutebrowser/extensions/loader.py
+++ b/qutebrowser/extensions/loader.py
@@ -6,12 +6,11 @@
import pkgutil
import types
-import sys
import pathlib
import importlib
import argparse
import dataclasses
-from typing import Callable, Iterator, List, Optional, Set, Tuple
+from typing import Callable, Iterator, List, Optional, Tuple
from qutebrowser.qt.core import pyqtSlot
@@ -80,14 +79,6 @@ def load_components(*, skip_hooks: bool = False) -> None:
def walk_components() -> Iterator[ExtensionInfo]:
"""Yield ExtensionInfo objects for all modules."""
- if hasattr(sys, 'frozen'):
- yield from _walk_pyinstaller()
- else:
- yield from _walk_normal()
-
-
-def _walk_normal() -> Iterator[ExtensionInfo]:
- """Walk extensions when not using PyInstaller."""
for _finder, name, ispkg in pkgutil.walk_packages(
path=components.__path__,
prefix=components.__name__ + '.',
@@ -102,23 +93,6 @@ def _walk_normal() -> Iterator[ExtensionInfo]:
yield ExtensionInfo(name=name)
-def _walk_pyinstaller() -> Iterator[ExtensionInfo]:
- """Walk extensions when using PyInstaller.
-
- See https://github.com/pyinstaller/pyinstaller/issues/1905
-
- Inspired by:
- https://github.com/webcomics/dosage/blob/master/dosagelib/loader.py
- """
- toc: Set[str] = set()
- for importer in pkgutil.iter_importers('qutebrowser'):
- if hasattr(importer, 'toc'):
- toc |= importer.toc
- for name in toc:
- if name.startswith(components.__name__ + '.'):
- yield ExtensionInfo(name=name)
-
-
def _get_init_context() -> InitContext:
"""Get an InitContext object."""
return InitContext(data_dir=pathlib.Path(standarddir.data()),
diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py
index 1f5da2dcd..363d5607a 100644
--- a/qutebrowser/utils/qtutils.py
+++ b/qutebrowser/utils/qtutils.py
@@ -18,8 +18,8 @@ import enum
import pathlib
import operator
import contextlib
-from typing import (Any, AnyStr, TYPE_CHECKING, BinaryIO, IO, Iterator,
- Optional, Union, Tuple, Protocol, cast, TypeVar)
+from typing import (Any, TYPE_CHECKING, BinaryIO, IO, Iterator, Literal,
+ Optional, Union, Tuple, Protocol, cast, overload, TypeVar)
from qutebrowser.qt import machinery, sip
from qutebrowser.qt.core import (qVersion, QEventLoop, QDataStream, QByteArray,
@@ -89,8 +89,8 @@ def version_check(version: str,
With `compiled=False` only the runtime Qt version (1) is checked.
You can often run older PyQt versions against newer Qt versions, but you
- won't be able to access any APIs that where only added in the newer Qt
- version. So if you want to check if a new feature if supported, use the
+ won't be able to access any APIs that were only added in the newer Qt
+ version. So if you want to check if a new feature is supported, use the
default behavior. If you just want to check the underlying Qt version,
pass `compiled=False`.
@@ -236,12 +236,32 @@ def deserialize_stream(stream: QDataStream, obj: _QtSerializableType) -> None:
check_qdatastream(stream)
+@overload
+@contextlib.contextmanager
+def savefile_open(
+ filename: str,
+ binary: Literal[False] = ...,
+ encoding: str = 'utf-8'
+) -> Iterator[IO[str]]:
+ ...
+
+
+@overload
+@contextlib.contextmanager
+def savefile_open(
+ filename: str,
+ binary: Literal[True] = ...,
+ encoding: str = 'utf-8'
+) -> Iterator[IO[str]]:
+ ...
+
+
@contextlib.contextmanager
def savefile_open(
filename: str,
binary: bool = False,
encoding: str = 'utf-8'
-) -> Iterator[IO[AnyStr]]:
+) -> Iterator[Union[IO[str], IO[bytes]]]:
"""Context manager to easily use a QSaveFile."""
f = QSaveFile(filename)
cancelled = False
@@ -253,7 +273,7 @@ def savefile_open(
dev = cast(BinaryIO, PyQIODevice(f))
if binary:
- new_f: IO[Any] = dev # FIXME:mypy Why doesn't AnyStr work?
+ new_f: Union[IO[str], IO[bytes]] = dev
else:
new_f = io.TextIOWrapper(dev, encoding=encoding)
diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py
index 75df73ffa..a139d01c5 100644
--- a/qutebrowser/utils/version.py
+++ b/qutebrowser/utils/version.py
@@ -686,7 +686,7 @@ class WebEngineVersions:
return cls._CHROMIUM_VERSIONS.get(minor_version)
@classmethod
- def from_api(cls, qtwe_version: str, chromium_version: str) -> 'WebEngineVersions':
+ def from_api(cls, qtwe_version: str, chromium_version: Optional[str]) -> 'WebEngineVersions':
"""Get the versions based on the exact versions.
This is called if we have proper APIs to get the versions easily
@@ -796,8 +796,10 @@ def qtwebengine_versions(*, avoid_init: bool = False) -> WebEngineVersions:
except ImportError:
pass # Needs QtWebEngine 6.2+ with PyQtWebEngine 6.3.1+
else:
+ qtwe_version = qWebEngineVersion()
+ assert qtwe_version is not None
return WebEngineVersions.from_api(
- qtwe_version=qWebEngineVersion(),
+ qtwe_version=qtwe_version,
chromium_version=qWebEngineChromiumVersion(),
)
diff --git a/requirements.txt b/requirements.txt
index dc07bf531..f1b9a4a2a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,10 +2,10 @@
adblock==0.6.0
colorama==0.4.6
-importlib-resources==6.1.0 ; python_version=="3.8.*"
+importlib-resources==6.1.1 ; python_version=="3.8.*"
Jinja2==3.1.2
MarkupSafe==2.1.3
-Pygments==2.16.1
+Pygments==2.17.1
PyYAML==6.0.1
zipp==3.17.0
# Unpinned due to recompile_requirements.py limitations
diff --git a/scripts/dev/ci/problemmatchers.py b/scripts/dev/ci/problemmatchers.py
index fa623dec7..3316c5597 100644
--- a/scripts/dev/ci/problemmatchers.py
+++ b/scripts/dev/ci/problemmatchers.py
@@ -160,13 +160,17 @@ MATCHERS = {
"tests": [
{
# pytest test summary output
+ # Examples (with ANSI color codes around FAILED|ERROR and the
+ # function name):
+ # FAILED tests/end2end/features/test_keyinput_bdd.py::test_fakekey_sending_special_key_to_the_website - end2end.fixtures.testprocess.WaitForTimeout: Timed out after 15000ms waiting for {'category': 'js', 'message': '[*] key press: 27'}.
+ # ERROR tests/end2end/test_insert_mode.py::test_insert_mode[100-textarea.html-qute-textarea-clipboard-qutebrowser] - Failed: Logged unexpected errors:
"severity": "error",
"pattern": [
{
- "regexp": r'^=+ short test summary info =+$',
+ "regexp": r'^.*=== short test summary info ===.*$',
},
{
- "regexp": r"^((ERROR|FAILED) .*)",
+ "regexp": r"^[^ ]*((ERROR|FAILED)[^ ]* .*)$",
"message": 1,
"loop": True,
}
diff --git a/tests/end2end/fixtures/quteprocess.py b/tests/end2end/fixtures/quteprocess.py
index a2f870e32..de9b490ca 100644
--- a/tests/end2end/fixtures/quteprocess.py
+++ b/tests/end2end/fixtures/quteprocess.py
@@ -390,7 +390,8 @@ class QuteProc(testprocess.Process):
'--json-logging', '--loglevel', 'vdebug',
'--backend', backend, '--debug-flag', 'no-sql-history',
'--debug-flag', 'werror', '--debug-flag',
- 'test-notification-service']
+ 'test-notification-service',
+ '--qt-flag', 'disable-features=PaintHoldingCrossOrigin']
if self.request.config.webengine and testutils.disable_seccomp_bpf_sandbox():
args += testutils.DISABLE_SECCOMP_BPF_ARGS
diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py
index af81781f6..72e08af96 100644
--- a/tests/end2end/test_invocations.py
+++ b/tests/end2end/test_invocations.py
@@ -15,6 +15,7 @@ import re
import json
import platform
from contextlib import nullcontext as does_not_raise
+from unittest.mock import ANY
import pytest
from qutebrowser.qt.core import QProcess, QPoint
@@ -885,27 +886,78 @@ def test_sandboxing(
bpf_text = "Seccomp-BPF sandbox"
yama_text = "Ptrace Protection with Yama LSM"
- header, *lines, empty, result = text.split("\n")
- assert not empty
+ if not utils.is_windows:
+ header, *lines, empty, result = text.split("\n")
+ assert not empty
- expected_status = {
- "Layer 1 Sandbox": "Namespace" if has_namespaces else "None",
+ expected_status = {
+ "Layer 1 Sandbox": "Namespace" if has_namespaces else "None",
- "PID namespaces": "Yes" if has_namespaces else "No",
- "Network namespaces": "Yes" if has_namespaces else "No",
+ "PID namespaces": "Yes" if has_namespaces else "No",
+ "Network namespaces": "Yes" if has_namespaces else "No",
- bpf_text: "Yes" if has_seccomp else "No",
- f"{bpf_text} supports TSYNC": "Yes" if has_seccomp else "No",
+ bpf_text: "Yes" if has_seccomp else "No",
+ f"{bpf_text} supports TSYNC": "Yes" if has_seccomp else "No",
- f"{yama_text} (Broker)": "Yes" if has_yama else "No",
- f"{yama_text} (Non-broker)": "Yes" if has_yama_non_broker else "No",
- }
-
- assert header == "Sandbox Status"
- assert result == expected_result
+ f"{yama_text} (Broker)": "Yes" if has_yama else "No",
+ f"{yama_text} (Non-broker)": "Yes" if has_yama_non_broker else "No",
+ }
- status = dict(line.split("\t") for line in lines)
- assert status == expected_status
+ assert header == "Sandbox Status"
+ assert result == expected_result
+
+ status = dict(line.split("\t") for line in lines)
+ assert status == expected_status
+
+ else: # utils.is_windows
+ # The sandbox page on Windows if different that Linux and macOS. It's
+ # a lot more complex. There is a table up top with lots of columns and
+ # a row per tab and helper process then a json object per row down
+ # below with even more detail (which we ignore).
+ # https://www.chromium.org/Home/chromium-security/articles/chrome-sandbox-diagnostics-for-windows/
+
+ # We're not getting full coverage of the table and there doesn't seem
+ # to be a simple summary like for linux. The "Sandbox" and "Lockdown"
+ # column are probably the key ones.
+ # We are looking at all the rows in the table for the sake of
+ # completeness, but I expect there will always be just one row with a
+ # renderer process in it for this test. If other helper processes pop
+ # up we might want to exclude them.
+ lines = text.split("\n")
+ assert lines.pop(0) == "Sandbox Status"
+ header = lines.pop(0).split("\t")
+ rows = []
+ current_line = lines.pop(0)
+ while current_line.strip():
+ if lines[0].startswith("\t"):
+ # Continuation line. Not sure how to 100% identify them
+ # but new rows should start with a process ID.
+ current_line += lines.pop(0)
+ continue
+
+ columns = current_line.split("\t")
+ assert len(header) == len(columns)
+ rows.append(dict(zip(header, columns)))
+ current_line = lines.pop(0)
+
+ assert rows
+
+ # I'm using has_namespaces as a proxy for "should be sandboxed" here,
+ # which is a bit lazy but its either that or match on the text
+ # "sandboxing" arg. The seccomp-bpf arg does nothing on windows, so
+ # we only have the off and on states.
+ for row in rows:
+ assert row == {
+ "Process": ANY,
+ "Type": "Renderer",
+ "Name": "",
+ "Sandbox": "Renderer" if has_namespaces else "Not Sandboxed",
+ "Lockdown": "Lockdown" if has_namespaces else "",
+ "Integrity": ANY if has_namespaces else "",
+ "Mitigations": ANY if has_namespaces else "",
+ "Component Filter": ANY if has_namespaces else "",
+ "Lowbox/AppContainer": "",
+ }
@pytest.mark.not_frozen
diff --git a/tests/unit/extensions/test_loader.py b/tests/unit/extensions/test_loader.py
index fd15130ba..a2a99f305 100644
--- a/tests/unit/extensions/test_loader.py
+++ b/tests/unit/extensions/test_loader.py
@@ -20,16 +20,10 @@ def test_on_walk_error():
def test_walk_normal():
- names = [info.name for info in loader._walk_normal()]
+ names = [info.name for info in loader.walk_components()]
assert 'qutebrowser.components.scrollcommands' in names
-def test_walk_pyinstaller():
- # We can't test whether we get something back without being frozen by
- # PyInstaller, but at least we can test that we don't crash.
- list(loader._walk_pyinstaller())
-
-
def test_load_component(monkeypatch):
monkeypatch.setattr(objects, 'commands', {})
diff --git a/tox.ini b/tox.ini
index 87decce12..238c532f3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -51,8 +51,9 @@ deps =
pyqt63: -r{toxinidir}/misc/requirements/requirements-pyqt-6.3.txt
pyqt64: -r{toxinidir}/misc/requirements/requirements-pyqt-6.4.txt
pyqt65: -r{toxinidir}/misc/requirements/requirements-pyqt-6.5.txt
+ pyqt66: -r{toxinidir}/misc/requirements/requirements-pyqt-6.6.txt
commands =
- !pyqt-!pyqt515-!pyqt5152-!pyqt62-!pyqt63-!pyqt64-!pyqt65: {envpython} scripts/link_pyqt.py --tox {envdir}
+ !pyqt-!pyqt515-!pyqt5152-!pyqt62-!pyqt63-!pyqt64-!pyqt65-!pyqt66: {envpython} scripts/link_pyqt.py --tox {envdir}
{envpython} -bb -m pytest {posargs:tests}
cov: {envpython} scripts/dev/check_coverage.py {posargs}
@@ -191,7 +192,6 @@ passenv =
APPDATA
HOME
PYINSTALLER_DEBUG
- PYINSTALLER_COMPILE_BOOTLOADER
setenv =
qt5: PYINSTALLER_QT5=true
deps =
@@ -281,7 +281,6 @@ passenv = *
# Override default PyQt6 from [testenv]
setenv =
qt5: QUTE_QT_WRAPPER=PyQt5
- PYINSTALLER_COMPILE_BOOTLOADER=true
usedevelop = true
deps =
-r{toxinidir}/requirements.txt