summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.asciidoc9
-rw-r--r--doc/changelog.asciidoc8
-rw-r--r--misc/requirements/requirements-dev.txt10
-rw-r--r--misc/requirements/requirements-flake8.txt6
-rw-r--r--misc/requirements/requirements-mypy.txt6
-rw-r--r--misc/requirements/requirements-pylint.txt8
-rw-r--r--misc/requirements/requirements-pyroma.txt2
-rw-r--r--misc/requirements/requirements-sphinx.txt4
-rw-r--r--misc/requirements/requirements-tests.txt8
-rw-r--r--misc/requirements/requirements-tox.txt8
-rw-r--r--misc/requirements/requirements-yamllint.txt2
-rw-r--r--qutebrowser/api/cmdutils.py31
-rw-r--r--qutebrowser/browser/webengine/interceptor.py7
-rw-r--r--qutebrowser/browser/webengine/notification.py14
-rw-r--r--qutebrowser/mainwindow/tabbedbrowser.py2
-rw-r--r--qutebrowser/utils/version.py7
-rw-r--r--requirements.txt2
-rw-r--r--tests/helpers/testutils.py2
-rw-r--r--tests/unit/browser/webengine/test_webengineinterceptor.py97
-rw-r--r--tests/unit/utils/test_version.py8
20 files changed, 185 insertions, 56 deletions
diff --git a/README.asciidoc b/README.asciidoc
index 910a6b987..2b6bdfdd6 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -220,6 +220,7 @@ Active
* https://nyxt.atlas.engineer/[Nyxt browser] (formerly "Next browser", Lisp, Emacs-like but also offers Vim bindings, QtWebEngine or GTK+/WebKit2 - note there was a https://jgkamat.gitlab.io/blog/next-rce.html[critical remote code execution in 2019] which was handled quite badly)
* https://vieb.dev/[Vieb] (JavaScript, Electron)
* https://surf.suckless.org/[surf] (C, GTK+ with WebKit1/WebKit2)
+* https://github.com/jun7/wyeb[wyeb] (C, GTK+ with WebKit2)
* Chrome/Chromium addons:
https://vimium.github.io/[Vimium]
* Firefox addons (based on WebExtensions):
@@ -227,9 +228,8 @@ Active
https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/[Vimium-FF]
* Addons for Firefox and Chrome:
https://github.com/brookhong/Surfingkeys[Surfingkeys],
- https://lydell.github.io/LinkHints/[Link Hints] (hinting only)
-* Addons for Safari:
- https://televator.net/vimari/[Vimari]
+ https://lydell.github.io/LinkHints/[Link Hints] (hinting only),
+ https://github.com/ueokande/vimmatic[Vimmatic]
Inactive
~~~~~~~~
@@ -246,7 +246,6 @@ main inspiration for qutebrowser)
* https://www.uzbl.org/[uzbl] (C, GTK+ with WebKit1/WebKit2)
* https://github.com/conformal/xombrero[xombrero] (C, GTK+ with WebKit1)
* https://github.com/linkdd/cream-browser[Cream Browser] (C, GTK+ with WebKit1)
-* https://github.com/jun7/wyeb[wyeb] (C, GTK+ with WebKit2)
* Firefox addons (not based on WebExtensions or no recent activity):
http://www.vimperator.org/[Vimperator],
http://bug.5digits.org/pentadactyl/index[Pentadactyl],
@@ -263,6 +262,8 @@ main inspiration for qutebrowser)
https://github.com/1995eaton/chromium-vim[cVim],
https://github.com/dcchambers/vb4c[vb4c] (fork of cVim, https://github.com/dcchambers/vb4c/issues/23#issuecomment-810694017[unmaintained]),
https://glee.github.io/[GleeBox]
+* Addons for Safari:
+ https://televator.net/vimari/[Vimari]
License
-------
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index 03dbbeeae..b2b392a4c 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -202,8 +202,16 @@ Fixed
- Crash when using QtWebKit with PAC and the file has an invalid encoding.
- Crash with the "tiramisu" notification server.
- Crash when the "herbe" notification presenter doesn't start correctly.
+- Crash when no notification server is installed/available.
+- Warning with recent versions of the "deadd" (aka "linux notification center") notification server.
- Crash when using `:print --pdf` with a directory where its parent directory
did not exist.
+- The `PyQt{5,6}.sip` version is now shown correctly in the :version|--version
+ output. Previously that showed the version from the standalone `sip` module
+ which was only set for PyQt5. (#7805)
+- When a `config.py` calls `.redirect()` via a request interceptor (which is
+ unsupported) and supplies an invalid redirect target URL, an exception is now
+ raised for the `.redirect()` call instead of later inside qutebrowser.
[[v2.5.4]]
v2.5.4 (2023-03-13)
diff --git a/misc/requirements/requirements-dev.txt b/misc/requirements/requirements-dev.txt
index 6655cbfde..c9590f1c5 100644
--- a/misc/requirements/requirements-dev.txt
+++ b/misc/requirements/requirements-dev.txt
@@ -6,7 +6,7 @@ bump2version==1.0.1
certifi==2023.7.22
cffi==1.15.1
charset-normalizer==3.2.0
-cryptography==41.0.2
+cryptography==41.0.3
docutils==0.20.1
github3.py==4.0.1
hunter==3.6.1
@@ -19,12 +19,12 @@ keyring==24.2.0
manhole==1.8.0
markdown-it-py==3.0.0
mdurl==0.1.2
-more-itertools==9.1.0
+more-itertools==10.1.0
packaging==23.1
pkginfo==1.9.6
ply==3.11
pycparser==2.21
-Pygments==2.15.1
+Pygments==2.16.1
PyJWT==2.8.0
Pympler==1.0.1
pyproject_hooks==1.0.0
@@ -34,9 +34,9 @@ readme-renderer==40.0
requests==2.31.0
requests-toolbelt==1.0.0
rfc3986==2.0.0
-rich==13.4.2
+rich==13.5.2
SecretStorage==3.3.3
-sip==6.7.10
+sip==6.7.11
six==1.16.0
tomli==2.0.1
twine==4.0.2
diff --git a/misc/requirements/requirements-flake8.txt b/misc/requirements/requirements-flake8.txt
index 685542224..e16d6860f 100644
--- a/misc/requirements/requirements-flake8.txt
+++ b/misc/requirements/requirements-flake8.txt
@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
attrs==23.1.0
-flake8==6.0.0
+flake8==6.1.0
flake8-bugbear==23.7.10
flake8-builtins==2.1.0
flake8-comprehensions==3.14.0
@@ -16,8 +16,8 @@ flake8-tidy-imports==4.10.0
flake8-tuple==0.4.1
mccabe==0.7.0
pep8-naming==0.13.3
-pycodestyle==2.10.0
+pycodestyle==2.11.0
pydocstyle==6.3.0
-pyflakes==3.0.1
+pyflakes==3.1.0
six==1.16.0
snowballstemmer==2.2.0
diff --git a/misc/requirements/requirements-mypy.txt b/misc/requirements/requirements-mypy.txt
index a47f25d3f..1e18a7ab2 100644
--- a/misc/requirements/requirements-mypy.txt
+++ b/misc/requirements/requirements-mypy.txt
@@ -1,6 +1,6 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-chardet==5.1.0
+chardet==5.2.0
diff-cover==7.7.0
importlib-resources==6.0.0
Jinja2==3.1.2
@@ -9,12 +9,12 @@ MarkupSafe==2.1.3
mypy==1.4.1
mypy-extensions==1.0.0
pluggy==1.2.0
-Pygments==2.15.1
+Pygments==2.16.1
PyQt5-stubs==5.15.6.0
tomli==2.0.1
types-colorama==0.4.15.12
types-docutils==0.20.0.1
-types-Pygments==2.15.0.2
+types-Pygments==2.16.0.0
types-PyYAML==6.0.12.11
types-setuptools==68.0.0.3
typing_extensions==4.7.1
diff --git a/misc/requirements/requirements-pylint.txt b/misc/requirements/requirements-pylint.txt
index 62d7696eb..cd09e4bf2 100644
--- a/misc/requirements/requirements-pylint.txt
+++ b/misc/requirements/requirements-pylint.txt
@@ -4,7 +4,7 @@ astroid==2.15.6
certifi==2023.7.22
cffi==1.15.1
charset-normalizer==3.2.0
-cryptography==41.0.2
+cryptography==41.0.3
dill==0.3.7
github3.py==4.0.1
idna==3.4
@@ -12,16 +12,16 @@ isort==5.12.0
lazy-object-proxy==1.9.0
mccabe==0.7.0
pefile==2023.2.7
-platformdirs==3.9.1
+platformdirs==3.10.0
pycparser==2.21
PyJWT==2.8.0
-pylint==2.17.4
+pylint==2.17.5
python-dateutil==2.8.2
./scripts/dev/pylint_checkers
requests==2.31.0
six==1.16.0
tomli==2.0.1
-tomlkit==0.11.8
+tomlkit==0.12.1
typing_extensions==4.7.1
uritemplate==4.1.1
# urllib3==2.0.4
diff --git a/misc/requirements/requirements-pyroma.txt b/misc/requirements/requirements-pyroma.txt
index 50078baeb..f574b4c26 100644
--- a/misc/requirements/requirements-pyroma.txt
+++ b/misc/requirements/requirements-pyroma.txt
@@ -6,7 +6,7 @@ charset-normalizer==3.2.0
docutils==0.20.1
idna==3.4
packaging==23.1
-Pygments==2.15.1
+Pygments==2.16.1
pyproject_hooks==1.0.0
pyroma==4.2
requests==2.31.0
diff --git a/misc/requirements/requirements-sphinx.txt b/misc/requirements/requirements-sphinx.txt
index 35b0e6257..3557eab6c 100644
--- a/misc/requirements/requirements-sphinx.txt
+++ b/misc/requirements/requirements-sphinx.txt
@@ -11,11 +11,11 @@ importlib-metadata==6.8.0
Jinja2==3.1.2
MarkupSafe==2.1.3
packaging==23.1
-Pygments==2.15.1
+Pygments==2.16.1
pytz==2023.3
requests==2.31.0
snowballstemmer==2.2.0
-Sphinx==7.0.1
+Sphinx==7.1.2
sphinxcontrib-applehelp==1.0.4
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.1
diff --git a/misc/requirements/requirements-tests.txt b/misc/requirements/requirements-tests.txt
index 9b99a577a..abd6ea727 100644
--- a/misc/requirements/requirements-tests.txt
+++ b/misc/requirements/requirements-tests.txt
@@ -13,23 +13,23 @@ execnet==2.0.2
filelock==3.12.2
Flask==2.3.2
hunter==3.6.1
-hypothesis==6.82.0
+hypothesis==6.82.2
idna==3.4
importlib-metadata==6.8.0
iniconfig==2.0.0
itsdangerous==2.1.2
-jaraco.functools==3.8.0
+jaraco.functools==3.8.1
# Jinja2==3.1.2
Mako==1.2.4
manhole==1.8.0
# MarkupSafe==2.1.3
-more-itertools==9.1.0
+more-itertools==10.1.0
packaging==23.1
parse==1.19.1
parse-type==0.6.2
pluggy==1.2.0
py-cpuinfo==9.0.0
-Pygments==2.15.1
+Pygments==2.16.1
pytest==7.4.0
pytest-bdd==6.1.1
pytest-benchmark==4.0.0
diff --git a/misc/requirements/requirements-tox.txt b/misc/requirements/requirements-tox.txt
index a4c7c4948..ae8fce6ff 100644
--- a/misc/requirements/requirements-tox.txt
+++ b/misc/requirements/requirements-tox.txt
@@ -1,17 +1,17 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
cachetools==5.3.1
-chardet==5.1.0
+chardet==5.2.0
colorama==0.4.6
distlib==0.3.7
filelock==3.12.2
packaging==23.1
pip==23.2.1
-platformdirs==3.9.1
+platformdirs==3.10.0
pluggy==1.2.0
pyproject-api==1.5.3
setuptools==68.0.0
tomli==2.0.1
tox==4.6.4
-virtualenv==20.24.1
-wheel==0.41.0
+virtualenv==20.24.2
+wheel==0.41.1
diff --git a/misc/requirements/requirements-yamllint.txt b/misc/requirements/requirements-yamllint.txt
index a35c0ff58..fd9ea256f 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.11.1
+pathspec==0.11.2
PyYAML==6.0.1
yamllint==1.32.0
diff --git a/qutebrowser/api/cmdutils.py b/qutebrowser/api/cmdutils.py
index 067ebca92..0c367c6bf 100644
--- a/qutebrowser/api/cmdutils.py
+++ b/qutebrowser/api/cmdutils.py
@@ -35,7 +35,7 @@ Possible values:
import inspect
-from typing import Any, Callable, Iterable
+from typing import Any, Callable, Iterable, Protocol, Optional, Dict, cast
from qutebrowser.utils import qtutils
from qutebrowser.commands import command, cmdexc
@@ -90,7 +90,21 @@ def check_exclusive(flags: Iterable[bool], names: Iterable[str]) -> None:
raise CommandError("Only one of {} can be given!".format(argstr))
-_CmdHandlerType = Callable[..., Any]
+_CmdHandlerFunc = Callable[..., Any]
+
+
+class _CmdHandlerType(Protocol):
+
+ """A qutebrowser command function, which had qute_args patched on it.
+
+ Applying @cmdutils.argument to a function will patch it with a qute_args attribute.
+ Below, we cast the decorated function to _CmdHandlerType to make mypy aware of this.
+ """
+
+ qute_args: Optional[Dict[str, command.ArgInfo]]
+
+ def __call__(self, *args: Any, **kwargs: Any) -> Any:
+ ...
class register: # noqa: N801,N806 pylint: disable=invalid-name
@@ -118,7 +132,7 @@ class register: # noqa: N801,N806 pylint: disable=invalid-name
# The arguments to pass to Command.
self._kwargs = kwargs
- def __call__(self, func: _CmdHandlerType) -> _CmdHandlerType:
+ def __call__(self, func: _CmdHandlerFunc) -> _CmdHandlerType:
"""Register the command before running the function.
Gets called when a function should be decorated.
@@ -158,7 +172,8 @@ class register: # noqa: N801,N806 pylint: disable=invalid-name
# This is checked by future @cmdutils.argument calls so they fail
# (as they'd be silently ignored otherwise)
- func.qute_args = None # type: ignore[attr-defined]
+ func = cast(_CmdHandlerType, func)
+ func.qute_args = None
return func
@@ -210,19 +225,21 @@ class argument: # noqa: N801,N806 pylint: disable=invalid-name
self._argname = argname # The name of the argument to handle.
self._kwargs = kwargs # Valid ArgInfo members.
- def __call__(self, func: _CmdHandlerType) -> _CmdHandlerType:
+ def __call__(self, func: _CmdHandlerFunc) -> _CmdHandlerType:
funcname = func.__name__
if self._argname not in inspect.signature(func).parameters:
raise ValueError("{} has no argument {}!".format(funcname,
self._argname))
+
+ func = cast(_CmdHandlerType, func)
if not hasattr(func, 'qute_args'):
- func.qute_args = {} # type: ignore[attr-defined]
+ func.qute_args = {}
elif func.qute_args is None:
raise ValueError("@cmdutils.argument got called above (after) "
"@cmdutils.register for {}!".format(funcname))
arginfo = command.ArgInfo(**self._kwargs)
- func.qute_args[self._argname] = arginfo # type: ignore[attr-defined]
+ func.qute_args[self._argname] = arginfo
return func
diff --git a/qutebrowser/browser/webengine/interceptor.py b/qutebrowser/browser/webengine/interceptor.py
index ac0795803..161f5ffab 100644
--- a/qutebrowser/browser/webengine/interceptor.py
+++ b/qutebrowser/browser/webengine/interceptor.py
@@ -10,7 +10,7 @@ from qutebrowser.qt.webenginecore import (QWebEngineUrlRequestInterceptor,
from qutebrowser.config import websettings, config
from qutebrowser.browser import shared
-from qutebrowser.utils import debug, log
+from qutebrowser.utils import debug, log, qtutils
from qutebrowser.extensions import interceptors
from qutebrowser.misc import objects
@@ -35,6 +35,11 @@ class WebEngineRequest(interceptors.Request):
if self._webengine_info is None:
raise interceptors.RedirectException("Request improperly initialized.")
+ try:
+ qtutils.ensure_valid(url)
+ except qtutils.QtValueError as e:
+ raise interceptors.RedirectException(f"Redirect to invalid URL: {e}")
+
# Redirecting a request that contains payload data is not allowed.
# To be safe, abort on any request not in a whitelist.
verb = self._webengine_info.requestMethod()
diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py
index 2edb2d538..e8b2e27f1 100644
--- a/qutebrowser/browser/webengine/notification.py
+++ b/qutebrowser/browser/webengine/notification.py
@@ -113,6 +113,9 @@ class DBusError(Error):
# https://crashes.qutebrowser.org/view/de62220a
# after "Notification daemon did quit!"
"org.freedesktop.DBus.Error.UnknownObject",
+
+ # notmuch-sha1-ef7b6e9e79e5f2f6cba90224122288895c1fe0d8
+ "org.freedesktop.DBus.Error.ServiceUnknown",
}
def __init__(self, msg: QDBusMessage) -> None:
@@ -856,12 +859,15 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
log.misc.debug(f"Enabling quirks {quirks}")
self._quirks = quirks
- expected_spec_version = self._quirks.spec_version or self.SPEC_VERSION
- if spec_version != expected_spec_version:
+ expected_spec_versions = [self.SPEC_VERSION]
+ if self._quirks.spec_version is not None:
+ expected_spec_versions.append(self._quirks.spec_version)
+
+ if spec_version not in expected_spec_versions:
log.misc.warning(
f"Notification server ({name} {ver} by {vendor}) implements "
- f"spec {spec_version}, but {expected_spec_version} was expected. "
- f"If {name} is up to date, please report a qutebrowser bug.")
+ f"spec {spec_version}, but {'/'.join(expected_spec_versions)} was "
+ f"expected. If {name} is up to date, please report a qutebrowser bug.")
# https://specifications.freedesktop.org/notification-spec/latest/ar01s08.html
icon_key_overrides = {
diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py
index 85f683133..98cb67cb2 100644
--- a/qutebrowser/mainwindow/tabbedbrowser.py
+++ b/qutebrowser/mainwindow/tabbedbrowser.py
@@ -316,6 +316,8 @@ class TabbedBrowser(QWidget):
fields['id'] = self._win_id
title = title_format.format(**fields)
+ # prevent hanging WMs and similar issues with giant URLs
+ title = utils.elide(title, 1024)
self._window().setWindowTitle(title)
diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py
index fdaa12efb..ce816b9fd 100644
--- a/qutebrowser/utils/version.py
+++ b/qutebrowser/utils/version.py
@@ -381,7 +381,6 @@ class ModuleInfo:
def _create_module_info() -> Dict[str, ModuleInfo]:
packages = [
- ('sip', ['SIP_VERSION_STR']),
('colorama', ['VERSION', '__version__']),
('jinja2', ['__version__']),
('pygments', ['__version__']),
@@ -395,9 +394,13 @@ def _create_module_info() -> Dict[str, ModuleInfo]:
('PyQt5.QtWebEngineWidgets', []),
('PyQt5.QtWebEngine', ['PYQT_WEBENGINE_VERSION_STR']),
('PyQt5.QtWebKitWidgets', []),
+ ('PyQt5.sip', ['SIP_VERSION_STR']),
]
elif machinery.IS_QT6:
- packages.append(('PyQt6.QtWebEngineCore', ['PYQT_WEBENGINE_VERSION_STR']))
+ packages += [
+ ('PyQt6.QtWebEngineCore', ['PYQT_WEBENGINE_VERSION_STR']),
+ ('PyQt6.sip', ['SIP_VERSION_STR']),
+ ]
else:
raise utils.Unreachable()
diff --git a/requirements.txt b/requirements.txt
index b5bab3296..f10ab6f9b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,7 +5,7 @@ colorama==0.4.6
importlib-resources==6.0.0 ; python_version=="3.8.*"
Jinja2==3.1.2
MarkupSafe==2.1.3
-Pygments==2.15.1
+Pygments==2.16.1
PyYAML==6.0.1
zipp==3.16.2
# Unpinned due to recompile_requirements.py limitations
diff --git a/tests/helpers/testutils.py b/tests/helpers/testutils.py
index f6d7fcc4b..dc6fdac32 100644
--- a/tests/helpers/testutils.py
+++ b/tests/helpers/testutils.py
@@ -150,7 +150,7 @@ def partial_compare(val1, val2, *, indent=0):
if val2 is Ellipsis:
print_i("Ignoring ellipsis comparison", indent, error=True)
return PartialCompareOutcome()
- elif type(val1) != type(val2): # pylint: disable=unidiomatic-typecheck
+ elif type(val1) is not type(val2):
outcome = PartialCompareOutcome(
"Different types ({}, {}) -> False".format(type(val1).__name__,
type(val2).__name__))
diff --git a/tests/unit/browser/webengine/test_webengineinterceptor.py b/tests/unit/browser/webengine/test_webengineinterceptor.py
index d579d60f7..099ba69d7 100644
--- a/tests/unit/browser/webengine/test_webengineinterceptor.py
+++ b/tests/unit/browser/webengine/test_webengineinterceptor.py
@@ -6,12 +6,15 @@
import pytest
+import pytest_mock
-pytest.importorskip('qutebrowser.qt.webenginecore')
+pytest.importorskip("qutebrowser.qt.webenginecore")
+from qutebrowser.qt.core import QUrl, QByteArray
from qutebrowser.qt.webenginecore import QWebEngineUrlRequestInfo
from qutebrowser.browser.webengine import interceptor
+from qutebrowser.extensions import interceptors
from qutebrowser.utils import qtutils
from helpers import testutils
@@ -19,10 +22,12 @@ from helpers import testutils
def test_no_missing_resource_types():
request_interceptor = interceptor.RequestInterceptor()
qb_keys = set(request_interceptor._resource_types.keys())
- qt_keys = set(testutils.enum_members(
- QWebEngineUrlRequestInfo,
- QWebEngineUrlRequestInfo.ResourceType,
- ).values())
+ qt_keys = set(
+ testutils.enum_members(
+ QWebEngineUrlRequestInfo,
+ QWebEngineUrlRequestInfo.ResourceType,
+ ).values()
+ )
assert qt_keys == qb_keys
@@ -30,3 +35,85 @@ def test_resource_type_values():
request_interceptor = interceptor.RequestInterceptor()
for qt_value, qb_item in request_interceptor._resource_types.items():
assert qtutils.extract_enum_val(qt_value) == qb_item.value
+
+
+@pytest.fixture
+def we_request( # a shrubbery!
+ mocker: pytest_mock.MockerFixture,
+) -> interceptor.WebEngineRequest:
+ qt_info = mocker.Mock(spec=QWebEngineUrlRequestInfo)
+ qt_info.requestMethod.return_value = QByteArray(b"GET")
+ first_party_url = QUrl("https://firstparty.example.org/")
+ request_url = QUrl("https://request.example.org/")
+ return interceptor.WebEngineRequest(
+ first_party_url=first_party_url,
+ request_url=request_url,
+ webengine_info=qt_info,
+ )
+
+
+def test_block(we_request: interceptor.WebEngineRequest):
+ assert not we_request.is_blocked
+ we_request.block()
+ assert we_request.is_blocked
+
+
+class TestRedirect:
+ REDIRECT_URL = QUrl("https://redirect.example.com/")
+
+ def test_redirect(self, we_request: interceptor.WebEngineRequest):
+ assert not we_request._redirected
+ we_request.redirect(self.REDIRECT_URL)
+ assert we_request._redirected
+ we_request._webengine_info.redirect.assert_called_once_with(self.REDIRECT_URL)
+
+ def test_twice(self, we_request: interceptor.WebEngineRequest):
+ we_request.redirect(self.REDIRECT_URL)
+ with pytest.raises(
+ interceptors.RedirectException,
+ match=r"Request already redirected.",
+ ):
+ we_request.redirect(self.REDIRECT_URL)
+ we_request._webengine_info.redirect.assert_called_once_with(self.REDIRECT_URL)
+
+ def test_invalid_method(self, we_request: interceptor.WebEngineRequest):
+ we_request._webengine_info.requestMethod.return_value = QByteArray(b"POST")
+ with pytest.raises(
+ interceptors.RedirectException,
+ match=(
+ r"Request method b'POST' for https://request.example.org/ does not "
+ r"support redirection."
+ ),
+ ):
+ we_request.redirect(self.REDIRECT_URL)
+ assert not we_request._webengine_info.redirect.called
+
+ def test_invalid_method_ignore_unsupported(
+ self,
+ we_request: interceptor.WebEngineRequest,
+ caplog: pytest.LogCaptureFixture,
+ ):
+ we_request._webengine_info.requestMethod.return_value = QByteArray(b"POST")
+ we_request.redirect(self.REDIRECT_URL, ignore_unsupported=True)
+ assert caplog.messages == [
+ "Request method b'POST' for https://request.example.org/ does not support "
+ "redirection."
+ ]
+ assert not we_request._webengine_info.redirect.called
+
+ def test_improperly_initialized(self, we_request: interceptor.WebEngineRequest):
+ we_request._webengine_info = None
+ with pytest.raises(
+ interceptors.RedirectException,
+ match=r"Request improperly initialized.",
+ ):
+ we_request.redirect(self.REDIRECT_URL)
+
+ def test_invalid_url(self, we_request: interceptor.WebEngineRequest):
+ url = QUrl()
+ assert not url.isValid()
+ with pytest.raises(
+ interceptors.RedirectException,
+ match=r"Redirect to invalid URL: PyQt\d\.QtCore\.QUrl\(''\) is not valid",
+ ):
+ we_request.redirect(url)
diff --git a/tests/unit/utils/test_version.py b/tests/unit/utils/test_version.py
index f78a6f12d..486270d70 100644
--- a/tests/unit/utils/test_version.py
+++ b/tests/unit/utils/test_version.py
@@ -644,8 +644,8 @@ class TestModuleVersions:
assert version._module_versions() == expected
@pytest.mark.parametrize('module, idx, expected', [
- ('colorama', 1, 'colorama: no'),
- ('adblock', 5, 'adblock: no'),
+ ('colorama', 0, 'colorama: no'),
+ ('adblock', 4, 'adblock: no'),
])
def test_missing_module(self, module, idx, expected, import_fake):
"""Test with a module missing.
@@ -693,11 +693,11 @@ class TestModuleVersions:
assert not mod_info.is_usable()
expected = f"adblock: {fake_version} (< {mod_info.min_version}, outdated)"
- assert version._module_versions()[5] == expected
+ assert version._module_versions()[4] == expected
@pytest.mark.parametrize('attribute, expected_modules', [
('VERSION', ['colorama']),
- ('SIP_VERSION_STR', ['sip']),
+ ('SIP_VERSION_STR', ['PyQt5.sip', 'PyQt6.sip']),
(None, []),
])
def test_version_attribute(self, attribute, expected_modules, import_fake):