summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngrid <36052282+twigleingrid@users.noreply.github.com>2021-11-05 16:07:21 +0100
committerGitHub <noreply@github.com>2021-11-05 16:07:21 +0100
commitdf31ffd570c09bee4f388af7e611705ffb137019 (patch)
treeac5cdf74c2ccea6d37a53184861d9dd92bfed869
parent2767bc1a54410ab6f9437ec037dd3602c4483fe6 (diff)
parentdafe9f6966132ae48b16347538a6210ca1010f6c (diff)
downloadqutebrowser-df31ffd570c09bee4f388af7e611705ffb137019.tar.gz
qutebrowser-df31ffd570c09bee4f388af7e611705ffb137019.zip
Merge branch 'qutebrowser:master' into settings-frontend-new-css
-rw-r--r--.bumpversion.cfg2
-rw-r--r--.gitignore1
-rw-r--r--doc/changelog.asciidoc32
-rw-r--r--doc/help/configuring.asciidoc1
-rw-r--r--doc/help/settings.asciidoc2
-rw-r--r--doc/qutebrowser.1.asciidoc3
-rwxr-xr-xmisc/nsis/install.nsh3
-rw-r--r--misc/org.qutebrowser.qutebrowser.appdata.xml1
-rw-r--r--misc/org.qutebrowser.qutebrowser.desktop2
-rw-r--r--misc/requirements/requirements-check-manifest.txt6
-rw-r--r--misc/requirements/requirements-dev.txt20
-rw-r--r--misc/requirements/requirements-flake8.txt10
-rw-r--r--misc/requirements/requirements-mypy.txt10
-rw-r--r--misc/requirements/requirements-pyinstaller.txt2
-rw-r--r--misc/requirements/requirements-pylint.txt12
-rw-r--r--misc/requirements/requirements-pyqt-5.15.txt4
-rw-r--r--misc/requirements/requirements-pyqt-pyinstaller.txt7
-rw-r--r--misc/requirements/requirements-pyqt-pyinstaller.txt-raw2
-rw-r--r--misc/requirements/requirements-pyqt.txt4
-rw-r--r--misc/requirements/requirements-pyroma.txt8
-rw-r--r--misc/requirements/requirements-sphinx.txt10
-rw-r--r--misc/requirements/requirements-tests-bleeding.txt2
-rw-r--r--misc/requirements/requirements-tests.txt26
-rw-r--r--misc/requirements/requirements-tests.txt-raw3
-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/webengine/notification.py4
-rw-r--r--qutebrowser/config/configdata.yml15
-rw-r--r--qutebrowser/extensions/loader.py36
-rw-r--r--qutebrowser/misc/earlyinit.py14
-rw-r--r--qutebrowser/misc/guiprocess.py6
-rw-r--r--qutebrowser/qutebrowser.py25
-rw-r--r--qutebrowser/utils/resources.py2
-rw-r--r--qutebrowser/utils/utils.py7
-rw-r--r--requirements.txt6
-rwxr-xr-xscripts/dev/build_release.py2
-rw-r--r--scripts/dev/recompile_requirements.py6
-rw-r--r--tests/unit/extensions/test_loader.py8
-rw-r--r--tests/unit/misc/test_guiprocess.py14
-rw-r--r--tests/unit/test_qutebrowser.py60
-rw-r--r--tests/unit/utils/test_urlmatch.py157
-rw-r--r--tests/unit/utils/test_utils.py5
-rw-r--r--tox.ini2
44 files changed, 371 insertions, 185 deletions
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index e1e31afc5..cf1c019f7 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 2.3.1
+current_version = 2.4.0
commit = True
message = Release v{new_version}
tag = True
diff --git a/.gitignore b/.gitignore
index 31c4ca3b7..ccfc12ccb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,6 +49,7 @@ TODO
/scripts/testbrowser/cpp/webengine/testbrowser
/scripts/testbrowser/cpp/webengine/.qmake.stash
/scripts/dev/pylint_checkers/qute_pylint.egg-info
+/scripts/dev/pylint_checkers/build
/misc/file_version_info.txt
/doc/extapi/_build
/misc/nsis/include
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index c17f35eec..f86b84622 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -15,10 +15,40 @@ breaking changes (such as renamed commands) can happen in minor releases.
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
+[[v2.5.0]]
+v2.5.0 (unreleased)
+-------------------
+
+Changed
+~~~~~~~
+
+- Improved message if a spawned process wasn't found and a Flatpak container is
+ in use.
+
+[[v2.4.1]]
+v2.4.1 (unreleased)
+-------------------
+
+Fixed
+~~~~~
+
+- Speculative fix for an immediate crash at start with the macOS/Windows
+ binaries (in certain rare environments).
+- Speculative fix for a qutebrowser crash when the notification daemon crashes
+ while showing the notification.
+
[[v2.4.0]]
-v2.4.0 (unreleased)
+v2.4.0 (2021-10-21)
-------------------
+Security
+~~~~~~~~
+
+- **CVE-2021-41146**: Fix arbitrary command execution on Windows via URL handler
+ argument injection. See the
+ https://github.com/qutebrowser/qutebrowser/security/advisories/GHSA-vw27-fwjf-5qxm[security advisory]
+ for details.
+
Added
~~~~~
diff --git a/doc/help/configuring.asciidoc b/doc/help/configuring.asciidoc
index 23894ddc4..552145023 100644
--- a/doc/help/configuring.asciidoc
+++ b/doc/help/configuring.asciidoc
@@ -412,6 +412,7 @@ Pre-built colorschemes
- https://github.com/dracula/qutebrowser-dracula-theme[Dracula]
- https://gitlab.com/lovetocode999/selenized-qutebrowser[Selenized]
- https://github.com/morhetz/gruvbox[gruvbox]: https://github.com/The-Compiler/dotfiles/blob/master/qutebrowser/gruvbox.py[The-Compiler], https://gitlab.com/shaneyost/dots-popos-september-2020/-/blob/master/qutebrowser/config.py[Shane Yost]
+- https://www.opencode.net/wakellor957/qb-breath/-/blob/main/qb-breath.py[Manjaro Breath-like]
Avoiding flake8 errors
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc
index 18dfebc5d..60c229078 100644
--- a/doc/help/settings.asciidoc
+++ b/doc/help/settings.asciidoc
@@ -2669,7 +2669,7 @@ Default: +pass:[false]+
=== content.proxy
Proxy to use.
In addition to the listed values, you can use a `socks://...` or `http://...` URL.
-Note that with QtWebEngine, it will take a couple of seconds until the change is applied, if this value is changed at runtime.
+Note that with QtWebEngine, it will take a couple of seconds until the change is applied, if this value is changed at runtime. Authentication for SOCKS proxies isn't supported due to Chromium limitations.
Type: <<types,Proxy>>
diff --git a/doc/qutebrowser.1.asciidoc b/doc/qutebrowser.1.asciidoc
index 8db231add..bc312f108 100644
--- a/doc/qutebrowser.1.asciidoc
+++ b/doc/qutebrowser.1.asciidoc
@@ -65,6 +65,9 @@ show it.
*--desktop-file-name* 'DESKTOP_FILE_NAME'::
Set the base name of the desktop entry for this application. Used to set the app_id under Wayland. See https://doc.qt.io/qt-5/qguiapplication.html#desktopFileName-prop
+*--untrusted-args*::
+ Mark all following arguments as untrusted, which enforces that they are URLs/search terms (and not flags or commands)
+
=== debug arguments
*-l* '{critical,error,warning,info,debug,vdebug}', *--loglevel* '{critical,error,warning,info,debug,vdebug}'::
Override the configured console loglevel
diff --git a/misc/nsis/install.nsh b/misc/nsis/install.nsh
index f29a0a9a8..9f0cdf446 100755
--- a/misc/nsis/install.nsh
+++ b/misc/nsis/install.nsh
@@ -351,13 +351,12 @@ Section "Register with Windows" SectionWindowsRegister
!insertmacro UpdateRegDWORD SHCTX "SOFTWARE\Classes\$2" "EditFlags" 0x00000002
!insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\DefaultIcon" "" "$1,0"
!insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\shell" "" "open"
- !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\shell\open\command" "" "$\"$1$\" $\"%1$\""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\shell\open\command" "" "$\"$1$\" --untrusted-args $\"%1$\""
!insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\shell\open\ddeexec" "" ""
StrCmp $2 "${PRODUCT_NAME}HTML" 0 +4
StrCpy $2 "${PRODUCT_NAME}URL"
StrCpy $3 "${PRODUCT_NAME} URL"
Goto WriteRegHandler
- !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2" "URL Protocol" ""
${endif}
SectionEnd
diff --git a/misc/org.qutebrowser.qutebrowser.appdata.xml b/misc/org.qutebrowser.qutebrowser.appdata.xml
index 7c382cbb3..9930514d0 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="2.4.0" date="2021-10-21"/>
<release version="2.3.1" date="2021-07-28"/>
<release version="2.3.0" date="2021-06-28"/>
<release version="2.2.3" date="2021-06-01"/>
diff --git a/misc/org.qutebrowser.qutebrowser.desktop b/misc/org.qutebrowser.qutebrowser.desktop
index 52144b3c5..d999496ee 100644
--- a/misc/org.qutebrowser.qutebrowser.desktop
+++ b/misc/org.qutebrowser.qutebrowser.desktop
@@ -45,7 +45,7 @@ Comment[it]= Un browser web vim-like utilizzabile da tastiera basato su PyQt5
Icon=qutebrowser
Type=Application
Categories=Network;WebBrowser;
-Exec=qutebrowser %u
+Exec=qutebrowser --untrusted-args %u
Terminal=false
StartupNotify=true
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/qute;
diff --git a/misc/requirements/requirements-check-manifest.txt b/misc/requirements/requirements-check-manifest.txt
index 9a783f8b2..21843c4ae 100644
--- a/misc/requirements/requirements-check-manifest.txt
+++ b/misc/requirements/requirements-check-manifest.txt
@@ -2,8 +2,8 @@
build==0.7.0
check-manifest==0.47
-packaging==21.0
-pep517==0.11.0
+packaging==21.2
+pep517==0.12.0
pyparsing==2.4.7
toml==0.10.2
-tomli==1.2.1
+tomli==1.2.2
diff --git a/misc/requirements/requirements-dev.txt b/misc/requirements/requirements-dev.txt
index 391106422..088604a77 100644
--- a/misc/requirements/requirements-dev.txt
+++ b/misc/requirements/requirements-dev.txt
@@ -1,26 +1,26 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
bump2version==1.0.1
-certifi==2021.5.30
-cffi==1.14.6
-charset-normalizer==2.0.6
+certifi==2021.10.8
+cffi==1.15.0
+charset-normalizer==2.0.7
cryptography==35.0.0
Deprecated==1.2.13
-github3.py==2.0.0
+github3.py==3.0.0
hunter==3.3.8
-idna==3.2
+idna==3.3
jwcrypto==1.0
manhole==1.8.0
-packaging==21.0
+packaging==21.2
pycparser==2.20
Pympler==0.9
pyparsing==2.4.7
-PyQt-builder==1.11.0
+PyQt-builder==1.12.2
python-dateutil==2.8.2
requests==2.26.0
-sip==6.2.0
+sip==6.4.0
six==1.16.0
toml==0.10.2
-uritemplate==3.0.1
+uritemplate==4.1.1
# urllib3==1.26.7
-wrapt==1.12.1
+wrapt==1.13.3
diff --git a/misc/requirements/requirements-flake8.txt b/misc/requirements/requirements-flake8.txt
index 7a39fba32..08b75e2bf 100644
--- a/misc/requirements/requirements-flake8.txt
+++ b/misc/requirements/requirements-flake8.txt
@@ -1,10 +1,10 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
attrs==21.2.0
-flake8==3.9.2
+flake8==4.0.1
flake8-bugbear==21.9.2
flake8-builtins==1.5.3
-flake8-comprehensions==3.6.1
+flake8-comprehensions==3.7.0
flake8-copyright==0.2.2
flake8-debugger==4.0.0
flake8-deprecated==1.3
@@ -13,12 +13,12 @@ flake8-future-import==0.4.6
flake8-mock==0.3
flake8-polyfill==1.0.2
flake8-string-format==0.3.0
-flake8-tidy-imports==4.4.1
+flake8-tidy-imports==4.5.0
flake8-tuple==0.4.1
mccabe==0.6.1
pep8-naming==0.12.1
-pycodestyle==2.7.0
+pycodestyle==2.8.0
pydocstyle==6.1.1
-pyflakes==2.3.1
+pyflakes==2.4.0
six==1.16.0
snowballstemmer==2.1.0
diff --git a/misc/requirements/requirements-mypy.txt b/misc/requirements/requirements-mypy.txt
index 4732fed81..5aa36d659 100644
--- a/misc/requirements/requirements-mypy.txt
+++ b/misc/requirements/requirements-mypy.txt
@@ -1,11 +1,11 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
chardet==4.0.0
-diff-cover==6.4.1
+diff-cover==6.4.2
importlib-metadata==4.8.1
-importlib-resources==5.2.2
+importlib-resources==5.4.0
inflect==5.3.0
-Jinja2==3.0.1
+Jinja2==3.0.2
jinja2-pluralize==0.3.0
lxml==4.6.3
MarkupSafe==2.0.1
@@ -15,7 +15,7 @@ pluggy==1.0.0
Pygments==2.10.0
PyQt5-stubs==5.15.2.0
toml==0.10.2
-types-dataclasses==0.1.7
-types-PyYAML==5.4.10
+types-dataclasses==0.6.1
+types-PyYAML==6.0.0
typing-extensions==3.10.0.2
zipp==3.6.0
diff --git a/misc/requirements/requirements-pyinstaller.txt b/misc/requirements/requirements-pyinstaller.txt
index 81b66393b..8d5567e67 100644
--- a/misc/requirements/requirements-pyinstaller.txt
+++ b/misc/requirements/requirements-pyinstaller.txt
@@ -1,5 +1,5 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
altgraph==0.17.2
-pyinstaller==4.5.1
+pyinstaller==4.6
pyinstaller-hooks-contrib==2021.3
diff --git a/misc/requirements/requirements-pylint.txt b/misc/requirements/requirements-pylint.txt
index 26e07b878..abc6c2812 100644
--- a/misc/requirements/requirements-pylint.txt
+++ b/misc/requirements/requirements-pylint.txt
@@ -1,14 +1,14 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
astroid==2.3.3 # rq.filter: < 2.4
-certifi==2021.5.30
-cffi==1.14.6
-charset-normalizer==2.0.6
+certifi==2021.10.8
+cffi==1.15.0
+charset-normalizer==2.0.7
cryptography==35.0.0
Deprecated==1.2.13
future==0.18.2
-github3.py==2.0.0
-idna==3.2
+github3.py==3.0.0
+idna==3.3
isort==4.3.21
jwcrypto==1.0
lazy-object-proxy==1.4.3
@@ -21,6 +21,6 @@ python-dateutil==2.8.2
requests==2.26.0
six==1.16.0
typed-ast==1.4.3 ; python_version<"3.8"
-uritemplate==3.0.1
+uritemplate==4.1.1
# urllib3==1.26.7
wrapt==1.11.2
diff --git a/misc/requirements/requirements-pyqt-5.15.txt b/misc/requirements/requirements-pyqt-5.15.txt
index 8b7a53c44..3a3110c8b 100644
--- a/misc/requirements/requirements-pyqt-5.15.txt
+++ b/misc/requirements/requirements-pyqt-5.15.txt
@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-PyQt5==5.15.4 # rq.filter: < 5.16
+PyQt5==5.15.6 # rq.filter: < 5.16
PyQt5-Qt5==5.15.2
PyQt5-sip==12.9.0
-PyQtWebEngine==5.15.4 # rq.filter: < 5.16
+PyQtWebEngine==5.15.5 # rq.filter: < 5.16
PyQtWebEngine-Qt5==5.15.2
diff --git a/misc/requirements/requirements-pyqt-pyinstaller.txt b/misc/requirements/requirements-pyqt-pyinstaller.txt
deleted file mode 100644
index 678a1d7ea..000000000
--- a/misc/requirements/requirements-pyqt-pyinstaller.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file is automatically generated by scripts/dev/recompile_requirements.py
-
-PyQt5==5.15.3
-PyQt5-Qt==5.15.2
-PyQt5-sip==12.9.0
-PyQtWebEngine==5.15.3
-PyQtWebEngine-Qt==5.15.2
diff --git a/misc/requirements/requirements-pyqt-pyinstaller.txt-raw b/misc/requirements/requirements-pyqt-pyinstaller.txt-raw
deleted file mode 100644
index 89b5644da..000000000
--- a/misc/requirements/requirements-pyqt-pyinstaller.txt-raw
+++ /dev/null
@@ -1,2 +0,0 @@
-PyQt5==5.15.3
-PyQtWebEngine==5.15.3
diff --git a/misc/requirements/requirements-pyqt.txt b/misc/requirements/requirements-pyqt.txt
index 75ef27bf4..3953d27b3 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
-PyQt5==5.15.4
+PyQt5==5.15.6
PyQt5-Qt5==5.15.2
PyQt5-sip==12.9.0
-PyQtWebEngine==5.15.4
+PyQtWebEngine==5.15.5
PyQtWebEngine-Qt5==5.15.2
diff --git a/misc/requirements/requirements-pyroma.txt b/misc/requirements/requirements-pyroma.txt
index 77badd53c..8849014be 100644
--- a/misc/requirements/requirements-pyroma.txt
+++ b/misc/requirements/requirements-pyroma.txt
@@ -1,9 +1,9 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-certifi==2021.5.30
-charset-normalizer==2.0.6
-docutils==0.17.1
-idna==3.2
+certifi==2021.10.8
+charset-normalizer==2.0.7
+docutils==0.18
+idna==3.3
Pygments==2.10.0
pyroma==3.2
requests==2.26.0
diff --git a/misc/requirements/requirements-sphinx.txt b/misc/requirements/requirements-sphinx.txt
index 88d56b677..86553bb4c 100644
--- a/misc/requirements/requirements-sphinx.txt
+++ b/misc/requirements/requirements-sphinx.txt
@@ -2,14 +2,14 @@
alabaster==0.7.12
Babel==2.9.1
-certifi==2021.5.30
-charset-normalizer==2.0.6
+certifi==2021.10.8
+charset-normalizer==2.0.7
docutils==0.17.1
-idna==3.2
+idna==3.3
imagesize==1.2.0
-Jinja2==3.0.1
+Jinja2==3.0.2
MarkupSafe==2.0.1
-packaging==21.0
+packaging==21.2
Pygments==2.10.0
pyparsing==2.4.7
pytz==2021.3
diff --git a/misc/requirements/requirements-tests-bleeding.txt b/misc/requirements/requirements-tests-bleeding.txt
index 49911c48d..d2a7fcfb6 100644
--- a/misc/requirements/requirements-tests-bleeding.txt
+++ b/misc/requirements/requirements-tests-bleeding.txt
@@ -9,7 +9,7 @@ git+https://github.com/HypothesisWorks/hypothesis.git#subdirectory=hypothesis-py
git+https://github.com/pytest-dev/pytest.git
# Problematic: https://github.com/pytest-dev/pytest-bdd/issues/447
# git+https://github.com/pytest-dev/pytest-bdd.git
-pytest-bdd
+pytest-bdd<5
git+https://github.com/ionelmc/pytest-benchmark.git
git+https://github.com/pytest-dev/pytest-instafail.git
git+https://github.com/pytest-dev/pytest-mock.git
diff --git a/misc/requirements/requirements-tests.txt b/misc/requirements/requirements-tests.txt
index b61eab6a8..23fb69402 100644
--- a/misc/requirements/requirements-tests.txt
+++ b/misc/requirements/requirements-tests.txt
@@ -2,29 +2,29 @@
attrs==21.2.0
beautifulsoup4==4.10.0
-certifi==2021.5.30
-charset-normalizer==2.0.6
+certifi==2021.10.8
+charset-normalizer==2.0.7
cheroot==8.5.2
-click==8.0.1
-coverage==6.0
+click==8.0.3
+coverage==6.1.1
EasyProcess==0.3
execnet==1.9.0
-filelock==3.3.0
-Flask==2.0.1
+filelock==3.3.2
+Flask==2.0.2
glob2==0.7
hunter==3.3.8
-hypothesis==6.23.1
+hypothesis==6.24.1
icdiff==2.0.4
-idna==3.2
+idna==3.3
iniconfig==1.1.1
itsdangerous==2.0.1
-jaraco.functools==3.3.0
-# Jinja2==3.0.1
+jaraco.functools==3.4.0
+# Jinja2==3.0.2
Mako==1.1.5
manhole==1.8.0
# MarkupSafe==2.0.1
more-itertools==8.10.0
-packaging==21.0
+packaging==21.2
parse==1.19.0
parse-type==0.5.2
pluggy==1.0.0
@@ -54,7 +54,7 @@ sortedcontainers==2.4.0
soupsieve==2.2.1
tldextract==3.1.2
toml==0.10.2
-tomli==1.2.1
+tomli==1.2.2
urllib3==1.26.7
vulture==2.3
-Werkzeug==2.0.1
+Werkzeug==2.0.2
diff --git a/misc/requirements/requirements-tests.txt-raw b/misc/requirements/requirements-tests.txt-raw
index ab580ac4b..5586a86ef 100644
--- a/misc/requirements/requirements-tests.txt-raw
+++ b/misc/requirements/requirements-tests.txt-raw
@@ -4,7 +4,8 @@ coverage
Flask
hypothesis
pytest
-pytest-bdd
+# https://github.com/pytest-dev/pytest-bdd/issues/447
+pytest-bdd<5
pytest-benchmark
pytest-instafail
pytest-mock
diff --git a/misc/requirements/requirements-tox.txt b/misc/requirements/requirements-tox.txt
index 4c1cfbe27..248c850c2 100644
--- a/misc/requirements/requirements-tox.txt
+++ b/misc/requirements/requirements-tox.txt
@@ -2,16 +2,16 @@
backports.entry-points-selectable==1.1.0
distlib==0.3.3
-filelock==3.3.0
-packaging==21.0
-pip==21.2.4
+filelock==3.3.2
+packaging==21.2
+pip==21.3.1
platformdirs==2.4.0
pluggy==1.0.0
py==1.10.0
pyparsing==2.4.7
-setuptools==58.2.0
+setuptools==58.4.0
six==1.16.0
toml==0.10.2
tox==3.24.4
-virtualenv==20.8.1
+virtualenv==20.9.0
wheel==0.37.0
diff --git a/misc/requirements/requirements-yamllint.txt b/misc/requirements/requirements-yamllint.txt
index 897184c74..12553f2b2 100644
--- a/misc/requirements/requirements-yamllint.txt
+++ b/misc/requirements/requirements-yamllint.txt
@@ -1,5 +1,5 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
pathspec==0.9.0
-PyYAML==5.4.1
+PyYAML==6.0
yamllint==1.26.3
diff --git a/qutebrowser/__init__.py b/qutebrowser/__init__.py
index 29a8e4836..c05215792 100644
--- a/qutebrowser/__init__.py
+++ b/qutebrowser/__init__.py
@@ -26,7 +26,7 @@ __copyright__ = "Copyright 2014-2021 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
-__version__ = "2.3.1"
+__version__ = "2.4.0"
__version_info__ = tuple(int(part) for part in __version__.split('.'))
__description__ = "A keyboard-driven, vim-like browser based on PyQt5."
diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py
index e40b3e736..f8e1a59b1 100644
--- a/qutebrowser/browser/webengine/notification.py
+++ b/qutebrowser/browser/webengine/notification.py
@@ -715,6 +715,10 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
# https://github.com/KDE/plasma-workspace/blob/v5.21.4/libnotificationmanager/server_p.cpp#L227-L237
# Created too many similar notifications in quick succession
"org.freedesktop.Notifications.Error.ExcessNotificationGeneration",
+
+ # From https://crashes.qutebrowser.org/view/b8c9838a - probably when
+ # notification daemon crashes?
+ "org.freedesktop.DBus.Error.Spawn.ChildSignaled",
}
def __init__(self, parent: QObject = None) -> None:
diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml
index a525e2426..e034fe8f5 100644
--- a/qutebrowser/config/configdata.yml
+++ b/qutebrowser/config/configdata.yml
@@ -679,14 +679,14 @@ content.headers.user_agent:
# Vim-protip: Place your cursor below this comment and run
# :r!python scripts/dev/ua_fetch.py
- - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
- like Gecko) Chrome/90.0.4430.93 Safari/537.36"
- - Chrome 90 Win10
+ like Gecko) Chrome/92.0.4515.131 Safari/537.36"
+ - Chrome 92 Win10
- - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
- (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
- - Chrome 90 macOS
+ (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
+ - Chrome 92 macOS
- - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like
- Gecko) Chrome/90.0.4430.93 Safari/537.36"
- - Chrome 90 Linux
+ Gecko) Chrome/92.0.4515.131 Safari/537.36"
+ - Chrome 92 Linux
supports_pattern: true
desc: |
User agent to send.
@@ -1060,7 +1060,8 @@ content.proxy:
`http://...` URL.
Note that with QtWebEngine, it will take a couple of seconds until the
- change is applied, if this value is changed at runtime.
+ change is applied, if this value is changed at runtime. Authentication for
+ SOCKS proxies isn't supported due to Chromium limitations.
content.proxy_dns_requests:
default: true
diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py
index 7ae45023b..c7b619b3e 100644
--- a/qutebrowser/extensions/loader.py
+++ b/qutebrowser/extensions/loader.py
@@ -21,12 +21,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 PyQt5.QtCore import pyqtSlot
@@ -95,18 +94,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 _on_walk_error(name: str) -> None:
- raise ImportError("Failed to import {}".format(name))
-
-
-def _walk_normal() -> Iterator[ExtensionInfo]:
- """Walk extensions when not using PyInstaller."""
for _finder, name, ispkg in pkgutil.walk_packages(
# Only packages have a __path__ attribute,
# but we're sure this is one.
@@ -123,23 +110,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 # type: ignore[union-attr]
- 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()),
@@ -190,3 +160,7 @@ def _on_config_changed(changed_name: str) -> None:
def init() -> None:
config.instance.changed.connect(_on_config_changed)
+
+
+def _on_walk_error(name: str) -> None:
+ raise ImportError("Failed to import {}".format(name))
diff --git a/qutebrowser/misc/earlyinit.py b/qutebrowser/misc/earlyinit.py
index c4ff0bb85..f27b7acfe 100644
--- a/qutebrowser/misc/earlyinit.py
+++ b/qutebrowser/misc/earlyinit.py
@@ -111,17 +111,23 @@ def init_faulthandler(fileobj=sys.__stderr__):
Args:
fobj: An opened file object to write the traceback to.
"""
- if fileobj is None:
+ try:
+ faulthandler.enable(fileobj)
+ except (RuntimeError, AttributeError):
# When run with pythonw.exe, sys.__stderr__ can be None:
# https://docs.python.org/3/library/sys.html#sys.__stderr__
- # If we'd enable faulthandler in that case, we just get a weird
- # exception, so we don't enable faulthandler if we have no stdout.
+ #
+ # With PyInstaller, it can be a NullWriter raising AttributeError on
+ # fileno: https://github.com/pyinstaller/pyinstaller/issues/4481
#
# Later when we have our data dir available we re-enable faulthandler
# to write to a file so we can display a crash to the user at the next
# start.
+ #
+ # Note that we don't have any logging initialized yet at this point, so
+ # this is a silent error.
return
- faulthandler.enable(fileobj)
+
if (hasattr(faulthandler, 'register') and hasattr(signal, 'SIGUSR1') and
sys.stderr is not None):
# If available, we also want a traceback on SIGUSR1.
diff --git a/qutebrowser/misc/guiprocess.py b/qutebrowser/misc/guiprocess.py
index e5ccd1b8b..c93fad09b 100644
--- a/qutebrowser/misc/guiprocess.py
+++ b/qutebrowser/misc/guiprocess.py
@@ -27,7 +27,7 @@ from typing import Mapping, Sequence, Dict, Optional
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, QObject, QProcess,
QProcessEnvironment, QByteArray, QUrl, Qt)
-from qutebrowser.utils import message, log, utils, usertypes
+from qutebrowser.utils import message, log, utils, usertypes, version
from qutebrowser.api import cmdutils, apitypes
from qutebrowser.completion.models import miscmodels
@@ -273,7 +273,9 @@ class GUIProcess(QObject):
known_errors = ['No such file or directory', 'Permission denied']
if (': ' in error_string and # pragma: no branch
error_string.split(': ', maxsplit=1)[1] in known_errors):
- msg += f'\n(Hint: Make sure {self.cmd!r} exists and is executable)'
+ msg += f'\nHint: Make sure {self.cmd!r} exists and is executable'
+ if version.is_flatpak():
+ msg += ' inside the Flatpak container'
message.error(msg)
diff --git a/qutebrowser/qutebrowser.py b/qutebrowser/qutebrowser.py
index d0819f832..c576c4a06 100644
--- a/qutebrowser/qutebrowser.py
+++ b/qutebrowser/qutebrowser.py
@@ -87,6 +87,11 @@ def get_argparser():
help="Set the base name of the desktop entry for this "
"application. Used to set the app_id under Wayland. See "
"https://doc.qt.io/qt-5/qguiapplication.html#desktopFileName-prop")
+ parser.add_argument('--untrusted-args',
+ action='store_true',
+ help="Mark all following arguments as untrusted, which "
+ "enforces that they are URLs/search terms (and not flags or "
+ "commands)")
parser.add_argument('--json-args', help=argparse.SUPPRESS)
parser.add_argument('--temp-basedir-restarted',
@@ -207,7 +212,27 @@ def _unpack_json_args(args):
return argparse.Namespace(**new_args)
+def _validate_untrusted_args(argv):
+ # NOTE: Do not use f-strings here, as this should run with older Python
+ # versions (so that a proper error can be displayed)
+ try:
+ untrusted_idx = argv.index('--untrusted-args')
+ except ValueError:
+ return
+
+ rest = argv[untrusted_idx + 1:]
+ if len(rest) > 1:
+ sys.exit(
+ "Found multiple arguments ({}) after --untrusted-args, "
+ "aborting.".format(' '.join(rest)))
+
+ for arg in rest:
+ if arg.startswith(('-', ':')):
+ sys.exit("Found {} after --untrusted-args, aborting.".format(arg))
+
+
def main():
+ _validate_untrusted_args(sys.argv)
parser = get_argparser()
argv = sys.argv[1:]
args = parser.parse_args(argv)
diff --git a/qutebrowser/utils/resources.py b/qutebrowser/utils/resources.py
index ff5ec9d9a..f561d6747 100644
--- a/qutebrowser/utils/resources.py
+++ b/qutebrowser/utils/resources.py
@@ -82,7 +82,7 @@ def _glob(
else: # zipfile.Path or importlib_resources compat object
# Unfortunately, we can't tell mypy about resource_path being of type
# Union[pathlib.Path, zipfile.Path] because we set "python_version = 3.6" in
- # .mypy.ini, but the zipfiel stubs (correctly) only declare zipfile.Path with
+ # .mypy.ini, but the zipfile stubs (correctly) only declare zipfile.Path with
# Python 3.8...
assert glob_path.is_dir(), glob_path # type: ignore[unreachable]
for subpath in glob_path.iterdir():
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index a56769255..f42515c5c 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -669,11 +669,12 @@ def yaml_load(f: Union[str, IO[str]]) -> Any:
r"of from 'collections\.abc' is deprecated.*"):
try:
data = yaml.load(f, Loader=YamlLoader)
- except ValueError as e:
- if str(e).startswith('could not convert string to float'):
+ except ValueError as e: # pragma: no cover
+ pyyaml_error = 'could not convert string to float'
+ if str(e).startswith(pyyaml_error):
# WORKAROUND for https://github.com/yaml/pyyaml/issues/168
raise yaml.YAMLError(e)
- raise # pragma: no cover
+ raise
end = datetime.datetime.now()
diff --git a/requirements.txt b/requirements.txt
index 01d49032a..0805ad6cc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,10 +4,10 @@ adblock==0.5.0
colorama==0.4.4
dataclasses==0.6 ; python_version<"3.7"
importlib-metadata==4.8.1 ; python_version<"3.8"
-importlib-resources==5.2.2 ; python_version<"3.9"
-Jinja2==3.0.1
+importlib-resources==5.4.0 ; python_version<"3.9"
+Jinja2==3.0.2
MarkupSafe==2.0.1
Pygments==2.10.0
-PyYAML==5.4.1
+PyYAML==6.0
typing-extensions==3.10.0.2
zipp==3.6.0
diff --git a/scripts/dev/build_release.py b/scripts/dev/build_release.py
index a1c6646eb..4961cbdc8 100755
--- a/scripts/dev/build_release.py
+++ b/scripts/dev/build_release.py
@@ -227,7 +227,7 @@ def patch_mac_app():
# Replace some duplicate files by symlinks
framework_path = os.path.join(app_path, 'Contents', 'MacOS', 'PyQt5',
- 'Qt', 'lib', 'QtWebEngineCore.framework')
+ 'Qt5', 'lib', 'QtWebEngineCore.framework')
core_lib = os.path.join(framework_path, 'Versions', '5', 'QtWebEngineCore')
os.remove(core_lib)
diff --git a/scripts/dev/recompile_requirements.py b/scripts/dev/recompile_requirements.py
index 6c9a6bcc9..c013346ae 100644
--- a/scripts/dev/recompile_requirements.py
+++ b/scripts/dev/recompile_requirements.py
@@ -81,7 +81,7 @@ CHANGELOG_URLS = {
'attrs': 'https://www.attrs.org/en/stable/changelog.html',
'Jinja2': 'https://jinja.palletsprojects.com/en/latest/changes/',
'MarkupSafe': 'https://markupsafe.palletsprojects.com/en/latest/changes/',
- 'flake8': 'https://gitlab.com/pycqa/flake8/tree/master/docs/source/release-notes',
+ 'flake8': 'https://github.com/PyCQA/flake8/tree/main/docs/source/release-notes',
'flake8-docstrings': 'https://pypi.org/project/flake8-docstrings/',
'flake8-debugger': 'https://github.com/JBKahn/flake8-debugger/',
'flake8-builtins': 'https://github.com/gforcada/flake8-builtins/blob/master/CHANGES.rst',
@@ -141,10 +141,8 @@ CHANGELOG_URLS = {
'toml': 'https://github.com/uiri/toml/releases',
'tomli': 'https://github.com/hukkin/tomli/blob/master/CHANGELOG.md',
'PyQt5': 'https://www.riverbankcomputing.com/news',
- 'PyQt5-Qt': 'https://www.riverbankcomputing.com/news',
'PyQt5-Qt5': 'https://www.riverbankcomputing.com/news',
'PyQtWebEngine': 'https://www.riverbankcomputing.com/news',
- 'PyQtWebEngine-Qt': 'https://www.riverbankcomputing.com/news',
'PyQtWebEngine-Qt5': 'https://www.riverbankcomputing.com/news',
'PyQt-builder': 'https://www.riverbankcomputing.com/news',
'PyQt5-sip': 'https://www.riverbankcomputing.com/news',
@@ -170,7 +168,7 @@ CHANGELOG_URLS = {
'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/commits/main',
+ 'filelock': 'https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst',
'github3.py': 'https://github3py.readthedocs.io/en/master/release-notes/index.html',
'manhole': 'https://github.com/ionelmc/python-manhole/blob/master/CHANGELOG.rst',
'pycparser': 'https://github.com/eliben/pycparser/blob/master/CHANGES',
diff --git a/tests/unit/extensions/test_loader.py b/tests/unit/extensions/test_loader.py
index feb5dd347..e9b8055aa 100644
--- a/tests/unit/extensions/test_loader.py
+++ b/tests/unit/extensions/test_loader.py
@@ -35,16 +35,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/tests/unit/misc/test_guiprocess.py b/tests/unit/misc/test_guiprocess.py
index be86bf215..faf2006de 100644
--- a/tests/unit/misc/test_guiprocess.py
+++ b/tests/unit/misc/test_guiprocess.py
@@ -26,7 +26,7 @@ import pytest
from PyQt5.QtCore import QProcess, QUrl
from qutebrowser.misc import guiprocess
-from qutebrowser.utils import usertypes, utils
+from qutebrowser.utils import usertypes, utils, version
from qutebrowser.api import cmdutils
from qutebrowser.qt import sip
@@ -394,8 +394,11 @@ def test_running(qtbot, proc, py_proc):
proc.outcome.was_successful()
-def test_failing_to_start(qtbot, proc, caplog, message_mock):
+@pytest.mark.parametrize('is_flatpak', [True, False])
+def test_failing_to_start(qtbot, proc, caplog, message_mock, monkeypatch, is_flatpak):
"""Test the process failing to start."""
+ monkeypatch.setattr(version, 'is_flatpak', lambda: is_flatpak)
+
with caplog.at_level(logging.ERROR, 'message'):
with qtbot.wait_signal(proc.error, timeout=5000):
proc.start('this_does_not_exist_either', [])
@@ -405,8 +408,11 @@ def test_failing_to_start(qtbot, proc, caplog, message_mock):
"Testprocess 'this_does_not_exist_either' failed to start:")
if not utils.is_windows:
- assert msg.text.endswith(
- "(Hint: Make sure 'this_does_not_exist_either' exists and is executable)")
+ expected_msg = (
+ "Hint: Make sure 'this_does_not_exist_either' exists and is executable")
+ if is_flatpak:
+ expected_msg += ' inside the Flatpak container'
+ assert msg.text.endswith(expected_msg)
assert not proc.outcome.running
assert proc.outcome.status is None
diff --git a/tests/unit/test_qutebrowser.py b/tests/unit/test_qutebrowser.py
index d9275631d..36b4065a1 100644
--- a/tests/unit/test_qutebrowser.py
+++ b/tests/unit/test_qutebrowser.py
@@ -22,6 +22,8 @@
(Mainly commandline flag parsing)
"""
+import re
+
import pytest
from qutebrowser import qutebrowser
@@ -75,3 +77,61 @@ class TestJsonArgs:
# pylint: disable=no-member
assert args.debug
assert not args.temp_basedir
+
+
+class TestValidateUntrustedArgs:
+
+ @pytest.mark.parametrize('args', [
+ [],
+ [':nop'],
+ [':nop', '--untrusted-args'],
+ [':nop', '--debug', '--untrusted-args'],
+ [':nop', '--untrusted-args', 'foo'],
+ ['--debug', '--untrusted-args', 'foo'],
+ ['foo', '--untrusted-args', 'bar'],
+ ])
+ def test_valid(self, args):
+ qutebrowser._validate_untrusted_args(args)
+
+ @pytest.mark.parametrize('args, message', [
+ (
+ ['--untrusted-args', '--debug'],
+ "Found --debug after --untrusted-args, aborting.",
+ ),
+ (
+ ['--untrusted-args', ':nop'],
+ "Found :nop after --untrusted-args, aborting.",
+ ),
+ (
+ ['--debug', '--untrusted-args', '--debug'],
+ "Found --debug after --untrusted-args, aborting.",
+ ),
+ (
+ [':nop', '--untrusted-args', '--debug'],
+ "Found --debug after --untrusted-args, aborting.",
+ ),
+ (
+ [':nop', '--untrusted-args', ':nop'],
+ "Found :nop after --untrusted-args, aborting.",
+ ),
+ (
+ [
+ ':nop',
+ '--untrusted-args',
+ ':nop',
+ '--untrusted-args',
+ 'https://www.example.org',
+ ],
+ (
+ "Found multiple arguments (:nop --untrusted-args "
+ "https://www.example.org) after --untrusted-args, aborting."
+ )
+ ),
+ (
+ ['--untrusted-args', 'okay1', 'okay2'],
+ "Found multiple arguments (okay1 okay2) after --untrusted-args, aborting.",
+ ),
+ ])
+ def test_invalid(self, args, message):
+ with pytest.raises(SystemExit, match=re.escape(message)):
+ qutebrowser._validate_untrusted_args(args)
diff --git a/tests/unit/utils/test_urlmatch.py b/tests/unit/utils/test_urlmatch.py
index 35ccc94fe..caf52c76d 100644
--- a/tests/unit/utils/test_urlmatch.py
+++ b/tests/unit/utils/test_urlmatch.py
@@ -37,24 +37,30 @@ from PyQt5.QtCore import QUrl
from qutebrowser.utils import urlmatch
+# pylint: disable=line-too-long
+
@pytest.mark.parametrize('pattern, error', [
### Chromium: kMissingSchemeSeparator
## TEST(ExtensionURLPatternTest, ParseInvalid)
# ("http", "No scheme given"),
- ("http:", "Invalid port: Port is empty"),
- ("http:/", "Invalid port: Port is empty"),
- ("about://", "Pattern without path"),
- ("http:/bar", "Invalid port: Port is empty"),
+ pytest.param("http:", "Invalid port: Port is empty", id='scheme-no-slash'),
+ pytest.param("http:/", "Invalid port: Port is empty", id='scheme-single-slash'),
+ pytest.param("about://", "Pattern without path", id='scheme-no-path'),
+ pytest.param(
+ "http:/bar",
+ "Invalid port: Port is empty",
+ id='scheme-single-slash-path',
+ ),
### Chromium: kEmptyHost
## TEST(ExtensionURLPatternTest, ParseInvalid)
- ("http://", "Pattern without host"),
- ("http:///", "Pattern without host"),
- ("http://:1234/", "Pattern without host"),
- ("http://*./", "Pattern without host"),
+ pytest.param("http://", "Pattern without host", id='host-double-slash'),
+ pytest.param("http:///", "Pattern without host", id='host-triple-slash'),
+ pytest.param("http://:1234/", "Pattern without host", id='host-port'),
+ pytest.param("http://*./", "Pattern without host", id='host-pattern'),
## TEST(ExtensionURLPatternTest, IPv6Patterns)
- ("http://[]:8888/*", "Pattern without host"),
+ pytest.param("http://[]:8888/*", "Pattern without host", id='host-ipv6'),
### Chromium: kEmptyPath
## TEST(ExtensionURLPatternTest, ParseInvalid)
@@ -63,53 +69,132 @@ from qutebrowser.utils import urlmatch
### Chromium: kInvalidHost
## TEST(ExtensionURLPatternTest, ParseInvalid)
- ("http://\0www/", "May not contain NUL byte"),
+ pytest.param("http://\0www/", "May not contain NUL byte", id='host-nul'),
## TEST(ExtensionURLPatternTest, IPv6Patterns)
# No closing bracket (`]`).
- ("http://[2607:f8b0:4005:805::200e/*", "Invalid IPv6 URL"),
+ pytest.param(
+ "http://[2607:f8b0:4005:805::200e/*",
+ "Invalid IPv6 URL",
+ id='host-ipv6-no-closing',
+ ),
# Two closing brackets (`]]`).
- pytest.param("http://[2607:f8b0:4005:805::200e]]/*", "Invalid IPv6 URL", marks=pytest.mark.xfail(reason="https://bugs.python.org/issue34360")),
+ pytest.param(
+ "http://[2607:f8b0:4005:805::200e]]/*",
+ "Invalid IPv6 URL",
+ marks=pytest.mark.xfail(reason="https://bugs.python.org/issue34360"),
+ id='host-ipv6-two-closing',
+ ),
# Two open brackets (`[[`).
- ("http://[[2607:f8b0:4005:805::200e]/*", r"""Expected '\]' to match '\[' in hostname; source was "\[2607:f8b0:4005:805::200e"; host = """""),
+ pytest.param(
+ "http://[[2607:f8b0:4005:805::200e]/*",
+ r"""Expected '\]' to match '\[' in hostname; source was "\[2607:f8b0:4005:805::200e"; host = """"",
+ id='host-ipv6-two-open',
+ ),
# Too few colons in the last chunk.
- ("http://[2607:f8b0:4005:805:200e]/*", 'Invalid IPv6 address; source was "2607:f8b0:4005:805:200e"; host = ""'),
+ pytest.param(
+ "http://[2607:f8b0:4005:805:200e]/*",
+ 'Invalid IPv6 address; source was "2607:f8b0:4005:805:200e"; host = ""',
+ id='host-ipv6-colons',
+ ),
# Non-hex piece.
- ("http://[2607:f8b0:4005:805:200e:12:bogus]/*", 'Invalid IPv6 address; source was "2607:f8b0:4005:805:200e:12:bogus"; host = ""'),
+ pytest.param(
+ "http://[2607:f8b0:4005:805:200e:12:bogus]/*",
+ 'Invalid IPv6 address; source was "2607:f8b0:4005:805:200e:12:bogus"; host = ""',
+ id='host-ipv6-non-hex',
+ ),
### Chromium: kInvalidHostWildcard
## TEST(ExtensionURLPatternTest, ParseInvalid)
- ("http://*foo/bar", "Invalid host wildcard"),
- ("http://foo.*.bar/baz", "Invalid host wildcard"),
- ("http://fo.*.ba:123/baz", "Invalid host wildcard"),
- ("http://foo.*/bar", "Invalid host wildcard"),
+ pytest.param("http://*foo/bar", "Invalid host wildcard", id='host-wildcard-no-dot'),
+ pytest.param(
+ "http://foo.*.bar/baz",
+ "Invalid host wildcard",
+ id='host-wildcard-middle',
+ ),
+ pytest.param(
+ "http://fo.*.ba:123/baz",
+ "Invalid host wildcard",
+ id='host-wildcard-middle-port',
+ ),
+ pytest.param("http://foo.*/bar", "Invalid host wildcard", id='host-wildcard-end'),
### Chromium: kInvalidPort
## TEST(ExtensionURLPatternTest, Ports)
- ("http://foo:/", "Invalid port: Port is empty"),
- ("http://*.foo:/", "Invalid port: Port is empty"),
- ("http://foo:com/", "Invalid port: .* 'com'"),
- ("http://foo:123456/", "Invalid port: Port out of range 0-65535"),
- ("http://foo:80:80/monkey", "Invalid port: .* '80:80'"),
- ("chrome://foo:1234/bar", "Ports are unsupported with chrome scheme"),
+ pytest.param("http://foo:/", "Invalid port: Port is empty", id='port-empty'),
+ pytest.param(
+ "http://*.foo:/",
+ "Invalid port: Port is empty",
+ id='port-empty-wildcard',
+ ),
+ pytest.param("http://foo:com/", "Invalid port: .* 'com'", id='port-alpha'),
+ pytest.param(
+ "http://foo:123456/",
+ "Invalid port: Port out of range 0-65535",
+ id='port-range',
+ ),
+ pytest.param(
+ "http://foo:80:80/monkey",
+ "Invalid port: .* '80:80'",
+ id='port-double',
+ ),
+ pytest.param(
+ "chrome://foo:1234/bar",
+ "Ports are unsupported with chrome scheme",
+ id='port-chrome',
+ ),
# No port specified, but port separator.
- ("http://[2607:f8b0:4005:805::200e]:/*", "Invalid port: Port is empty"),
+ pytest.param(
+ "http://[2607:f8b0:4005:805::200e]:/*",
+ "Invalid port: Port is empty",
+ id='port-empty-ipv6',
+ ),
### Additional tests
- ("http://[", "Invalid IPv6 URL"),
- ("http://[fc2e::bb88::edac]", 'Invalid IPv6 address; source was "fc2e::bb88::edac"; host = ""'),
- ("http://[fc2e:0e35:bb88::edac:fc2e:0e35:bb88:edac]", 'Invalid IPv6 address; source was "fc2e:0e35:bb88::edac:fc2e:0e35:bb88:edac"; host = ""'),
- ("http://[fc2e:0e35:bb88:af:edac:fc2e:0e35:bb88:edac]", 'Invalid IPv6 address; source was "fc2e:0e35:bb88:af:edac:fc2e:0e35:bb88:edac"; host = ""'),
- ("http://[127.0.0.1:fc2e::bb88:edac]", r'Invalid IPv6 address; source was "127\.0\.0\.1:fc2e::bb88:edac'),
- ("http://[fc2e::bb88", "Invalid IPv6 URL"),
- ("http://[fc2e:bb88:edac]", 'Invalid IPv6 address; source was "fc2e:bb88:edac"; host = ""'),
- ("http://[fc2e:bb88:edac::z]", 'Invalid IPv6 address; source was "fc2e:bb88:edac::z"; host = ""'),
- ("http://[fc2e:bb88:edac::2]:2a2", "Invalid port: .* '2a2'"),
- ("://", "Missing scheme"),
+ pytest.param("http://[", "Invalid IPv6 URL", id='ipv6-single-open'),
+ pytest.param(
+ "http://[fc2e::bb88::edac]",
+ 'Invalid IPv6 address; source was "fc2e::bb88::edac"; host = ""',
+ id='ipv6-double-double',
+ ),
+ pytest.param(
+ "http://[fc2e:0e35:bb88::edac:fc2e:0e35:bb88:edac]",
+ 'Invalid IPv6 address; source was "fc2e:0e35:bb88::edac:fc2e:0e35:bb88:edac"; host = ""',
+ id='ipv6-long-double',
+ ),
+ pytest.param(
+ "http://[fc2e:0e35:bb88:af:edac:fc2e:0e35:bb88:edac]",
+ 'Invalid IPv6 address; source was "fc2e:0e35:bb88:af:edac:fc2e:0e35:bb88:edac"; host = ""',
+ id='ipv6-long',
+ ),
+ pytest.param(
+ "http://[127.0.0.1:fc2e::bb88:edac]",
+ r'Invalid IPv6 address; source was "127\.0\.0\.1:fc2e::bb88:edac',
+ id='ipv6-ipv4',
+ ),
+ pytest.param("http://[fc2e::bb88", "Invalid IPv6 URL", id='ipv6-trailing'),
+ pytest.param(
+ "http://[fc2e:bb88:edac]",
+ 'Invalid IPv6 address; source was "fc2e:bb88:edac"; host = ""',
+ id='ipv6-short',
+ ),
+ pytest.param(
+ "http://[fc2e:bb88:edac::z]",
+ 'Invalid IPv6 address; source was "fc2e:bb88:edac::z"; host = ""',
+ id='ipv6-z',
+ ),
+ pytest.param(
+ "http://[fc2e:bb88:edac::2]:2a2",
+ "Invalid port: .* '2a2'",
+ id='ipv6-port',
+ ),
+ pytest.param("://", "Missing scheme", id='scheme-naked'),
])
def test_invalid_patterns(pattern, error):
with pytest.raises(urlmatch.ParseError, match=error):
urlmatch.UrlPattern(pattern)
+# pylint: enable=line-too-long
+
@pytest.mark.parametrize('host', ['.', ' ', ' .', '. ', '. .', '. . .', ' . '])
def test_whitespace_hosts(host):
diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py
index 57adc883c..330ef3b96 100644
--- a/tests/unit/utils/test_utils.py
+++ b/tests/unit/utils/test_utils.py
@@ -809,8 +809,11 @@ class TestYaml:
assert utils.yaml_load("[1, 2]") == [1, 2]
def test_load_float_bug(self):
- with pytest.raises(yaml.YAMLError):
+ try:
utils.yaml_load("._")
+ except yaml.YAMLError:
+ # Either no exception or YAMLError, not ValueError
+ pass
def test_load_file(self, tmp_path):
tmpfile = tmp_path / 'foo.yml'
diff --git a/tox.ini b/tox.ini
index 4be5b8620..271bf4241 100644
--- a/tox.ini
+++ b/tox.ini
@@ -160,7 +160,7 @@ passenv = APPDATA HOME PYINSTALLER_DEBUG
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/misc/requirements/requirements-pyinstaller.txt
- -r{toxinidir}/misc/requirements/requirements-pyqt-pyinstaller.txt
+ -r{toxinidir}/misc/requirements/requirements-pyqt.txt
commands =
{envbindir}/pyinstaller --noconfirm misc/qutebrowser.spec