Merge remote-tracking branch 'upstream/main' into tree-tabs-integration
This commit is contained in:
commit
9bf2bae60f
2
.flake8
2
.flake8
|
|
@ -70,6 +70,4 @@ per-file-ignores =
|
|||
copyright-check = True
|
||||
copyright-regexp = # Copyright [\d-]+ .*
|
||||
copyright-min-file-size = 110
|
||||
pytest-fixture-no-parentheses = True
|
||||
pytest-mark-no-parentheses = True
|
||||
pytest-parametrize-names-type = csv
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.mypy_cache
|
||||
|
|
@ -56,7 +56,7 @@ jobs:
|
|||
run: "python scripts/dev/ci/problemmatchers.py ${{ matrix.testenv }} ${{ runner.temp }}"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
[[ ${{ matrix.testenv }} == eslint ]] && npm install -g eslint
|
||||
[[ ${{ matrix.testenv }} == eslint ]] && npm install -g 'eslint@<9.0.0'
|
||||
[[ ${{ 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
|
||||
|
|
@ -184,7 +184,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.mypy_cache
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ jobs:
|
|||
if: "github.repository == 'qutebrowser/qutebrowser'"
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image:
|
||||
- archlinux-webkit
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@ jobs:
|
|||
- name: Patch qutebrowser for debugging
|
||||
if: "contains(matrix.args, '--debug')"
|
||||
run: |
|
||||
sed -i '' '/.-d., .--debug.,/s/$/ default=True,/' qutebrowser/qutebrowser.py
|
||||
sed '/.-d., .--debug.,/s/$/ default=True,/' qutebrowser/qutebrowser.py > qutebrowser/qutebrowser.py.tmp
|
||||
cp qutebrowser/qutebrowser.py.tmp qutebrowser/qutebrowser.py
|
||||
rm qutebrowser/qutebrowser.py.tmp
|
||||
- name: Run tox
|
||||
run: "tox -e ${{ matrix.toxenv }} -- --gh-token ${{ secrets.GITHUB_TOKEN }} ${{ matrix.args }}"
|
||||
- name: Gather info
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ jobs:
|
|||
- name: Run qutebrowser smoke test
|
||||
run: "xvfb-run .venv/bin/python3 -m qutebrowser --no-err-windows --nowindow --temp-basedir about:blank ':later 500 quit'"
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
committer: qutebrowser bot <bot@qutebrowser.org>
|
||||
author: qutebrowser bot <bot@qutebrowser.org>
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ jobs:
|
|||
git push --set-upstream origin v${{ steps.bump.outputs.version_x }}
|
||||
- name: Create GitHub draft release
|
||||
id: create-release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{ steps.bump.outputs.version }}
|
||||
draft: true
|
||||
|
|
|
|||
|
|
@ -22,13 +22,15 @@ disallow_any_unimported = True
|
|||
enable_error_code = ignore-without-code
|
||||
|
||||
### Output
|
||||
show_error_codes = True
|
||||
show_error_context = True
|
||||
pretty = True
|
||||
|
||||
### FIXME:v4 get rid of this
|
||||
no_implicit_optional = False
|
||||
|
||||
### Future default behavior
|
||||
local_partial_types = True
|
||||
|
||||
[mypy-hunter]
|
||||
# https://github.com/ionelmc/python-hunter/issues/43
|
||||
ignore_missing_imports = True
|
||||
|
|
|
|||
|
|
@ -19,12 +19,34 @@ breaking changes (such as renamed commands) can happen in minor releases.
|
|||
v3.2.0 (unreleased)
|
||||
-------------------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- When qutebrowser receives a SIGHUP it will now reload any config.py file
|
||||
in use (same as the `:config-source` command does). (#8108)
|
||||
- The Chromium security patch version is now shown in the backend string in
|
||||
--version and :version. This reflects the latest Chromium version that
|
||||
security fixes have been backported to the base QtWebEngine version from.
|
||||
(#7187)
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- A few more completions will now match search terms in any order:
|
||||
`:quickmark-*`, `:bookmark-*`, `:tab-take` and `:tab-select` (for the quick
|
||||
and bookmark categories). (#7955)
|
||||
- Elements with an ARIA `role="switch"` now get hints (toggle switches like
|
||||
e.g. on cookie banners).
|
||||
- The `tor_identity` userscript now validates that the -c|--control-port
|
||||
argument value is an int. (#8162)
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- `input.insert_mode.auto_load` sometimes not triggering due to a race
|
||||
condition.
|
||||
- Worked around qutebrowser quitting when closing a KDE file dialog due to a Qt
|
||||
bug.
|
||||
|
||||
[[v3.1.1]]
|
||||
v3.1.1 (unreleased)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@
|
|||
|<<colors.tooltip.bg,colors.tooltip.bg>>|Background color of tooltips.
|
||||
|<<colors.tooltip.fg,colors.tooltip.fg>>|Foreground color of tooltips.
|
||||
|<<colors.webpage.bg,colors.webpage.bg>>|Background color for webpages if unset (or empty to use the theme's color).
|
||||
|<<colors.webpage.darkmode.algorithm,colors.webpage.darkmode.algorithm>>|Which algorithm to use for modifying how colors are rendered with darkmode.
|
||||
|<<colors.webpage.darkmode.algorithm,colors.webpage.darkmode.algorithm>>|Which algorithm to use for modifying how colors are rendered with dark mode.
|
||||
|<<colors.webpage.darkmode.contrast,colors.webpage.darkmode.contrast>>|Contrast for dark mode.
|
||||
|<<colors.webpage.darkmode.enabled,colors.webpage.darkmode.enabled>>|Render all web contents using a dark theme.
|
||||
|<<colors.webpage.darkmode.policy.images,colors.webpage.darkmode.policy.images>>|Which images to apply dark mode to.
|
||||
|
|
@ -1662,7 +1662,7 @@ Default: +pass:[white]+
|
|||
|
||||
[[colors.webpage.darkmode.algorithm]]
|
||||
=== colors.webpage.darkmode.algorithm
|
||||
Which algorithm to use for modifying how colors are rendered with darkmode.
|
||||
Which algorithm to use for modifying how colors are rendered with dark mode.
|
||||
The `lightness-cielab` value was added with QtWebEngine 5.14 and is treated like `lightness-hsl` with older QtWebEngine versions.
|
||||
|
||||
This setting requires a restart.
|
||||
|
|
@ -3493,6 +3493,7 @@ Default:
|
|||
* +pass:[[role="button"\]]+
|
||||
* +pass:[[role="tab"\]]+
|
||||
* +pass:[[role="checkbox"\]]+
|
||||
* +pass:[[role="switch"\]]+
|
||||
* +pass:[[role="menuitem"\]]+
|
||||
* +pass:[[role="menuitemcheckbox"\]]+
|
||||
* +pass:[[role="menuitemradio"\]]+
|
||||
|
|
|
|||
|
|
@ -280,14 +280,14 @@ track down issues.
|
|||
NOTE: Due to GitHub limitations, you need to be signed in with a GitHub account
|
||||
to download the files.
|
||||
|
||||
https://chocolatey.org/packages/qutebrowser[Chocolatey package]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Package managers
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
* PackageManagement PowerShell module
|
||||
----
|
||||
PS C:\> Install-Package qutebrowser
|
||||
----
|
||||
* Chocolatey's client
|
||||
* https://chocolatey.org/packages/qutebrowser[Chocolatey package] with `choco`:
|
||||
----
|
||||
C:\> choco install qutebrowser
|
||||
----
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
build==1.0.3
|
||||
build==1.2.1
|
||||
check-manifest==0.49
|
||||
importlib-metadata==7.0.1
|
||||
packaging==23.2
|
||||
importlib_metadata==7.1.0
|
||||
packaging==24.0
|
||||
pyproject_hooks==1.0.0
|
||||
tomli==2.0.1
|
||||
zipp==3.17.0
|
||||
zipp==3.18.1
|
||||
|
|
|
|||
|
|
@ -1,45 +1,48 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
build==1.0.3
|
||||
backports.tarfile==1.0.0
|
||||
build==1.2.1
|
||||
bump2version==1.0.1
|
||||
certifi==2023.11.17
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
cryptography==41.0.7
|
||||
cryptography==42.0.5
|
||||
docutils==0.20.1
|
||||
github3.py==4.0.1
|
||||
hunter==3.6.1
|
||||
idna==3.6
|
||||
importlib-metadata==7.0.1
|
||||
importlib-resources==6.1.1
|
||||
jaraco.classes==3.3.0
|
||||
idna==3.7
|
||||
importlib_metadata==7.1.0
|
||||
importlib_resources==6.4.0
|
||||
jaraco.classes==3.4.0
|
||||
jaraco.context==5.3.0
|
||||
jaraco.functools==4.0.0
|
||||
jeepney==0.8.0
|
||||
keyring==24.3.0
|
||||
keyring==25.1.0
|
||||
manhole==1.8.0
|
||||
markdown-it-py==3.0.0
|
||||
mdurl==0.1.2
|
||||
more-itertools==10.1.0
|
||||
nh3==0.2.15
|
||||
packaging==23.2
|
||||
pkginfo==1.9.6
|
||||
pycparser==2.21
|
||||
more-itertools==10.2.0
|
||||
nh3==0.2.17
|
||||
packaging==24.0
|
||||
pkginfo==1.10.0
|
||||
pycparser==2.22
|
||||
Pygments==2.17.2
|
||||
PyJWT==2.8.0
|
||||
Pympler==1.0.1
|
||||
pyproject_hooks==1.0.0
|
||||
PyQt-builder==1.15.4
|
||||
python-dateutil==2.8.2
|
||||
readme-renderer==42.0
|
||||
PyQt-builder==1.16.0
|
||||
python-dateutil==2.9.0.post0
|
||||
readme_renderer==43.0
|
||||
requests==2.31.0
|
||||
requests-toolbelt==1.0.0
|
||||
rfc3986==2.0.0
|
||||
rich==13.7.0
|
||||
rich==13.7.1
|
||||
SecretStorage==3.3.3
|
||||
sip==6.8.1
|
||||
sip==6.8.3
|
||||
six==1.16.0
|
||||
tomli==2.0.1
|
||||
twine==4.0.2
|
||||
typing_extensions==4.9.0
|
||||
twine==5.0.0
|
||||
typing_extensions==4.11.0
|
||||
uritemplate==4.1.1
|
||||
# urllib3==2.1.0
|
||||
zipp==3.17.0
|
||||
# urllib3==2.2.1
|
||||
zipp==3.18.1
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
attrs==23.2.0
|
||||
flake8==7.0.0
|
||||
flake8-bugbear==23.12.2
|
||||
flake8-builtins==2.2.0
|
||||
flake8-bugbear==24.2.6
|
||||
flake8-builtins==2.5.0
|
||||
flake8-comprehensions==3.14.0
|
||||
flake8-debugger==4.1.2
|
||||
flake8-deprecated==2.2.1
|
||||
flake8-docstrings==1.7.0
|
||||
flake8-future-import==0.4.7
|
||||
flake8-plugin-utils==1.3.3
|
||||
flake8-pytest-style==1.7.2
|
||||
flake8-pytest-style==2.0.0
|
||||
flake8-string-format==0.3.0
|
||||
flake8-tidy-imports==4.10.0
|
||||
flake8-tuple==0.4.1
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
chardet==5.2.0
|
||||
diff_cover==8.0.2
|
||||
importlib-resources==6.1.1
|
||||
Jinja2==3.1.2
|
||||
lxml==5.0.1
|
||||
MarkupSafe==2.1.3
|
||||
mypy==1.8.0
|
||||
diff_cover==9.0.0
|
||||
importlib_resources==6.4.0
|
||||
Jinja2==3.1.3
|
||||
lxml==5.2.1
|
||||
MarkupSafe==2.1.5
|
||||
mypy==1.9.0
|
||||
mypy-extensions==1.0.0
|
||||
pluggy==1.3.0
|
||||
pluggy==1.4.0
|
||||
Pygments==2.17.2
|
||||
PyQt5-stubs==5.15.6.0
|
||||
tomli==2.0.1
|
||||
types-colorama==0.4.15.20240106
|
||||
types-docutils==0.20.0.20240106
|
||||
types-Pygments==2.17.0.20240106
|
||||
types-PyYAML==6.0.12.12
|
||||
types-setuptools==69.0.0.20240106
|
||||
typing_extensions==4.9.0
|
||||
zipp==3.17.0
|
||||
types-colorama==0.4.15.20240311
|
||||
types-docutils==0.20.0.20240406
|
||||
types-Pygments==2.17.0.20240310
|
||||
types-PyYAML==6.0.12.20240311
|
||||
types-setuptools==69.5.0.20240415
|
||||
typing_extensions==4.11.0
|
||||
zipp==3.18.1
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
altgraph==0.17.4
|
||||
importlib-metadata==7.0.1
|
||||
packaging==23.2
|
||||
pyinstaller==6.3.0
|
||||
pyinstaller-hooks-contrib==2023.12
|
||||
zipp==3.17.0
|
||||
importlib_metadata==7.1.0
|
||||
packaging==24.0
|
||||
pyinstaller==6.6.0
|
||||
pyinstaller-hooks-contrib==2024.4
|
||||
zipp==3.18.1
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
astroid==3.0.2
|
||||
certifi==2023.11.17
|
||||
astroid==3.1.0
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
cryptography==41.0.7
|
||||
dill==0.3.7
|
||||
cryptography==42.0.5
|
||||
dill==0.3.8
|
||||
github3.py==4.0.1
|
||||
idna==3.6
|
||||
idna==3.7
|
||||
isort==5.13.2
|
||||
mccabe==0.7.0
|
||||
pefile==2023.2.7
|
||||
platformdirs==4.1.0
|
||||
pycparser==2.21
|
||||
platformdirs==4.2.0
|
||||
pycparser==2.22
|
||||
PyJWT==2.8.0
|
||||
pylint==3.0.3
|
||||
python-dateutil==2.8.2
|
||||
pylint==3.1.0
|
||||
python-dateutil==2.9.0.post0
|
||||
./scripts/dev/pylint_checkers
|
||||
requests==2.31.0
|
||||
six==1.16.0
|
||||
tomli==2.0.1
|
||||
tomlkit==0.12.3
|
||||
typing_extensions==4.9.0
|
||||
tomlkit==0.12.4
|
||||
typing_extensions==4.11.0
|
||||
uritemplate==4.1.1
|
||||
# urllib3==2.1.0
|
||||
# urllib3==2.2.1
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.6.1
|
||||
PyQt6-Qt6==6.6.1
|
||||
PyQt6-Qt6==6.6.3
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.6.0
|
||||
PyQt6-WebEngine-Qt6==6.6.1
|
||||
PyQt6-WebEngine-Qt6==6.6.3
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.6.1
|
||||
PyQt6-Qt6==6.6.1
|
||||
PyQt6-Qt6==6.6.3
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.6.0
|
||||
PyQt6-WebEngine-Qt6==6.6.1
|
||||
PyQt6-WebEngine-Qt6==6.6.3
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.6.1
|
||||
PyQt6-Qt6==6.6.1
|
||||
PyQt6-Qt6==6.6.3
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.6.0
|
||||
PyQt6-WebEngine-Qt6==6.6.1
|
||||
PyQt6-WebEngine-Qt6==6.6.3
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
build==1.0.3
|
||||
certifi==2023.11.17
|
||||
build==1.2.1
|
||||
certifi==2024.2.2
|
||||
charset-normalizer==3.3.2
|
||||
docutils==0.20.1
|
||||
idna==3.6
|
||||
importlib-metadata==7.0.1
|
||||
packaging==23.2
|
||||
idna==3.7
|
||||
importlib_metadata==7.1.0
|
||||
packaging==24.0
|
||||
Pygments==2.17.2
|
||||
pyproject_hooks==1.0.0
|
||||
pyroma==4.2
|
||||
requests==2.31.0
|
||||
tomli==2.0.1
|
||||
trove-classifiers==2023.11.29
|
||||
urllib3==2.1.0
|
||||
zipp==3.17.0
|
||||
trove-classifiers==2024.4.10
|
||||
urllib3==2.2.1
|
||||
zipp==3.18.1
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ PyYAML
|
|||
#@ add: pyobjc-framework-Cocoa ; sys_platform=="darwin"
|
||||
|
||||
## stdlib backports
|
||||
importlib-resources
|
||||
importlib_resources
|
||||
|
||||
## Optional dependencies
|
||||
Pygments # For :view-source --pygments or on QtWebKit
|
||||
colorama # Colored log output on Windows
|
||||
adblock # Improved adblocking
|
||||
|
||||
#@ markers: importlib-resources python_version=="3.8.*"
|
||||
#@ markers: importlib_resources python_version=="3.8.*"
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
alabaster==0.7.13
|
||||
Babel==2.14.0
|
||||
certifi==2023.11.17
|
||||
certifi==2024.2.2
|
||||
charset-normalizer==3.3.2
|
||||
docutils==0.20.1
|
||||
idna==3.6
|
||||
idna==3.7
|
||||
imagesize==1.4.1
|
||||
importlib-metadata==7.0.1
|
||||
Jinja2==3.1.2
|
||||
MarkupSafe==2.1.3
|
||||
packaging==23.2
|
||||
importlib_metadata==7.1.0
|
||||
Jinja2==3.1.3
|
||||
MarkupSafe==2.1.5
|
||||
packaging==24.0
|
||||
Pygments==2.17.2
|
||||
pytz==2023.3.post1
|
||||
pytz==2024.1
|
||||
requests==2.31.0
|
||||
snowballstemmer==2.2.0
|
||||
Sphinx==7.1.2
|
||||
|
|
@ -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.1.0
|
||||
zipp==3.17.0
|
||||
urllib3==2.2.1
|
||||
zipp==3.18.1
|
||||
|
|
|
|||
|
|
@ -1,57 +1,56 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
attrs==23.2.0
|
||||
beautifulsoup4==4.12.2
|
||||
beautifulsoup4==4.12.3
|
||||
blinker==1.7.0
|
||||
certifi==2023.11.17
|
||||
certifi==2024.2.2
|
||||
charset-normalizer==3.3.2
|
||||
cheroot==10.0.0
|
||||
click==8.1.7
|
||||
coverage==7.4.0
|
||||
coverage==7.4.4
|
||||
exceptiongroup==1.2.0
|
||||
execnet==2.0.2
|
||||
filelock==3.13.1
|
||||
Flask==3.0.0
|
||||
execnet==2.1.1
|
||||
filelock==3.13.4
|
||||
Flask==3.0.3
|
||||
hunter==3.6.1
|
||||
hypothesis==6.92.3
|
||||
idna==3.6
|
||||
importlib-metadata==7.0.1
|
||||
hypothesis==6.100.1
|
||||
idna==3.7
|
||||
importlib_metadata==7.1.0
|
||||
iniconfig==2.0.0
|
||||
itsdangerous==2.1.2
|
||||
jaraco.functools==4.0.0
|
||||
# Jinja2==3.1.2
|
||||
Mako==1.3.0
|
||||
# Jinja2==3.1.3
|
||||
Mako==1.3.3
|
||||
manhole==1.8.0
|
||||
# MarkupSafe==2.1.3
|
||||
more-itertools==10.1.0
|
||||
packaging==23.2
|
||||
parse==1.20.0
|
||||
# MarkupSafe==2.1.5
|
||||
more-itertools==10.2.0
|
||||
packaging==24.0
|
||||
parse==1.20.1
|
||||
parse-type==0.6.2
|
||||
pluggy==1.3.0
|
||||
pluggy==1.4.0
|
||||
py-cpuinfo==9.0.0
|
||||
Pygments==2.17.2
|
||||
pytest==7.4.4
|
||||
pytest-bdd==7.0.1
|
||||
pytest==8.1.1
|
||||
pytest-bdd==7.1.2
|
||||
pytest-benchmark==4.0.0
|
||||
pytest-cov==4.1.0
|
||||
pytest-cov==5.0.0
|
||||
pytest-instafail==0.5.0
|
||||
pytest-mock==3.12.0
|
||||
pytest-qt==4.3.1
|
||||
pytest-mock==3.14.0
|
||||
pytest-qt==4.4.0
|
||||
pytest-repeat==0.9.3
|
||||
pytest-rerunfailures==13.0
|
||||
pytest-rerunfailures==14.0
|
||||
pytest-xdist==3.5.0
|
||||
pytest-xvfb==3.0.0
|
||||
PyVirtualDisplay==3.0
|
||||
requests==2.31.0
|
||||
requests-file==1.5.1
|
||||
requests-file==2.0.0
|
||||
six==1.16.0
|
||||
sortedcontainers==2.4.0
|
||||
soupsieve==2.5
|
||||
tldextract==5.1.1
|
||||
toml==0.10.2
|
||||
tldextract==5.1.2
|
||||
tomli==2.0.1
|
||||
typing_extensions==4.9.0
|
||||
urllib3==2.1.0
|
||||
vulture==2.10
|
||||
Werkzeug==3.0.1
|
||||
zipp==3.17.0
|
||||
typing_extensions==4.11.0
|
||||
urllib3==2.2.1
|
||||
vulture==2.11
|
||||
Werkzeug==3.0.2
|
||||
zipp==3.18.1
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
cachetools==5.3.2
|
||||
cachetools==5.3.3
|
||||
chardet==5.2.0
|
||||
colorama==0.4.6
|
||||
distlib==0.3.8
|
||||
filelock==3.13.1
|
||||
packaging==23.2
|
||||
pip==23.3.2
|
||||
platformdirs==4.1.0
|
||||
pluggy==1.3.0
|
||||
filelock==3.13.4
|
||||
packaging==24.0
|
||||
pip==24.0
|
||||
platformdirs==4.2.0
|
||||
pluggy==1.4.0
|
||||
pyproject-api==1.6.1
|
||||
setuptools==69.0.3
|
||||
setuptools==69.5.1
|
||||
tomli==2.0.1
|
||||
tox==4.11.4
|
||||
virtualenv==20.25.0
|
||||
wheel==0.42.0
|
||||
tox==4.14.2
|
||||
virtualenv==20.25.1
|
||||
wheel==0.43.0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
toml==0.10.2
|
||||
vulture==2.10
|
||||
tomli==2.0.1
|
||||
vulture==2.11
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
pathspec==0.12.1
|
||||
PyYAML==6.0.1
|
||||
yamllint==1.33.0
|
||||
yamllint==1.35.1
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ except ImportError:
|
|||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser(prog='tor_identity')
|
||||
parser.add_argument('-c', '--control-port', default=9051,
|
||||
parser.add_argument('-c', '--control-port', type=int, default=9051,
|
||||
help='Tor control port (default 9051).')
|
||||
parser.add_argument('-p', '--password', type=str, default=None,
|
||||
help='Tor control port password.')
|
||||
|
|
|
|||
|
|
@ -61,6 +61,15 @@ qt_log_ignore =
|
|||
^QBackingStore::endPaint\(\) called with active painter; did you forget to destroy it or call QPainter::end\(\) on it\?$
|
||||
# Qt 6.5 after system update, from qt-qt.accessibility.atspi
|
||||
Error in contacting registry: "org\.freedesktop\.DBus\.Error\.Disconnected" "Not connected to D-Bus server"
|
||||
# Seen in Qt 6.6.2 on CI, https://github.com/qutebrowser/qutebrowser/pull/8106#issuecomment-1952320663
|
||||
^QDBusConnection: couldn't handle call to Notify, no slot matched
|
||||
^QDBusConnection: couldn't handle call to CloseNotification, no slot matched
|
||||
# Qt 6.7
|
||||
^Path override failed for key base::DIR_APP_DICTIONARIES and path '.*/qtwebengine_dictionaries'
|
||||
# Sometime the above message gets printed twice at the same time and the messages get interleaved.
|
||||
# The last part of the outer message gets bumped down to a line on its own, so hopefully this
|
||||
# catches that. And we don't see any other weird permutations of this.
|
||||
^[^ ]*qtwebengine_dictionaries'$
|
||||
xfail_strict = true
|
||||
filterwarnings =
|
||||
error
|
||||
|
|
|
|||
|
|
@ -132,6 +132,9 @@ def init(*, args: argparse.Namespace) -> None:
|
|||
crashsignal.crash_handler.init_faulthandler()
|
||||
|
||||
objects.qapp.setQuitOnLastWindowClosed(False)
|
||||
# WORKAROUND for KDE file dialogs / QEventLoopLocker quitting:
|
||||
# https://bugreports.qt.io/browse/QTBUG-124386
|
||||
objects.qapp.setQuitLockEnabled(False)
|
||||
quitter.instance.shutting_down.connect(QApplication.closeAllWindows)
|
||||
|
||||
_init_icon()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from typing import (cast, TYPE_CHECKING, Any, Callable, Iterable, List, Optional
|
|||
|
||||
from qutebrowser.qt import machinery
|
||||
from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt,
|
||||
QEvent, QPoint, QRect)
|
||||
QEvent, QPoint, QRect, QTimer)
|
||||
from qutebrowser.qt.gui import QKeyEvent, QIcon, QPixmap
|
||||
from qutebrowser.qt.widgets import QApplication, QWidget
|
||||
from qutebrowser.qt.printsupport import QPrintDialog, QPrinter
|
||||
|
|
@ -904,7 +904,13 @@ class AbstractTabPrivate:
|
|||
modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
|
||||
'load finished', only_if_normal=True)
|
||||
|
||||
self._tab.elements.find_focused(_auto_insert_mode_cb)
|
||||
# There seems to be a race between loadFinished being called,
|
||||
# and the autoload attribute on websites actually focusing anything.
|
||||
# Thus, we delay this by a bit. Locally, a delay of 13ms caused no races
|
||||
# with 5000 test reruns (even with simultaneous CPU stress testing),
|
||||
# so 65ms should be a safe bet and still not be too noticeable.
|
||||
QTimer.singleShot(
|
||||
65, lambda: self._tab.elements.find_focused(_auto_insert_mode_cb))
|
||||
|
||||
def clear_ssl_errors(self) -> None:
|
||||
raise NotImplementedError
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
"""Handling of proxies."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from qutebrowser.qt.core import QUrl, pyqtSlot
|
||||
from qutebrowser.qt.network import QNetworkProxy, QNetworkProxyFactory
|
||||
|
||||
|
|
@ -13,7 +15,7 @@ from qutebrowser.misc import objects
|
|||
from qutebrowser.browser.network import pac
|
||||
|
||||
|
||||
application_factory = None
|
||||
application_factory: Optional["ProxyFactory"] = None
|
||||
|
||||
|
||||
def init():
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from qutebrowser.config import config, websettings
|
|||
from qutebrowser.utils import message, usertypes, log, urlutils, utils, debug, objreg, qtlog
|
||||
from qutebrowser.misc import quitter
|
||||
from qutebrowser.browser import downloads
|
||||
from qutebrowser.browser.webkit import http
|
||||
from qutebrowser.browser.webkit import httpheaders
|
||||
from qutebrowser.browser.webkit.network import networkmanager
|
||||
|
||||
|
||||
|
|
@ -533,7 +533,7 @@ class DownloadManager(downloads.AbstractDownloadManager):
|
|||
try:
|
||||
suggested_filename = target.suggested_filename()
|
||||
except downloads.NoFilenameError:
|
||||
_, suggested_filename = http.parse_content_disposition(reply)
|
||||
_, suggested_filename = httpheaders.parse_content_disposition(reply)
|
||||
log.downloads.debug("fetch: {} -> {}".format(reply.url(),
|
||||
suggested_filename))
|
||||
download = DownloadItem(reply, manager=self)
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ from qutebrowser.qt import sip
|
|||
|
||||
|
||||
pyeval_output = ":pyeval was never called"
|
||||
csrf_token = None
|
||||
csrf_token: Optional[str] = None
|
||||
|
||||
|
||||
_HANDLERS = {}
|
||||
_HANDLERS: Dict[str, "_HandlerCallable"] = {}
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ private_profile: Optional[QWebEngineProfile] = None
|
|||
# The global WebEngineSettings object
|
||||
_global_settings = cast('WebEngineSettings', None)
|
||||
|
||||
parsed_user_agent = None
|
||||
parsed_user_agent: Optional[websettings.UserAgent] = None
|
||||
|
||||
_qute_scheme_handler = cast(webenginequtescheme.QuteSchemeHandler, None)
|
||||
_req_interceptor = cast('interceptor.RequestInterceptor', None)
|
||||
|
|
|
|||
|
|
@ -292,6 +292,8 @@ class WebEngineCaret(browsertab.AbstractCaret):
|
|||
flags = set()
|
||||
if utils.is_windows:
|
||||
flags.add('windows')
|
||||
if 'caret' in objects.debug_flags:
|
||||
flags.add('debug')
|
||||
return list(flags)
|
||||
|
||||
@pyqtSlot(usertypes.KeyMode)
|
||||
|
|
|
|||
|
|
@ -238,9 +238,7 @@ class WebEnginePage(QWebEnginePage):
|
|||
self._set_bg_color()
|
||||
config.instance.changed.connect(self._set_bg_color)
|
||||
if machinery.IS_QT6:
|
||||
self.certificateError.connect( # pylint: disable=no-member
|
||||
self._handle_certificate_error
|
||||
)
|
||||
self.certificateError.connect(self._handle_certificate_error)
|
||||
# Qt 5: Overridden method instead of signal
|
||||
|
||||
@config.change_filter('colors.webpage.bg')
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from qutebrowser.qt.webkitwidgets import QWebPage, QWebFrame
|
|||
|
||||
from qutebrowser.config import websettings, config
|
||||
from qutebrowser.browser import pdfjs, shared, downloads, greasemonkey
|
||||
from qutebrowser.browser.webkit import http
|
||||
from qutebrowser.browser.webkit import httpheaders
|
||||
from qutebrowser.browser.webkit.network import networkmanager
|
||||
from qutebrowser.utils import message, usertypes, log, jinja, objreg
|
||||
from qutebrowser.qt import sip
|
||||
|
|
@ -263,14 +263,14 @@ class BrowserPage(QWebPage):
|
|||
At some point we might want to implement the MIME Sniffing standard
|
||||
here: https://mimesniff.spec.whatwg.org/
|
||||
"""
|
||||
inline, suggested_filename = http.parse_content_disposition(reply)
|
||||
inline, suggested_filename = httpheaders.parse_content_disposition(reply)
|
||||
download_manager = objreg.get('qtnetwork-download-manager')
|
||||
if not inline:
|
||||
# Content-Disposition: attachment -> force download
|
||||
download_manager.fetch(reply,
|
||||
suggested_filename=suggested_filename)
|
||||
return
|
||||
mimetype, _rest = http.parse_content_type(reply)
|
||||
mimetype, _rest = httpheaders.parse_content_type(reply)
|
||||
if mimetype == 'image/jpg':
|
||||
# Some servers (e.g. the LinkedIn CDN) send a non-standard
|
||||
# image/jpg (instead of image/jpeg, defined in RFC 1341 section
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
import traceback
|
||||
import re
|
||||
import contextlib
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Iterator, Mapping, MutableMapping
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Tuple, Iterator, Mapping, MutableMapping
|
||||
|
||||
from qutebrowser.qt.core import pyqtSlot, QUrl, QObject
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ if TYPE_CHECKING:
|
|||
_ReplacementFunction = Callable[['tabbedbrowser.TabbedBrowser'], str]
|
||||
|
||||
|
||||
last_command = {}
|
||||
last_command: Dict[usertypes.KeyMode, Tuple[str, int]] = {}
|
||||
|
||||
|
||||
def _url(tabbed_browser):
|
||||
|
|
|
|||
|
|
@ -437,8 +437,7 @@ class CompletionView(QTreeView):
|
|||
contents_height = (
|
||||
self.viewportSizeHint().height() +
|
||||
bar.sizeHint().height())
|
||||
if contents_height <= height:
|
||||
height = contents_height
|
||||
height = min(height, contents_height)
|
||||
# The width isn't really relevant as we're expanding anyways.
|
||||
return QSize(-1, height)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ key_instance = cast('KeyConfig', None)
|
|||
cache = cast('configcache.ConfigCache', None)
|
||||
|
||||
# Keeping track of all change filters to validate them later.
|
||||
change_filters = []
|
||||
change_filters: List["change_filter"] = []
|
||||
|
||||
# Sentinel
|
||||
UNSET = object()
|
||||
|
|
|
|||
|
|
@ -1784,6 +1784,7 @@ hints.selectors:
|
|||
- '[role="button"]'
|
||||
- '[role="tab"]'
|
||||
- '[role="checkbox"]'
|
||||
- '[role="switch"]'
|
||||
- '[role="menuitem"]'
|
||||
- '[role="menuitemcheckbox"]'
|
||||
- '[role="menuitemradio"]'
|
||||
|
|
@ -3330,7 +3331,7 @@ colors.webpage.darkmode.enabled:
|
|||
colors.webpage.darkmode.algorithm:
|
||||
default: lightness-cielab
|
||||
desc: >-
|
||||
Which algorithm to use for modifying how colors are rendered with darkmode.
|
||||
Which algorithm to use for modifying how colors are rendered with dark mode.
|
||||
|
||||
The `lightness-cielab` value was added with QtWebEngine 5.14 and is treated
|
||||
like `lightness-hsl` with older QtWebEngine versions.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
import argparse
|
||||
import os.path
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
from qutebrowser.qt.widgets import QMessageBox
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ from qutebrowser.misc import msgbox, objects, savemanager
|
|||
|
||||
|
||||
# Error which happened during init, so we can show a message box.
|
||||
_init_errors = None
|
||||
_init_errors: Optional[configexc.ConfigFileErrors] = None
|
||||
|
||||
|
||||
def early_init(args: argparse.Namespace) -> None:
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ def clear_private_data() -> None:
|
|||
elif objects.backend == usertypes.Backend.QtWebKit:
|
||||
from qutebrowser.browser.webkit import cookies
|
||||
assert cookies.ram_cookie_jar is not None
|
||||
cookies.ram_cookie_jar.setAllCookies([]) # type: ignore[unreachable]
|
||||
cookies.ram_cookie_jar.setAllCookies([])
|
||||
else:
|
||||
raise utils.Unreachable(objects.backend)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from qutebrowser.misc import objects
|
|||
|
||||
|
||||
# ModuleInfo objects for all loaded plugins
|
||||
_module_infos = []
|
||||
_module_infos: List["ModuleInfo"] = []
|
||||
|
||||
InitHookType = Callable[['InitContext'], None]
|
||||
ConfigChangedHookType = Callable[[], None]
|
||||
|
|
|
|||
|
|
@ -739,6 +739,12 @@ window._qutebrowser.caret = (function() {
|
|||
*/
|
||||
CaretBrowsing.isWindows = null;
|
||||
|
||||
/**
|
||||
* Whether we should log debug outputs.
|
||||
* @type {boolean}
|
||||
*/
|
||||
CaretBrowsing.isDebug = null;
|
||||
|
||||
/**
|
||||
* The id returned by window.setInterval for our stopAnimation function, so
|
||||
* we can cancel it when we call stopAnimation again.
|
||||
|
|
@ -1150,6 +1156,8 @@ window._qutebrowser.caret = (function() {
|
|||
action = "extend";
|
||||
}
|
||||
|
||||
CaretBrowsing.debug(`(move) ${action} ${count} ${granularity} ${direction}, selection ${CaretBrowsing.selectionState}`);
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
if (CaretBrowsing.selectionState === CaretBrowsing.SelectionState.LINE) {
|
||||
CaretBrowsing.updateLineSelection(direction, granularity);
|
||||
|
|
@ -1180,6 +1188,8 @@ window._qutebrowser.caret = (function() {
|
|||
if (CaretBrowsing.selectionState !== CaretBrowsing.SelectionState.NONE) {
|
||||
action = "extend";
|
||||
}
|
||||
CaretBrowsing.debug(`(moveToBlock) ${action} paragraph ${paragraph}, boundary ${boundary}, count ${count}, selection ${CaretBrowsing.selectionState}`);
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
window.
|
||||
getSelection().
|
||||
|
|
@ -1196,6 +1206,7 @@ window._qutebrowser.caret = (function() {
|
|||
};
|
||||
|
||||
CaretBrowsing.toggle = function(value) {
|
||||
CaretBrowsing.debug(`(toggle) enabled ${CaretBrowsing.isEnabled}, force ${CaretBrowsing.forceEnabled}`);
|
||||
if (CaretBrowsing.forceEnabled) {
|
||||
CaretBrowsing.recreateCaretElement();
|
||||
return;
|
||||
|
|
@ -1231,6 +1242,7 @@ window._qutebrowser.caret = (function() {
|
|||
* is enabled and whether this window / iframe has focus.
|
||||
*/
|
||||
CaretBrowsing.updateIsCaretVisible = function() {
|
||||
CaretBrowsing.debug(`(updateIsCaretVisible) isEnabled ${CaretBrowsing.isEnabled}, isWindowFocused ${CaretBrowsing.isWindowFocused}, isCaretVisible ${CaretBrowsing.isCaretVisible}, caretElement ${CaretBrowsing.caretElement}`);
|
||||
CaretBrowsing.isCaretVisible =
|
||||
(CaretBrowsing.isEnabled && CaretBrowsing.isWindowFocused);
|
||||
if (CaretBrowsing.isCaretVisible && !CaretBrowsing.caretElement) {
|
||||
|
|
@ -1274,6 +1286,12 @@ window._qutebrowser.caret = (function() {
|
|||
}
|
||||
};
|
||||
|
||||
CaretBrowsing.debug = (text) => {
|
||||
if (CaretBrowsing.isDebug) {
|
||||
console.debug(`caret: ${text}`);
|
||||
}
|
||||
}
|
||||
|
||||
CaretBrowsing.init = function() {
|
||||
CaretBrowsing.isWindowFocused = document.hasFocus();
|
||||
|
||||
|
|
@ -1313,6 +1331,7 @@ window._qutebrowser.caret = (function() {
|
|||
|
||||
funcs.setFlags = (flags) => {
|
||||
CaretBrowsing.isWindows = flags.includes("windows");
|
||||
CaretBrowsing.isDebug = flags.includes("debug");
|
||||
};
|
||||
|
||||
funcs.disableCaret = () => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ from qutebrowser.qt.gui import QKeySequence, QKeyEvent
|
|||
if machinery.IS_QT6:
|
||||
from qutebrowser.qt.core import QKeyCombination
|
||||
else:
|
||||
QKeyCombination = None # QKeyCombination was added in Qt 6
|
||||
QKeyCombination: None = None # QKeyCombination was added in Qt 6
|
||||
|
||||
from qutebrowser.utils import utils, qtutils, debug
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import sys
|
||||
import code
|
||||
from typing import MutableSequence
|
||||
from typing import MutableSequence, Optional
|
||||
|
||||
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, Qt
|
||||
from qutebrowser.qt.widgets import QTextEdit, QWidget, QVBoxLayout, QApplication
|
||||
|
|
@ -17,7 +17,7 @@ from qutebrowser.misc import cmdhistory, miscwidgets
|
|||
from qutebrowser.utils import utils, objreg
|
||||
|
||||
|
||||
console_widget = None
|
||||
console_widget: Optional["ConsoleWidget"] = None
|
||||
|
||||
|
||||
class ConsoleLineEdit(miscwidgets.CommandLineEdit):
|
||||
|
|
|
|||
|
|
@ -22,8 +22,9 @@ from qutebrowser.qt.core import (pyqtSlot, qInstallMessageHandler, QObject,
|
|||
from qutebrowser.qt.widgets import QApplication
|
||||
|
||||
from qutebrowser.api import cmdutils
|
||||
from qutebrowser.config import configfiles, configexc
|
||||
from qutebrowser.misc import earlyinit, crashdialog, ipc, objects
|
||||
from qutebrowser.utils import usertypes, standarddir, log, objreg, debug, utils
|
||||
from qutebrowser.utils import usertypes, standarddir, log, objreg, debug, utils, message
|
||||
from qutebrowser.qt import sip
|
||||
if TYPE_CHECKING:
|
||||
from qutebrowser.misc import quitter
|
||||
|
|
@ -322,6 +323,17 @@ class SignalHandler(QObject):
|
|||
self._activated = False
|
||||
self._orig_wakeup_fd: Optional[int] = None
|
||||
|
||||
self._handlers = {
|
||||
signal.SIGINT: self.interrupt,
|
||||
signal.SIGTERM: self.interrupt,
|
||||
}
|
||||
platform_dependant_handlers = {
|
||||
"SIGHUP": self.reload_config,
|
||||
}
|
||||
for sig_str, handler in platform_dependant_handlers.items():
|
||||
if hasattr(signal.Signals, sig_str):
|
||||
self._handlers[signal.Signals[sig_str]] = handler
|
||||
|
||||
def activate(self):
|
||||
"""Set up signal handlers.
|
||||
|
||||
|
|
@ -331,10 +343,8 @@ class SignalHandler(QObject):
|
|||
On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
|
||||
notified.
|
||||
"""
|
||||
self._orig_handlers[signal.SIGINT] = signal.signal(
|
||||
signal.SIGINT, self.interrupt)
|
||||
self._orig_handlers[signal.SIGTERM] = signal.signal(
|
||||
signal.SIGTERM, self.interrupt)
|
||||
for sig, handler in self._handlers.items():
|
||||
self._orig_handlers[sig] = signal.signal(sig, handler)
|
||||
|
||||
if utils.is_posix and hasattr(signal, 'set_wakeup_fd'):
|
||||
# pylint: disable=import-error,no-member,useless-suppression
|
||||
|
|
@ -430,6 +440,15 @@ class SignalHandler(QObject):
|
|||
print("WHY ARE YOU DOING THIS TO ME? :(")
|
||||
sys.exit(128 + signum)
|
||||
|
||||
def reload_config(self, _signum, _frame):
|
||||
"""Reload the config."""
|
||||
log.signals.info("SIGHUP received, reloading config.")
|
||||
filename = standarddir.config_py()
|
||||
try:
|
||||
configfiles.read_config_py(filename)
|
||||
except configexc.ConfigFileErrors as e:
|
||||
message.error(str(e))
|
||||
|
||||
|
||||
def init(q_app: QApplication,
|
||||
args: argparse.Namespace,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ PROTOCOL_VERSION = 1
|
|||
|
||||
|
||||
# The ipc server instance
|
||||
server = None
|
||||
server: Optional["IPCServer"] = None
|
||||
|
||||
|
||||
def _get_socketname_windows(basedir):
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from qutebrowser.utils import log
|
|||
|
||||
|
||||
# Needs to be saved to avoid garbage collection
|
||||
_instance = None
|
||||
_instance: Optional["NativeEventFilter"] = None
|
||||
|
||||
# Using C-style naming for C structures in this file
|
||||
# pylint: disable=invalid-name
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ from qutebrowser.utils import log
|
|||
# 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.
|
||||
_WRAPPER_OVERRIDE = None
|
||||
_WRAPPER_OVERRIDE = None # type: ignore[var-annotated]
|
||||
|
||||
WRAPPERS = [
|
||||
"PyQt6",
|
||||
|
|
@ -168,9 +168,9 @@ def _select_wrapper(args: Optional[argparse.Namespace]) -> SelectionInfo:
|
|||
- Otherwise, try the wrappers in WRAPPER in order (PyQt6 -> PyQt5)
|
||||
"""
|
||||
# If any Qt wrapper has been imported before this, something strange might
|
||||
# be happening.
|
||||
# be happening. With PyInstaller, it imports the Qt bindings early.
|
||||
for name in WRAPPERS:
|
||||
if name in sys.modules:
|
||||
if name in sys.modules and not hasattr(sys, "frozen"):
|
||||
warnings.warn(f"{name} already imported", stacklevel=1)
|
||||
|
||||
if args is not None and args.qt_wrapper is not None:
|
||||
|
|
@ -190,7 +190,7 @@ def _select_wrapper(args: Optional[argparse.Namespace]) -> SelectionInfo:
|
|||
return SelectionInfo(wrapper=env_wrapper, reason=SelectionReason.env)
|
||||
|
||||
if _WRAPPER_OVERRIDE is not None:
|
||||
assert _WRAPPER_OVERRIDE in WRAPPERS # type: ignore[unreachable]
|
||||
assert _WRAPPER_OVERRIDE in WRAPPERS
|
||||
return SelectionInfo(wrapper=_WRAPPER_OVERRIDE, reason=SelectionReason.override)
|
||||
|
||||
return _autoselect_wrapper()
|
||||
|
|
|
|||
|
|
@ -171,12 +171,13 @@ def debug_flag_error(flag):
|
|||
avoid-chromium-init: Enable `--version` without initializing Chromium.
|
||||
werror: Turn Python warnings into errors.
|
||||
test-notification-service: Use the testing libnotify service.
|
||||
caret: Enable debug logging for caret.js.
|
||||
"""
|
||||
valid_flags = ['debug-exit', 'pdb-postmortem', 'no-sql-history',
|
||||
'no-scroll-filtering', 'log-requests', 'log-cookies',
|
||||
'log-scroll-pos', 'log-sensitive-keys', 'stack', 'chromium',
|
||||
'wait-renderer-process', 'avoid-chromium-init', 'werror',
|
||||
'test-notification-service', 'log-qt-events']
|
||||
'test-notification-service', 'log-qt-events', 'caret']
|
||||
|
||||
if flag in valid_flags:
|
||||
return flag
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ if TYPE_CHECKING:
|
|||
from qutebrowser.config import config as configmodule
|
||||
|
||||
_log_inited = False
|
||||
_args = None
|
||||
_args: Optional[argparse.Namespace] = None
|
||||
|
||||
COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'purple', 'cyan', 'white']
|
||||
COLOR_ESCAPES = {color: '\033[{}m'.format(i)
|
||||
|
|
@ -146,7 +146,7 @@ LOGGER_NAMES = [
|
|||
|
||||
ram_handler: Optional['RAMHandler'] = None
|
||||
console_handler: Optional[logging.Handler] = None
|
||||
console_filter = None
|
||||
console_filter: Optional["LogFilter"] = None
|
||||
|
||||
|
||||
def stub(suffix: str = '') -> None:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from typing import Iterator, Optional
|
|||
from qutebrowser.qt import core as qtcore
|
||||
from qutebrowser.utils import log
|
||||
|
||||
_args = None
|
||||
_args: Optional[argparse.Namespace] = None
|
||||
|
||||
|
||||
def init(args: argparse.Namespace) -> None:
|
||||
|
|
|
|||
|
|
@ -193,6 +193,15 @@ def check_qdatastream(stream: QDataStream) -> None:
|
|||
QDataStream.Status.WriteFailed: ("The data stream cannot write to the "
|
||||
"underlying device."),
|
||||
}
|
||||
try:
|
||||
status_to_str[QDataStream.Status.SizeLimitExceeded] = ( # type: ignore[attr-defined]
|
||||
"The data stream cannot read or write the data because its size is larger "
|
||||
"than supported by the current platform."
|
||||
)
|
||||
except AttributeError:
|
||||
# Added in Qt 6.7
|
||||
pass
|
||||
|
||||
if stream.status() != QDataStream.Status.Ok:
|
||||
raise OSError(status_to_str[stream.status()])
|
||||
|
||||
|
|
@ -736,4 +745,4 @@ else:
|
|||
def add_optional(obj: Optional[_T]) -> Optional[_T]:
|
||||
return obj
|
||||
|
||||
QT_NONE = None
|
||||
QT_NONE: None = None
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import sys
|
|||
import contextlib
|
||||
import posixpath
|
||||
import pathlib
|
||||
from typing import Iterator, Iterable, Union
|
||||
from typing import Iterator, Iterable, Union, Dict
|
||||
|
||||
|
||||
# We cannot use the stdlib version on 3.8 because we need the files() API.
|
||||
|
|
@ -25,7 +25,7 @@ else: # pragma: no cover
|
|||
from importlib_resources.abc import Traversable
|
||||
|
||||
import qutebrowser
|
||||
_cache = {}
|
||||
_cache: Dict[str, str] = {}
|
||||
|
||||
|
||||
_ResourceType = Union[Traversable, pathlib.Path]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import sys
|
|||
import contextlib
|
||||
import enum
|
||||
import argparse
|
||||
from typing import Iterator, Optional
|
||||
from typing import Iterator, Optional, Dict
|
||||
|
||||
from qutebrowser.qt.core import QStandardPaths
|
||||
from qutebrowser.qt.widgets import QApplication
|
||||
|
|
@ -18,7 +18,7 @@ from qutebrowser.qt.widgets import QApplication
|
|||
from qutebrowser.utils import log, debug, utils, version, qtutils
|
||||
|
||||
# The cached locations
|
||||
_locations = {}
|
||||
_locations: Dict["_Location", str] = {}
|
||||
|
||||
|
||||
class _Location(enum.Enum):
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ except ImportError: # pragma: no cover
|
|||
|
||||
from qutebrowser.utils import log
|
||||
|
||||
fake_clipboard = None
|
||||
fake_clipboard: Optional[str] = None
|
||||
log_clipboard = False
|
||||
|
||||
is_mac = sys.platform.startswith('darwin')
|
||||
|
|
@ -341,7 +341,7 @@ class prevent_exceptions: # noqa: N801,N806 pylint: disable=invalid-name
|
|||
"""Call the original function."""
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except BaseException:
|
||||
except BaseException: # noqa: B036
|
||||
log.misc.exception("Error in {}".format(qualname(func)))
|
||||
return retval
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class DistributionInfo:
|
|||
pretty: str
|
||||
|
||||
|
||||
pastebin_url = None
|
||||
pastebin_url: Optional[str] = None
|
||||
|
||||
|
||||
class Distribution(enum.Enum):
|
||||
|
|
@ -535,6 +535,7 @@ class WebEngineVersions:
|
|||
webengine: utils.VersionNumber
|
||||
chromium: Optional[str]
|
||||
source: str
|
||||
chromium_security: Optional[str] = None
|
||||
chromium_major: Optional[int] = dataclasses.field(init=False)
|
||||
|
||||
_CHROMIUM_VERSIONS: ClassVar[Dict[utils.VersionNumber, str]] = {
|
||||
|
|
@ -610,12 +611,21 @@ class WebEngineVersions:
|
|||
# 6.5.0: Security fixes up to 110.0.5481.104 (2023-02-16)
|
||||
# 6.5.1: Security fixes up to 112.0.5615.138 (2023-04-18)
|
||||
# 6.5.2: Security fixes up to 114.0.5735.133 (2023-06-13)
|
||||
# 6.5.3: Security fixes up to 117.0.5938.63 (2023-09-12)
|
||||
utils.VersionNumber(6, 5): '108.0.5359.220',
|
||||
|
||||
# Qt 6.6: Chromium 112
|
||||
# 112.0.5615.213 (~2023-04-18)
|
||||
# 6.6.0: Security fixes up to 116.0.5845.110 (?) (2023-08-22)
|
||||
# 6.6.0: Security fixes up to 117.0.5938.63 (2023-09-12)
|
||||
# 6.6.1: Security fixes up to 119.0.6045.123 (2023-11-07)
|
||||
# 6.6.2: Security fixes up to 121.0.6167.160 (2024-02-06)
|
||||
# 6.6.3: Security fixes up to 122.0.6261.128 (2024-03-12)
|
||||
utils.VersionNumber(6, 6): '112.0.5615.213',
|
||||
|
||||
# Qt 6.7: Chromium 118
|
||||
# 118.0.5993.220 (~2023-10-24)
|
||||
# 6.6.0: Security fixes up to 122.0.6261.128 (?) (2024-03-12)
|
||||
utils.VersionNumber(6, 7): '118.0.5993.220',
|
||||
}
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
|
|
@ -629,6 +639,8 @@ class WebEngineVersions:
|
|||
s = f'QtWebEngine {self.webengine}'
|
||||
if self.chromium is not None:
|
||||
s += f', based on Chromium {self.chromium}'
|
||||
if self.chromium_security is not None:
|
||||
s += f', with security patches up to {self.chromium_security} (plus any distribution patches)'
|
||||
if self.source != 'UA':
|
||||
s += f' (from {self.source})'
|
||||
return s
|
||||
|
|
@ -686,7 +698,12 @@ class WebEngineVersions:
|
|||
return cls._CHROMIUM_VERSIONS.get(minor_version)
|
||||
|
||||
@classmethod
|
||||
def from_api(cls, qtwe_version: str, chromium_version: Optional[str]) -> 'WebEngineVersions':
|
||||
def from_api(
|
||||
cls,
|
||||
qtwe_version: str,
|
||||
chromium_version: Optional[str],
|
||||
chromium_security: Optional[str] = None,
|
||||
) -> 'WebEngineVersions':
|
||||
"""Get the versions based on the exact versions.
|
||||
|
||||
This is called if we have proper APIs to get the versions easily
|
||||
|
|
@ -696,6 +713,7 @@ class WebEngineVersions:
|
|||
return cls(
|
||||
webengine=parsed,
|
||||
chromium=chromium_version,
|
||||
chromium_security=chromium_security,
|
||||
source='api',
|
||||
)
|
||||
|
||||
|
|
@ -796,11 +814,20 @@ def qtwebengine_versions(*, avoid_init: bool = False) -> WebEngineVersions:
|
|||
except ImportError:
|
||||
pass # Needs QtWebEngine 6.2+ with PyQtWebEngine 6.3.1+
|
||||
else:
|
||||
try:
|
||||
from qutebrowser.qt.webenginecore import (
|
||||
qWebEngineChromiumSecurityPatchVersion,
|
||||
)
|
||||
chromium_security = qWebEngineChromiumSecurityPatchVersion()
|
||||
except ImportError:
|
||||
chromium_security = None # Needs QtWebEngine 6.3+
|
||||
|
||||
qtwe_version = qWebEngineVersion()
|
||||
assert qtwe_version is not None
|
||||
return WebEngineVersions.from_api(
|
||||
qtwe_version=qtwe_version,
|
||||
chromium_version=qWebEngineChromiumVersion(),
|
||||
chromium_security=chromium_security,
|
||||
)
|
||||
|
||||
from qutebrowser.browser.webengine import webenginesettings
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
adblock==0.6.0
|
||||
colorama==0.4.6
|
||||
importlib-resources==6.1.1 ; python_version=="3.8.*"
|
||||
Jinja2==3.1.2
|
||||
MarkupSafe==2.1.3
|
||||
importlib_resources==6.4.0 ; python_version=="3.8.*"
|
||||
Jinja2==3.1.3
|
||||
MarkupSafe==2.1.5
|
||||
Pygments==2.17.2
|
||||
PyYAML==6.0.1
|
||||
zipp==3.17.0
|
||||
zipp==3.18.1
|
||||
# Unpinned due to recompile_requirements.py limitations
|
||||
pyobjc-core ; sys_platform=="darwin"
|
||||
pyobjc-framework-Cocoa ; sys_platform=="darwin"
|
||||
|
|
|
|||
|
|
@ -171,6 +171,9 @@ def smoke_test(executable: pathlib.Path, debug: bool, qt5: bool) -> None:
|
|||
r'[0-9:]* WARNING: Qt WebEngine resources not found at .*',
|
||||
(r'[0-9:]* WARNING: Installed Qt WebEngine locales directory not found at '
|
||||
r'location /qtwebengine_locales\. Trying application directory\.\.\.'),
|
||||
# Qt 6.7, only seen on macos for some reason
|
||||
(r'.*Path override failed for key base::DIR_APP_DICTIONARIES '
|
||||
r"and path '.*/qtwebengine_dictionaries'"),
|
||||
])
|
||||
elif IS_WINDOWS:
|
||||
stderr_whitelist.extend([
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@
|
|||
"flake8": "https://github.com/PyCQA/flake8/tree/main/docs/source/release-notes",
|
||||
"flake8-docstrings": "https://github.com/PyCQA/flake8-docstrings/blob/main/HISTORY.rst",
|
||||
"flake8-debugger": "https://github.com/JBKahn/flake8-debugger/",
|
||||
"flake8-builtins": "https://github.com/gforcada/flake8-builtins/blob/master/CHANGES.rst",
|
||||
"flake8-builtins": "https://github.com/gforcada/flake8-builtins/blob/main/CHANGES.rst",
|
||||
"flake8-bugbear": "https://github.com/PyCQA/flake8-bugbear#change-log",
|
||||
"flake8-tidy-imports": "https://github.com/adamchainz/flake8-tidy-imports/blob/main/CHANGELOG.rst",
|
||||
"flake8-tuple": "https://github.com/ar4s/flake8_tuple/blob/master/HISTORY.rst",
|
||||
"flake8-comprehensions": "https://github.com/adamchainz/flake8-comprehensions/blob/main/CHANGELOG.rst",
|
||||
"flake8-deprecated": "https://github.com/gforcada/flake8-deprecated/blob/master/CHANGES.rst",
|
||||
"flake8-deprecated": "https://github.com/gforcada/flake8-deprecated/blob/main/CHANGES.rst",
|
||||
"flake8-future-import": "https://github.com/xZise/flake8-future-import#changes",
|
||||
"flake8-string-format": "https://github.com/xZise/flake8-string-format#changes",
|
||||
"flake8-plugin-utils": "https://github.com/afonasev/flake8-plugin-utils#change-log",
|
||||
|
|
@ -78,7 +78,6 @@
|
|||
"sphinxcontrib-jsmath": "https://www.sphinx-doc.org/en/master/changes.html",
|
||||
"sphinxcontrib-qthelp": "https://www.sphinx-doc.org/en/master/changes.html",
|
||||
"sphinxcontrib-serializinghtml": "https://www.sphinx-doc.org/en/master/changes.html",
|
||||
"jaraco.functools": "https://jaracofunctools.readthedocs.io/en/latest/history.html",
|
||||
"parse": "https://github.com/r1chardj0n3s/parse#potential-gotchas",
|
||||
"Pympler": "https://github.com/pympler/pympler/blob/master/CHANGELOG.md",
|
||||
"pytest-mock": "https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst",
|
||||
|
|
@ -93,13 +92,12 @@
|
|||
"urllib3": "https://github.com/urllib3/urllib3/blob/main/CHANGES.rst",
|
||||
"lxml": "https://github.com/lxml/lxml/blob/master/CHANGES.txt",
|
||||
"cryptography": "https://cryptography.io/en/latest/changelog.html",
|
||||
"toml": "https://github.com/uiri/toml/releases",
|
||||
"tomli": "https://github.com/hukkin/tomli/blob/master/CHANGELOG.md",
|
||||
"PyQt5": "https://www.riverbankcomputing.com/news",
|
||||
"PyQt5-Qt5": "https://www.riverbankcomputing.com/news",
|
||||
"PyQtWebEngine": "https://www.riverbankcomputing.com/news",
|
||||
"PyQtWebEngine-Qt5": "https://www.riverbankcomputing.com/news",
|
||||
"PyQt-builder": "https://www.riverbankcomputing.com/news",
|
||||
"PyQt-builder": "https://pyqt-builder.readthedocs.io/en/stable/releases.html",
|
||||
"PyQt5-sip": "https://www.riverbankcomputing.com/news",
|
||||
"PyQt5-stubs": "https://github.com/python-qt-tools/PyQt5-stubs/blob/master/CHANGELOG.md",
|
||||
"sip": "https://www.riverbankcomputing.com/news",
|
||||
|
|
@ -120,33 +118,36 @@
|
|||
"tldextract": "https://github.com/john-kurkowski/tldextract/blob/master/CHANGELOG.md",
|
||||
"typing_extensions": "https://github.com/python/typing_extensions/blob/main/CHANGELOG.md",
|
||||
"diff_cover": "https://github.com/Bachmann1234/diff_cover/blob/main/CHANGELOG",
|
||||
"beautifulsoup4": "https://bazaar.launchpad.net/~leonardr/beautifulsoup/bs4/view/head:/CHANGELOG",
|
||||
"beautifulsoup4": "https://git.launchpad.net/beautifulsoup/tree/CHANGELOG",
|
||||
"check-manifest": "https://github.com/mgedmin/check-manifest/blob/master/CHANGES.rst",
|
||||
"yamllint": "https://github.com/adrienverge/yamllint/blob/master/CHANGELOG.rst",
|
||||
"pathspec": "https://github.com/cpburnz/python-path-specification/blob/master/CHANGES.rst",
|
||||
"filelock": "https://github.com/tox-dev/py-filelock/releases",
|
||||
"github3.py": "https://github3.readthedocs.io/en/latest/release-notes/index.html",
|
||||
"manhole": "https://github.com/ionelmc/python-manhole/blob/master/CHANGELOG.rst",
|
||||
"pycparser": "https://github.com/eliben/pycparser/blob/master/CHANGES",
|
||||
"pycparser": "https://github.com/eliben/pycparser/releases",
|
||||
"python-dateutil": "https://dateutil.readthedocs.io/en/stable/changelog.html",
|
||||
"platformdirs": "https://github.com/platformdirs/platformdirs/releases",
|
||||
"pluggy": "https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst",
|
||||
"mypy-extensions": "https://github.com/python/mypy_extensions/commits/master",
|
||||
"pyroma": "https://github.com/regebro/pyroma/blob/master/CHANGES.txt",
|
||||
"adblock": "https://github.com/ArniDagur/python-adblock/blob/master/CHANGELOG.md",
|
||||
"importlib-resources": "https://importlib-resources.readthedocs.io/en/latest/history.html",
|
||||
"importlib-metadata": "https://github.com/python/importlib_metadata/blob/main/NEWS.rst",
|
||||
"zipp": "https://github.com/jaraco/zipp/blob/main/NEWS.rst",
|
||||
"importlib_resources": "https://importlib-resources.readthedocs.io/en/latest/history.html",
|
||||
"importlib_metadata": "https://github.com/python/importlib_metadata/blob/main/NEWS.rst",
|
||||
"zipp": "https://zipp.readthedocs.io/en/latest/history.html",
|
||||
"pip": "https://pip.pypa.io/en/stable/news/",
|
||||
"wheel": "https://wheel.readthedocs.io/en/stable/news.html",
|
||||
"setuptools": "https://setuptools.readthedocs.io/en/latest/history.html",
|
||||
"pefile": "https://github.com/erocarrera/pefile/commits/master",
|
||||
"SecretStorage": "https://github.com/mitya57/secretstorage/blob/master/changelog",
|
||||
"jeepney": "https://gitlab.com/takluyver/jeepney/-/blob/master/docs/release-notes.rst",
|
||||
"keyring": "https://github.com/jaraco/keyring/blob/main/NEWS.rst",
|
||||
"jaraco.classes": "https://github.com/jaraco/jaraco.classes/blob/main/NEWS.rst",
|
||||
"keyring": "https://keyring.readthedocs.io/en/latest/history.html",
|
||||
"jaraco.classes": "https://jaracoclasses.readthedocs.io/en/latest/history.html",
|
||||
"jaraco.context": "https://jaracocontext.readthedocs.io/en/latest/history.html",
|
||||
"jaraco.functools": "https://jaracofunctools.readthedocs.io/en/latest/history.html",
|
||||
"backports.tarfile": "https://github.com/jaraco/backports.tarfile/blob/main/NEWS.rst",
|
||||
"pkginfo": "https://bazaar.launchpad.net/~tseaver/pkginfo/trunk/view/head:/CHANGES.txt",
|
||||
"readme-renderer": "https://github.com/pypa/readme_renderer/blob/main/CHANGES.rst",
|
||||
"readme_renderer": "https://github.com/pypa/readme_renderer/blob/main/CHANGES.rst",
|
||||
"requests-toolbelt": "https://github.com/requests/toolbelt/blob/master/HISTORY.rst",
|
||||
"rfc3986": "https://rfc3986.readthedocs.io/en/latest/release-notes/index.html",
|
||||
"twine": "https://twine.readthedocs.io/en/stable/changelog.html",
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ PERFECT_FILES = [
|
|||
'qutebrowser/browser/history.py'),
|
||||
('tests/unit/browser/test_pdfjs.py',
|
||||
'qutebrowser/browser/pdfjs.py'),
|
||||
('tests/unit/browser/webkit/http/test_http.py',
|
||||
'qutebrowser/browser/webkit/http.py'),
|
||||
('tests/unit/browser/webkit/http/test_httpheaders.py',
|
||||
'qutebrowser/browser/webkit/httpheaders.py'),
|
||||
# ('tests/unit/browser/webkit/test_webkitelem.py',
|
||||
# 'qutebrowser/browser/webkit/webkitelem.py'),
|
||||
# ('tests/unit/browser/webkit/test_webkitelem.py',
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ def import_html_bookmarks(bookmarks_file, bookmark_types, output_format):
|
|||
}
|
||||
bookmarks = []
|
||||
for typ in bookmark_types:
|
||||
tags = soup.findAll(bookmark_query[typ])
|
||||
tags = soup.find_all(bookmark_query[typ])
|
||||
for tag in tags:
|
||||
if typ == 'search':
|
||||
tag['href'] = search_escape(tag['href']).replace('%s', '{}')
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<span onclick='console.log("click_element special chars")'>"Don't", he shouted</span>
|
||||
<span>Duplicate</span>
|
||||
<span class='clickable' onclick='console.log("click_element CSS selector")'>Duplicate</span>
|
||||
<form><input autofocus id='qute-input'></input></form>
|
||||
<form><input id='qute-input' onfocus='console.log("qute-input focused")'></input></form>
|
||||
<a href="/data/hello.txt" id='link'>link</a>
|
||||
<span id='foo.bar' onclick='console.log("id with dot")'>ID with dot</span>
|
||||
<span style='position: absolute; left: 20px;top: 42px; width:10px; height:10px;'
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
elem.addEventListener('input', function() {
|
||||
console.log("contents: " + elem.value);
|
||||
});
|
||||
elem.addEventListener('focus', function() {
|
||||
console.log("autofocus element focused");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@ Feature: Caret mode
|
|||
|
||||
Scenario: :yank selection with --keep
|
||||
When I run :selection-toggle
|
||||
And I run :move-to-end-of-word
|
||||
And I run :move-to-next-word
|
||||
And I run :yank selection --keep
|
||||
And I run :move-to-end-of-word
|
||||
And I run :yank selection --keep
|
||||
Then the message "3 chars yanked to clipboard" should be shown
|
||||
Then the message "4 chars yanked to clipboard" should be shown
|
||||
And the message "7 chars yanked to clipboard" should be shown
|
||||
And the clipboard should contain "one two"
|
||||
|
||||
|
|
|
|||
|
|
@ -730,8 +730,15 @@ def should_quit(qtbot, quteproc):
|
|||
|
||||
def _get_scroll_values(quteproc):
|
||||
data = quteproc.get_session()
|
||||
pos = data['windows'][0]['tabs'][0]['history'][-1]['scroll-pos']
|
||||
return (pos['x'], pos['y'])
|
||||
|
||||
def get_active(things):
|
||||
return next(thing for thing in things if thing.get("active"))
|
||||
|
||||
active_window = get_active(data["windows"])
|
||||
active_tab = get_active(active_window["tabs"])
|
||||
current_entry = get_active(active_tab["history"])
|
||||
pos = current_entry["scroll-pos"]
|
||||
return (pos["x"], pos["y"])
|
||||
|
||||
|
||||
@bdd.then(bdd.parsers.re(r"the page should be scrolled "
|
||||
|
|
|
|||
|
|
@ -502,14 +502,13 @@ Feature: Various utility commands.
|
|||
|
||||
Scenario: Clicking on focused element when there is none
|
||||
When I open data/click_element.html
|
||||
# Need to loose focus on input element
|
||||
And I run :click-element position 20,42
|
||||
And I wait for the javascript message "click_element position"
|
||||
And I run :click-element focused
|
||||
Then the error "No element found with focus!" should be shown
|
||||
|
||||
Scenario: Clicking on focused element
|
||||
When I open data/click_element.html
|
||||
And I run :fake-key <Tab>
|
||||
And I wait for the javascript message "qute-input focused"
|
||||
And I run :click-element focused
|
||||
Then "Entering mode KeyMode.insert (reason: clicking input)" should be logged
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ Feature: Miscellaneous utility commands exposed to the user.
|
|||
Background:
|
||||
Given I open data/scroll/simple.html
|
||||
And I run :tab-only
|
||||
And I run :window-only
|
||||
|
||||
## :cmd-later
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ def is_ignored_lowlevel_message(message):
|
|||
'glx: failed to create drisw screen',
|
||||
'failed to load driver: zink',
|
||||
'DRI3 not available',
|
||||
# Webkit on arch with a newer mesa
|
||||
'MESA: error: ZINK: failed to load libvulkan.so.1',
|
||||
]
|
||||
return any(testutils.pattern_match(pattern=pattern, value=message)
|
||||
for pattern in ignored_messages)
|
||||
|
|
@ -213,6 +215,16 @@ def is_ignored_chromium_message(line):
|
|||
# [9895:9983:0904/043039.500565:ERROR:gpu_memory_buffer_support_x11.cc(49)]
|
||||
# dri3 extension not supported.
|
||||
"dri3 extension not supported.",
|
||||
|
||||
# Qt 6.7 debug build
|
||||
# [44513:44717:0325/173456.146759:WARNING:render_message_filter.cc(144)]
|
||||
# Could not find tid
|
||||
"Could not find tid",
|
||||
|
||||
# [127693:127748:0325/230155.835421:WARNING:discardable_shared_memory_manager.cc(438)]
|
||||
# Some MojoDiscardableSharedMemoryManagerImpls are still alive. They
|
||||
# will be leaked.
|
||||
"Some MojoDiscardableSharedMemoryManagerImpls are still alive. They will be leaked.",
|
||||
]
|
||||
return any(testutils.pattern_match(pattern=pattern, value=message)
|
||||
for pattern in ignored_messages)
|
||||
|
|
@ -395,9 +407,11 @@ class QuteProc(testprocess.Process):
|
|||
backend = 'webengine' if self.request.config.webengine else 'webkit'
|
||||
args = ['--debug', '--no-err-windows', '--temp-basedir',
|
||||
'--json-logging', '--loglevel', 'vdebug',
|
||||
'--backend', backend, '--debug-flag', 'no-sql-history',
|
||||
'--debug-flag', 'werror', '--debug-flag',
|
||||
'test-notification-service',
|
||||
'--backend', backend,
|
||||
'--debug-flag', 'no-sql-history',
|
||||
'--debug-flag', 'werror',
|
||||
'--debug-flag', 'test-notification-service',
|
||||
'--debug-flag', 'caret',
|
||||
'--qt-flag', 'disable-features=PaintHoldingCrossOrigin']
|
||||
|
||||
if self.request.config.webengine and testutils.disable_seccomp_bpf_sandbox():
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import pytest
|
|||
from qutebrowser.qt.core import pyqtSignal, QUrl
|
||||
|
||||
from end2end.fixtures import testprocess
|
||||
from helpers import testutils
|
||||
|
||||
|
||||
class Request(testprocess.Line):
|
||||
|
|
@ -111,6 +112,17 @@ class ExpectedRequest:
|
|||
return NotImplemented
|
||||
|
||||
|
||||
def is_ignored_webserver_message(line: str) -> bool:
|
||||
return testutils.pattern_match(
|
||||
pattern=(
|
||||
"Client ('127.0.0.1', *) lost — peer dropped the TLS connection suddenly, "
|
||||
"during handshake: (1, '[SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] ssl/tls "
|
||||
"alert certificate unknown (_ssl.c:*)')"
|
||||
),
|
||||
value=line,
|
||||
)
|
||||
|
||||
|
||||
class WebserverProcess(testprocess.Process):
|
||||
|
||||
"""Abstraction over a running Flask server process.
|
||||
|
|
@ -151,7 +163,13 @@ class WebserverProcess(testprocess.Process):
|
|||
if started_re.fullmatch(line):
|
||||
self.ready.emit()
|
||||
return None
|
||||
return Request(line)
|
||||
|
||||
try:
|
||||
return Request(line)
|
||||
except testprocess.InvalidLine:
|
||||
if is_ignored_webserver_message(line):
|
||||
return None
|
||||
raise
|
||||
|
||||
def _executable_args(self):
|
||||
if hasattr(sys, 'frozen'):
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ def test_insert_mode(file_name, elem_id, source, input_text, zoom,
|
|||
(True, False, True), # enabled and foreground tab
|
||||
(True, True, False), # background tab
|
||||
])
|
||||
@pytest.mark.flaky
|
||||
def test_auto_load(quteproc, auto_load, background, insert_mode):
|
||||
quteproc.set_setting('input.insert_mode.auto_load', str(auto_load))
|
||||
url_path = 'data/insert_mode_settings/html/autofocus.html'
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import textwrap
|
|||
import pytest
|
||||
from qutebrowser.qt.core import QUrl
|
||||
|
||||
from qutebrowser.utils import usertypes
|
||||
from qutebrowser.qt import machinery
|
||||
from qutebrowser.utils import utils, usertypes
|
||||
from qutebrowser.browser import browsertab
|
||||
|
||||
|
||||
|
|
@ -241,6 +242,13 @@ class TestWord:
|
|||
caret.move_to_end_of_word()
|
||||
selection.check("one")
|
||||
|
||||
@pytest.mark.xfail(
|
||||
machinery.IS_QT6 and utils.is_windows,
|
||||
reason=(
|
||||
"move-to-end-of-word is broken with Qt 6 and Windows: "
|
||||
"https://github.com/qutebrowser/qutebrowser/issues/8146"
|
||||
)
|
||||
)
|
||||
def test_moving_to_end_and_selecting_a_word(self, caret, selection):
|
||||
caret.move_to_end_of_word()
|
||||
selection.toggle()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import logging
|
|||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.browser.webkit import http
|
||||
from qutebrowser.browser.webkit import httpheaders
|
||||
|
||||
|
||||
DEFAULT_NAME = 'qutebrowser-download'
|
||||
|
|
@ -30,7 +30,7 @@ class HeaderChecker:
|
|||
"""Check if the passed header has the given filename."""
|
||||
reply = self.stubs.FakeNetworkReply(
|
||||
headers={'Content-Disposition': header})
|
||||
cd_inline, cd_filename = http.parse_content_disposition(reply)
|
||||
cd_inline, cd_filename = httpheaders.parse_content_disposition(reply)
|
||||
assert cd_filename is not None
|
||||
assert cd_filename == filename
|
||||
assert cd_inline == expected_inline
|
||||
|
|
@ -40,7 +40,7 @@ class HeaderChecker:
|
|||
reply = self.stubs.FakeNetworkReply(
|
||||
headers={'Content-Disposition': header})
|
||||
with self.caplog.at_level(logging.ERROR, 'network'):
|
||||
cd_inline, cd_filename = http.parse_content_disposition(reply)
|
||||
cd_inline, cd_filename = httpheaders.parse_content_disposition(reply)
|
||||
assert cd_filename == DEFAULT_NAME
|
||||
assert cd_inline
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ class HeaderChecker:
|
|||
"""Check if the passed header results in an unnamed attachment."""
|
||||
reply = self.stubs.FakeNetworkReply(
|
||||
headers={'Content-Disposition': header})
|
||||
cd_inline, cd_filename = http.parse_content_disposition(reply)
|
||||
cd_inline, cd_filename = httpheaders.parse_content_disposition(reply)
|
||||
assert cd_filename == DEFAULT_NAME
|
||||
assert not cd_inline
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ class TestAttachment:
|
|||
"""
|
||||
reply = stubs.FakeNetworkReply(
|
||||
headers={'Content-Disposition': 'attachment'})
|
||||
cd_inline, cd_filename = http.parse_content_disposition(reply)
|
||||
cd_inline, cd_filename = httpheaders.parse_content_disposition(reply)
|
||||
assert not cd_inline
|
||||
assert cd_filename == DEFAULT_NAME
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
"""Tests for qutebrowser.browser.webkit.http."""
|
||||
"""Tests for qutebrowser.browser.webkit.httpheaders."""
|
||||
|
||||
import logging
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ import hypothesis
|
|||
from hypothesis import strategies
|
||||
from qutebrowser.qt.core import QUrl
|
||||
|
||||
from qutebrowser.browser.webkit import http
|
||||
from qutebrowser.browser.webkit import httpheaders
|
||||
|
||||
|
||||
@pytest.mark.parametrize('url, expected', [
|
||||
|
|
@ -24,7 +24,7 @@ from qutebrowser.browser.webkit import http
|
|||
])
|
||||
def test_no_content_disposition(stubs, url, expected):
|
||||
reply = stubs.FakeNetworkReply(url=QUrl(url))
|
||||
inline, filename = http.parse_content_disposition(reply)
|
||||
inline, filename = httpheaders.parse_content_disposition(reply)
|
||||
assert inline
|
||||
assert filename == expected
|
||||
|
||||
|
|
@ -40,8 +40,8 @@ def test_no_content_disposition(stubs, url, expected):
|
|||
# dropping QtWebKit.
|
||||
])
|
||||
def test_parse_content_disposition_invalid(value):
|
||||
with pytest.raises(http.ContentDispositionError):
|
||||
http.ContentDisposition.parse(value)
|
||||
with pytest.raises(httpheaders.ContentDispositionError):
|
||||
httpheaders.ContentDisposition.parse(value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('template', [
|
||||
|
|
@ -58,16 +58,16 @@ def test_parse_content_disposition_hypothesis(caplog, template, stubs, s):
|
|||
header = template.format(s)
|
||||
reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
|
||||
with caplog.at_level(logging.ERROR, 'network'):
|
||||
http.parse_content_disposition(reply)
|
||||
httpheaders.parse_content_disposition(reply)
|
||||
|
||||
|
||||
@hypothesis.given(strategies.binary())
|
||||
def test_content_disposition_directly_hypothesis(s):
|
||||
"""Test rfc6266 parsing directly with binary data."""
|
||||
try:
|
||||
cd = http.ContentDisposition.parse(s)
|
||||
cd = httpheaders.ContentDisposition.parse(s)
|
||||
cd.filename()
|
||||
except http.ContentDispositionError:
|
||||
except httpheaders.ContentDispositionError:
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ def test_parse_content_type(stubs, content_type, expected_mimetype,
|
|||
reply = stubs.FakeNetworkReply()
|
||||
else:
|
||||
reply = stubs.FakeNetworkReply(headers={'Content-Type': content_type})
|
||||
mimetype, rest = http.parse_content_type(reply)
|
||||
mimetype, rest = httpheaders.parse_content_type(reply)
|
||||
assert mimetype == expected_mimetype
|
||||
assert rest == expected_rest
|
||||
|
||||
|
|
@ -91,4 +91,4 @@ def test_parse_content_type(stubs, content_type, expected_mimetype,
|
|||
@hypothesis.given(strategies.text())
|
||||
def test_parse_content_type_hypothesis(stubs, s):
|
||||
reply = stubs.FakeNetworkReply(headers={'Content-Type': s})
|
||||
http.parse_content_type(reply)
|
||||
httpheaders.parse_content_type(reply)
|
||||
|
|
@ -18,15 +18,15 @@ class FakeError:
|
|||
return self.msg
|
||||
|
||||
|
||||
@pytest.mark.parametrize('errors, expected', [
|
||||
@pytest.mark.parametrize('error_factories, expected', [
|
||||
(
|
||||
[QSslError(QSslError.SslError.UnableToGetIssuerCertificate)],
|
||||
[lambda: QSslError(QSslError.SslError.UnableToGetIssuerCertificate)],
|
||||
['<p>The issuer certificate could not be found</p>'],
|
||||
),
|
||||
(
|
||||
[
|
||||
QSslError(QSslError.SslError.UnableToGetIssuerCertificate),
|
||||
QSslError(QSslError.SslError.UnableToDecryptCertificateSignature),
|
||||
lambda: QSslError(QSslError.SslError.UnableToGetIssuerCertificate),
|
||||
lambda: QSslError(QSslError.SslError.UnableToDecryptCertificateSignature),
|
||||
],
|
||||
[
|
||||
'<ul>',
|
||||
|
|
@ -37,13 +37,13 @@ class FakeError:
|
|||
),
|
||||
|
||||
(
|
||||
[FakeError('Escaping test: <>')],
|
||||
[lambda: FakeError('Escaping test: <>')],
|
||||
['<p>Escaping test: <></p>'],
|
||||
),
|
||||
(
|
||||
[
|
||||
FakeError('Escaping test 1: <>'),
|
||||
FakeError('Escaping test 2: <>'),
|
||||
lambda: FakeError('Escaping test 1: <>'),
|
||||
lambda: FakeError('Escaping test 2: <>'),
|
||||
],
|
||||
[
|
||||
'<ul>',
|
||||
|
|
@ -53,8 +53,9 @@ class FakeError:
|
|||
],
|
||||
),
|
||||
])
|
||||
def test_html(stubs, errors, expected):
|
||||
def test_html(stubs, error_factories, expected):
|
||||
reply = stubs.FakeNetworkReply(url=QUrl("https://example.com"))
|
||||
errors = [factory() for factory in error_factories]
|
||||
wrapper = certificateerror.CertificateErrorWrapper(reply=reply, errors=errors)
|
||||
lines = [line.strip() for line in wrapper.html().splitlines() if line.strip()]
|
||||
assert lines == expected
|
||||
|
|
|
|||
|
|
@ -1874,24 +1874,24 @@ class TestProxy:
|
|||
def klass(self):
|
||||
return configtypes.Proxy
|
||||
|
||||
@pytest.mark.parametrize('val, expected', [
|
||||
('system', configtypes.SYSTEM_PROXY),
|
||||
('none', QNetworkProxy(QNetworkProxy.ProxyType.NoProxy)),
|
||||
@pytest.mark.parametrize('val, expected_factory', [
|
||||
('system', lambda: configtypes.SYSTEM_PROXY),
|
||||
('none', lambda: QNetworkProxy(QNetworkProxy.ProxyType.NoProxy)),
|
||||
('socks://example.com/',
|
||||
QNetworkProxy(QNetworkProxy.ProxyType.Socks5Proxy, 'example.com')),
|
||||
lambda: QNetworkProxy(QNetworkProxy.ProxyType.Socks5Proxy, 'example.com')),
|
||||
('socks5://foo:bar@example.com:2323',
|
||||
QNetworkProxy(QNetworkProxy.ProxyType.Socks5Proxy, 'example.com', 2323,
|
||||
'foo', 'bar')),
|
||||
lambda: QNetworkProxy(
|
||||
QNetworkProxy.ProxyType.Socks5Proxy, 'example.com', 2323, 'foo', 'bar')),
|
||||
('pac+http://example.com/proxy.pac',
|
||||
pac.PACFetcher(QUrl('pac+http://example.com/proxy.pac'))),
|
||||
lambda: pac.PACFetcher(QUrl('pac+http://example.com/proxy.pac'))),
|
||||
('pac+file:///tmp/proxy.pac',
|
||||
pac.PACFetcher(QUrl('pac+file:///tmp/proxy.pac'))),
|
||||
lambda: pac.PACFetcher(QUrl('pac+file:///tmp/proxy.pac'))),
|
||||
])
|
||||
def test_to_py_valid(self, klass, val, expected):
|
||||
def test_to_py_valid(self, klass, val, expected_factory):
|
||||
actual = klass().to_py(val)
|
||||
if isinstance(actual, QNetworkProxy):
|
||||
actual = QNetworkProxy(actual)
|
||||
assert actual == expected
|
||||
assert actual == expected_factory()
|
||||
|
||||
@pytest.mark.parametrize('val', [
|
||||
'blah',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
# SPDX-FileCopyrightText: Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
"""Tests for qutebrowser.misc.crashsignal."""
|
||||
|
||||
import signal
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.config import configexc
|
||||
from qutebrowser.qt.widgets import QApplication
|
||||
from qutebrowser.misc import crashsignal, quitter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def read_config_mock(mocker):
|
||||
# covers reload_config
|
||||
mocker.patch.object(
|
||||
crashsignal.standarddir,
|
||||
"config_py",
|
||||
return_value="config.py-unittest",
|
||||
)
|
||||
return mocker.patch.object(
|
||||
crashsignal.configfiles,
|
||||
"read_config_py",
|
||||
autospec=True,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def signal_handler(qtbot, mocker, read_config_mock):
|
||||
"""Signal handler instance with all external methods mocked out."""
|
||||
# covers init
|
||||
mocker.patch.object(crashsignal.sys, "exit", autospec=True)
|
||||
signal_handler = crashsignal.SignalHandler(
|
||||
app=mocker.Mock(spec=QApplication),
|
||||
quitter=mocker.Mock(spec=quitter.Quitter),
|
||||
)
|
||||
|
||||
return signal_handler
|
||||
|
||||
|
||||
def test_handlers_registered(signal_handler):
|
||||
signal_handler.activate()
|
||||
|
||||
for sig, handler in signal_handler._handlers.items():
|
||||
registered = signal.signal(sig, signal.SIG_DFL)
|
||||
assert registered == handler
|
||||
|
||||
|
||||
def test_handlers_deregistered(signal_handler):
|
||||
known_handler = lambda *_args: None
|
||||
for sig in signal_handler._handlers:
|
||||
signal.signal(sig, known_handler)
|
||||
|
||||
signal_handler.activate()
|
||||
signal_handler.deactivate()
|
||||
|
||||
for sig in signal_handler._handlers:
|
||||
registered = signal.signal(sig, signal.SIG_DFL)
|
||||
assert registered == known_handler
|
||||
|
||||
|
||||
def test_interrupt_repeatedly(signal_handler):
|
||||
signal_handler.activate()
|
||||
test_signal = signal.SIGINT
|
||||
|
||||
expected_handlers = [
|
||||
signal_handler.interrupt,
|
||||
signal_handler.interrupt_forcefully,
|
||||
signal_handler.interrupt_really_forcefully,
|
||||
]
|
||||
|
||||
# Call the SIGINT handler multiple times and make sure it calls the
|
||||
# expected sequence of functions.
|
||||
for expected in expected_handlers:
|
||||
registered = signal.signal(test_signal, signal.SIG_DFL)
|
||||
assert registered == expected
|
||||
expected(test_signal, None)
|
||||
|
||||
|
||||
@pytest.mark.posix
|
||||
def test_reload_config_call_on_hup(signal_handler, read_config_mock):
|
||||
signal_handler._handlers[signal.SIGHUP](None, None)
|
||||
|
||||
read_config_mock.assert_called_once_with("config.py-unittest")
|
||||
|
||||
|
||||
@pytest.mark.posix
|
||||
def test_reload_config_displays_errors(signal_handler, read_config_mock, mocker):
|
||||
read_config_mock.side_effect = configexc.ConfigFileErrors(
|
||||
"config.py",
|
||||
[
|
||||
configexc.ConfigErrorDesc("no config.py", ValueError("asdf"))
|
||||
]
|
||||
)
|
||||
message_mock = mocker.patch.object(crashsignal.message, "error")
|
||||
|
||||
signal_handler._handlers[signal.SIGHUP](None, None)
|
||||
|
||||
message_mock.assert_called_once_with(
|
||||
"Errors occurred while reading config.py:\n no config.py: asdf"
|
||||
)
|
||||
|
|
@ -208,6 +208,18 @@ def test_ensure_valid(obj, raising, exc_reason, exc_str):
|
|||
"The data stream has read corrupt data."),
|
||||
(QDataStream.Status.WriteFailed, True,
|
||||
"The data stream cannot write to the underlying device."),
|
||||
pytest.param(
|
||||
getattr(QDataStream.Status, "SizeLimitExceeded", None),
|
||||
True,
|
||||
(
|
||||
"The data stream cannot read or write the data because its size is larger "
|
||||
"than supported by the current platform."
|
||||
),
|
||||
marks=pytest.mark.skipif(
|
||||
not hasattr(QDataStream.Status, "SizeLimitExceeded"),
|
||||
reason="Added in Qt 6.7"
|
||||
)
|
||||
),
|
||||
])
|
||||
def test_check_qdatastream(status, raising, message):
|
||||
"""Test check_qdatastream.
|
||||
|
|
@ -226,10 +238,25 @@ def test_check_qdatastream(status, raising, message):
|
|||
qtutils.check_qdatastream(stream)
|
||||
|
||||
|
||||
def test_qdatastream_status_count():
|
||||
"""Make sure no new members are added to QDataStream.Status."""
|
||||
status_vals = testutils.enum_members(QDataStream, QDataStream.Status)
|
||||
assert len(status_vals) == 4
|
||||
def test_qdatastream_status_members():
|
||||
"""Make sure no new members are added to QDataStream.Status.
|
||||
|
||||
If this fails, qtutils.check_qdatastream will need to be updated with the
|
||||
respective error documentation.
|
||||
"""
|
||||
status_vals = set(testutils.enum_members(QDataStream, QDataStream.Status).values())
|
||||
expected = {
|
||||
QDataStream.Status.Ok,
|
||||
QDataStream.Status.ReadPastEnd,
|
||||
QDataStream.Status.ReadCorruptData,
|
||||
QDataStream.Status.WriteFailed,
|
||||
}
|
||||
try:
|
||||
expected.add(QDataStream.Status.SizeLimitExceeded)
|
||||
except AttributeError:
|
||||
# Added in Qt 6.7
|
||||
pass
|
||||
assert status_vals == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize('color, expected', [
|
||||
|
|
|
|||
|
|
@ -915,6 +915,17 @@ class TestWebEngineVersions:
|
|||
source='faked'),
|
||||
"QtWebEngine 5.15.2, based on Chromium 87.0.4280.144 (from faked)",
|
||||
),
|
||||
(
|
||||
version.WebEngineVersions(
|
||||
webengine=utils.VersionNumber(5, 15, 2),
|
||||
chromium='87.0.4280.144',
|
||||
chromium_security='9000.1',
|
||||
source='faked'),
|
||||
(
|
||||
"QtWebEngine 5.15.2, based on Chromium 87.0.4280.144, with security "
|
||||
"patches up to 9000.1 (plus any distribution patches) (from faked)"
|
||||
),
|
||||
),
|
||||
])
|
||||
def test_str(self, version, expected):
|
||||
assert str(version) == expected
|
||||
|
|
@ -1024,6 +1035,20 @@ class TestWebEngineVersions:
|
|||
|
||||
assert inferred == real
|
||||
|
||||
def test_real_chromium_security_version(self, qapp):
|
||||
"""Check the API for reading the chromium security patch version."""
|
||||
try:
|
||||
from qutebrowser.qt.webenginecore import (
|
||||
qWebEngineChromiumVersion,
|
||||
qWebEngineChromiumSecurityPatchVersion,
|
||||
)
|
||||
except ImportError:
|
||||
pytest.skip("Requires QtWebEngine 6.3+")
|
||||
|
||||
base = utils.VersionNumber.parse(qWebEngineChromiumVersion())
|
||||
security = utils.VersionNumber.parse(qWebEngineChromiumSecurityPatchVersion())
|
||||
assert security >= base
|
||||
|
||||
|
||||
class FakeQSslSocket:
|
||||
|
||||
|
|
|
|||
6
tox.ini
6
tox.ini
|
|
@ -16,8 +16,6 @@ setenv =
|
|||
pyqt{515,5152}: PYTEST_QT_API=pyqt5
|
||||
pyqt{515,5152}: QUTE_QT_WRAPPER=PyQt5
|
||||
cov: PYTEST_ADDOPTS=--cov --cov-report xml --cov-report=html --cov-report=
|
||||
py312: VIRTUALENV_PIP=23.2
|
||||
py312: PIP_REQUIRE_VIRTUALENV=0
|
||||
passenv =
|
||||
PYTHON
|
||||
DISPLAY
|
||||
|
|
@ -71,8 +69,8 @@ setenv =
|
|||
pip_pre = true
|
||||
deps = -r{toxinidir}/misc/requirements/requirements-tests-bleeding.txt
|
||||
commands_pre =
|
||||
qt5: pip install --extra-index-url https://www.riverbankcomputing.com/pypi/simple/ --pre --upgrade PyQt5 PyQtWebEngine PyQt5-Qt5 PyQtWebEngine-Qt5 PyQt5-sip
|
||||
!qt5: pip install --extra-index-url https://www.riverbankcomputing.com/pypi/simple/ --pre --upgrade PyQt6 PyQt6-WebEngine PyQt6-Qt6 PyQt6-WebEngine-Qt6 PyQt6-sip
|
||||
qt5: pip install --extra-index-url https://www.riverbankcomputing.com/pypi/simple/ --pre --upgrade --only-binary PyQt5,PyQtWebEngine PyQt5 PyQtWebEngine PyQt5-Qt5 PyQtWebEngine-Qt5 PyQt5-sip
|
||||
!qt5: pip install --extra-index-url https://www.riverbankcomputing.com/pypi/simple/ --pre --upgrade --only-binary PyQt6,PyQt6-WebEngine PyQt6 PyQt6-WebEngine PyQt6-Qt6 PyQt6-WebEngine-Qt6 PyQt6-sip
|
||||
commands = {envpython} -bb -m pytest {posargs:tests}
|
||||
|
||||
# other envs
|
||||
|
|
|
|||
Loading…
Reference in New Issue