libwayland-client.so is development symlink used during linking and there's no need to
have it installed (usually shipped in -devel/-dev packages) on user's machines. Instead
of hardcoding library file name, use same mechanism as in libX11 which let's Python
figure the details and share common logic between X11 and Wayland.
Fixes#8771
Qt 6.8.2 has a more fine-grained workaround:
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/606122
This never seems to have it made to Qt 6.9+, but I can't seem to reproduce the
issue anymore (neither with PDF.js nor with Google Sheets), even on older
affected Qt versions, even on older Intel hardware. Maybe something else (mesa
etc.?) changed and this was fixed there?
Let's reenable this and find out if it breaks things again for someone.
Fixes#8346
See #7489, #8001, #8006
With Python 3.14, since argparse enabled coloring by default:
17c5959aa3
running test_cmdutils.py failed with a lengthy traceback finishing in:
```
INTERNALERROR> pluggy.PluggyTeardownRaisedWarning: A plugin raised an exception during an old-style hookwrapper teardown.
INTERNALERROR> Plugin: /home/florian/proj/qutebrowser/git/tests/conftest.py, Hook: pytest_runtest_makereport
INTERNALERROR> PluggyTeardownRaisedWarning: A plugin raised an exception during an old-style hookwrapper teardown.
INTERNALERROR> Plugin: rerunfailures, Hook: pytest_runtest_makereport
INTERNALERROR> PluggyTeardownRaisedWarning: A plugin raised an exception during an old-style hookwrapper teardown.
INTERNALERROR> Plugin: hypothesispytest, Hook: pytest_runtest_makereport
INTERNALERROR> PluggyTeardownRaisedWarning: A plugin raised an exception during an old-style hookwrapper teardown.
INTERNALERROR> Plugin: pytest-bdd, Hook: pytest_runtest_makereport
INTERNALERROR> AttributeError: 'types.SimpleNamespace' object has no attribute 'verbose'
```
with one part pointing to Python internals:
```pytb
INTERNALERROR> File "/home/florian/proj/qutebrowser/git/.tox/py314-pyqt68/lib/python3.14/site-packages/_pytest/_code/code.py", line 669, in exconly
INTERNALERROR> lines = format_exception_only(self.type, self.value)
INTERNALERROR> File "/usr/lib/python3.14/traceback.py", line 180, in format_exception_only
INTERNALERROR> te = TracebackException(type(value), value, None, compact=True)
INTERNALERROR> File "/usr/lib/python3.14/traceback.py", line 1106, in __init__
INTERNALERROR> suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name)
INTERNALERROR> File "/usr/lib/python3.14/traceback.py", line 1653, in _compute_suggestion_error
INTERNALERROR> import _suggestions
INTERNALERROR> File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
INTERNALERROR> File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
INTERNALERROR> File "<frozen importlib._bootstrap>", line 951, in _load_unlocked
INTERNALERROR> File "<frozen importlib._bootstrap>", line 496, in _verbose_message
INTERNALERROR> AttributeError: 'types.SimpleNamespace' object has no attribute 'verbose'
```
This happens when Python tries to access sys.flags.verbose, but we replaced it
with a fake object that does not have a .verbose attribute anymore (only
temporarily, but for some reason that's enough to trigger the issue anyways).
Since we can't mutate sys.flags, instead we create an object that copies all
sys.flags attributes, and then use that as a nicer replacement.
See #8529
Unfortunately there is no way to get this information from Qt, so I had to
resort to some funny low-level C-like Python programming to directly use
libwayland-client and Xlib. Fun was had! Hopefully this avoids having to ask
for this information every time someone shows a bug/crash report, as there
are various subtleties that can be specific to the Wayland compositor in use.
Packages are slowly migrating to not having a __version__ attribute anymore,
instead relying on importlib.metadata to query the installed version.
jinja2 now shows a deprecation warning when accessing the __version__
attribute: https://github.com/pallets/jinja/pull/2098
For now we keep accessing __version__ for other packages (we still need the
logic for PyQt and its special version attributes anyways), but we fall back on
importlib.metadata.version if we can't get a version that way, and we stop
trying __version__ for jinja2.
With windows-2022 and windows-2025 on GitHub Actions,
we get:
qutescheme:data_for_url:128 url: qute://pdfjs/web/viewer.mjs, path: /web/viewer.mjs, host pdfjs
webenginequtescheme:requestStarted:105 Returning text/plain data
which causes:
JS: [qute://pdfjs/build/pdf.mjs:0] Failed to load module script: Expected a
JavaScript module script but the server responded with a MIME type of
"text/plain". Strict MIME type checking is enforced for module scripts per
HTML spec.
It's unclear why we get text/plain back there in the first place (can't
reproduce on a local Windows 11 install), but it's definitely wrong, so let's
just override that problematic case.
With PyQtWebEngine-Qt5 5.15.17 (Qt 5.15.19), we seem to run into similar issues
like we already did with Qt 6.5:
https://github.com/qutebrowser/qutebrowser/issues/7624#issuecomment-14740084709cb54b2099
However, skipping the ELF test is not enough, as we also get warnings
at runtime (as we don't have any API to get the version at runtime).
We don't care much about Qt 5 at this stage, so let's just not output
warnings in that case (and nothing in the code should care about the exact
QtWebEngine patch level beyond 5.15.2 anyways).
For most user-facing things, we *can* get the exact version number from
the user-agent, so this should not actually affect much.
We create the DownloadManager with parent=qapp, which means they will stick
around forever after the test finished.
While we disconnect the QWebEngineProfile::downloadRequested() signal,
we keep the DownloadManager around, which also keeps around its download-update
timers.
Those will then result in tests/unit/utils/usertypes/test_timer.py::test_early_timeout_check
being flaky, as their _validity_check_handler slot keeps getting called in the
background. Due to the globally mocked time.monotonic(), this results in
nonsensical error messages such as:
Got logging message on logger misc with level WARNING:
Timer download-update (id ...) triggered too early:
interval 500 but only -1023.269s passed!
After this change, we now clean up those objects properly, thus fixing the
flakiness.
See #5390.
Speculative fix for test_early_timeout_handler in
tests/unit/utils/usertypes/test_timer.py failing:
> assert len(caplog.messages) == 1
E AssertionError: assert 5 == 1
due to:
------------------------------ Captured log call -------------------------------
WARNING misc:usertypes.py:467 Timer download-update (id 620757000) triggered too early: interval 500 but only -609.805s passed
WARNING misc:usertypes.py:467 Timer download-update (id 922746881) triggered too early: interval 500 but only -609.429s passed
WARNING misc:usertypes.py:467 Timer download-update (id 1056964613) triggered too early: interval 500 but only -609.537s passed
WARNING misc:usertypes.py:467 Timer download-update (id 1912602631) triggered too early: interval 500 but only -609.671s passed
WARNING misc:usertypes.py:467 Timer t (id -1) triggered too early: interval 3 but only 0.001s passed
This can be used to easily test a different PDF.js version manually (which is
installed via update_3rdparty.py), without having to uninstall the system-wide
one first.
The DocumentPictureInPicture JS API added in Chromium 116 is not implemented in
QtWebEngine. This results in createWindow() being called with a window type with
random value, which then causes qutebrowser to bail out:
Traceback (most recent call last):
File ".../qutebrowser/browser/webengine/webview.py", line 123, in createWindow
raise ValueError("Invalid wintype {}".format(debug_type))
ValueError: Invalid wintype 843995690
Until this is fixed in Qt, we pass an argument to Chromium to disable the API
entirely, so that web pages hopefully fall back to something else.
In the case of the new Google Huddle feature, this results in them still working
with an on-page overlay instead.
Thanks to Joshua Cold and Vivia for helping to debug this!
Fixes#8449
See https://bugreports.qt.io/browse/QTBUG-132681
Turns out there are various places in the tests that somehow cause Qt to start
caching the dict location, not just actually accessing
.[is|set]SpellCheckEnabled() like I originally assumed.
Thus, move setting QTWEBENGINE_DICTIONARIES_PATH into conftest.py so it's run
before any tests. However, remove the sanity check after, as that requires
initializing a QWebEngineProfile which we might not always want to do when
running a subset of unit tests. If something goes wrong with this, chances are
we'll only notice later in the tests anyways.
Follow-up to db8e508530
See #8330
Starting with Qt 6.8, Qt enforces that the spell checking dictionary path exists
when enabling spell checking (but it doesn't check whether there is actually
anything in there). This caused our test ensuring that spell checking gets
enabled properly to fail, as we never actually set a proper directory.
We now do, though we need to do so for the entire test session, as QtWebEngine
caches the directory.
Reverts 7475d38
See https://github.com/qutebrowser/qutebrowser/issues/8242#issuecomment-2333609589Fixes#8330
Similarly to #5998, XHR requests should be able to set their custom
Accept-Language values - and for some odd reason, stuff breaks on websites
sometimes when that's not respected.
There's no way for qutebrowser to know if a given header value is already set in
a request (i.e. whether we're adding or overriding). Thus we only really have
two options here:
1) Don't set any shared.custom_headers() for XHR requests at all.
2) Special-case Accept-Language here, because the issue usually is triggered by
the global override, but that already gets set just fine via QWebEngineProfile
anyways.
Given that 2) is the thing causing trouble in the wild and it's unclear what the
desired behavior for 1) is (e.g. for the DNT header), let's go for 2) here.
Relying on `hasattr()` made me feel a bit guilty. So I've moved these
conditionals to be backed by a class. The only class based alternative I
can think of is putting it on the base type and leaving all the other
config variables to raise errors. But that doesn't tell the type system
anything.