Merge branch 'master' into qt6-v2

Just a few conflicts around CI and dependencies.
This commit is contained in:
toofar 2022-11-20 15:48:00 +13:00
commit 2d66466194
62 changed files with 324 additions and 200 deletions

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@ -97,8 +97,8 @@ jobs:
- name: Gather info
id: info
run: |
echo "::set-output name=date::$(date +'%Y-%m-%d')"
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
echo "date=$(date +'%Y-%m-%d')" >> "$GITHUB_OUTPUT"
echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:

View File

@ -45,7 +45,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@v3
uses: peter-evans/create-pull-request@v4
with:
committer: qutebrowser bot <bot@qutebrowser.org>
author: qutebrowser bot <bot@qutebrowser.org>

View File

@ -10,7 +10,6 @@ disallow_subclassing_any = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_decorators = True
# no_implicit_optional = True
warn_redundant_casts = True
warn_unused_ignores = True
# warn_return_any = True
@ -27,6 +26,9 @@ show_error_codes = True
show_error_context = True
pretty = True
### FIXME:qt6 get rid of this for v3
no_implicit_optional = False
[mypy-colorama]
# https://github.com/tartley/colorama/issues/206
ignore_missing_imports = True

View File

@ -119,6 +119,9 @@ Fixed
shown, qutebrowser used to only show one message. This is now only done when the
two messages are completely equivalent (text, level, etc.) instead of doing so
when only the text matches.
- The `progress` and `backforward` statusbar widgets now stay removed if you
choose to remove them. Previously they would appear again on navigation.
- Rare crash when running userscripts with crashed renderer processes.
[[v2.5.3]]
v2.5.3 (unreleased)
@ -138,6 +141,9 @@ Fixed
- Wrong type handling when using `:config-{dict,list}-*` commands with a config
option with non-string values. The only affected option is `bindings.commands`,
which is probably rarely used with those commands.
- The `readability` userscript now correctly passes the source URL to
Breadability, to make relative links work.
- Update `dictcli.py` to use the `main` branch, fixing a 404 error.
- Minor documentation fixes
[[v2.5.2]]

View File

@ -158,7 +158,7 @@ It also works nicely with rapid hints:
:bind ;M hint --rapid links spawn umpv {hint-url}
----
How do I use qutebrowser with mutt?::
How do I use qutebrowser with mutt/neomutt or other mail clients?::
For security reasons, local files without `.html` extensions aren't
rendered as HTML, see
https://bugs.chromium.org/p/chromium/issues/detail?id=777737[this Chromium issue]
@ -166,8 +166,29 @@ How do I use qutebrowser with mutt?::
extension:
+
----
text/html; qutebrowser %s; needsterminal; nametemplate=%s.html
text/html; qutebrowser %s; needsterminal; nametemplate=%s.html
----
+
Note that you might want to add additional options to qutebrowser, so that it
runs as a seperate instance configured to disable JavaScript and avoid network
requests, in order to avoid privacy leaks when reading mails. The easiest way
to do so is by specifying a non-existent proxy server, e.g.:
+
----
qutebrowser --temp-basedir -s content.proxy http://localhost:666 -s content.dns_prefetch false -s content.javascript.enabled false %s
----
+
With Qt 6, using something like:
+
----
qutebrowser --temp-basedir -s content.dns_prefetch false -s content.javascript.enabled false %s
----
+
should lead to a similar result, due to a more restrictive implementation of
the `content.local_content_can_access_remote_urls` setting (`false` by default
already). However, it's advised to use a page like
https://www.emailprivacytester.com/[Email Privacy Tester] to verify your
configuration.
What is the difference between bookmarks and quickmarks?::
Bookmarks will always use the title of the website as their name, but with quickmarks

View File

@ -449,6 +449,7 @@ Various emacs/conkeror-like keybinding configs exist:
- https://gitlab.com/Kaligule/qutebrowser-emacs-config/blob/master/config.py[Kaligule]
- https://web.archive.org/web/20210512185023/https://me0w.net/pit/1540882719[nm0i]
- https://www.reddit.com/r/qutebrowser/comments/eh10i7/config_share_qute_with_emacs_keybindings/[jasonsun0310]
- https://git.sr.ht/~willvaughn/dots/tree/mjolnir/item/.config/qutebrowser/qutemacs.py[willvaughn]
It's also mostly possible to get rid of modal keybindings by setting
`input.insert_mode.auto_enter` to `false`, and `input.forward_unbound_keys` to

View File

@ -218,7 +218,7 @@
|<<editor.encoding,editor.encoding>>|Encoding to use for the editor.
|<<editor.remove_file,editor.remove_file>>|Delete the temporary file upon closing the editor.
|<<fileselect.folder.command,fileselect.folder.command>>|Command (and arguments) to use for selecting a single folder in forms. The command should write the selected folder path to the specified file or stdout.
|<<fileselect.handler,fileselect.handler>>|Handler for selecting file(s) in forms. If `external`, then the commands specified by `fileselect.single_file.command` and `fileselect.multiple_files.command` are used to select one or multiple files respectively.
|<<fileselect.handler,fileselect.handler>>|Handler for selecting file(s) in forms. If `external`, then the commands specified by `fileselect.single_file.command`, `fileselect.multiple_files.command` and `fileselect.folder.command` are used to select one file, multiple files, and folders, respectively.
|<<fileselect.multiple_files.command,fileselect.multiple_files.command>>|Command (and arguments) to use for selecting multiple files in forms. The command should write the selected file paths to the specified file or to stdout, separated by newlines.
|<<fileselect.single_file.command,fileselect.single_file.command>>|Command (and arguments) to use for selecting a single file in forms. The command should write the selected file path to the specified file or stdout.
|<<fonts.completion.category,fonts.completion.category>>|Font used in the completion categories.
@ -3011,7 +3011,7 @@ Default:
[[fileselect.handler]]
=== fileselect.handler
Handler for selecting file(s) in forms. If `external`, then the commands specified by `fileselect.single_file.command` and `fileselect.multiple_files.command` are used to select one or multiple files respectively.
Handler for selecting file(s) in forms. If `external`, then the commands specified by `fileselect.single_file.command`, `fileselect.multiple_files.command` and `fileselect.folder.command` are used to select one file, multiple files, and folders, respectively.
Type: <<types,String>>

View File

@ -1,6 +1,6 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
build==0.8.0
build==0.9.0
check-manifest==0.48
packaging==21.3
pep517==0.13.0

View File

@ -1,45 +1,47 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
bleach==5.0.1
build==0.8.0
build==0.9.0
bump2version==1.0.1
certifi==2022.6.15
certifi==2022.9.24
cffi==1.15.1
charset-normalizer==2.1.1
commonmark==0.9.1
cryptography==37.0.4
cryptography==38.0.3
docutils==0.19
github3.py==3.2.0
hunter==3.4.3
idna==3.3
importlib-metadata==4.12.0
hunter==3.5.1
idna==3.4
importlib-metadata==5.0.0
jaraco.classes==3.2.3
jeepney==0.8.0
keyring==23.8.2
keyring==23.11.0
manhole==1.8.0
more-itertools==9.0.0
packaging==21.3
pep517==0.13.0
pkginfo==1.8.3
ply==3.11
pycparser==2.21
Pygments==2.13.0
PyJWT==2.4.0
PyJWT==2.6.0
Pympler==1.0.1
pyparsing==3.0.9
PyQt-builder==1.13.0
PyQt-builder==1.14.0
python-dateutil==2.8.2
readme-renderer==37.0
readme-renderer==37.3
requests==2.28.1
requests-toolbelt==0.9.1
requests-toolbelt==0.10.1
rfc3986==2.0.0
rich==12.5.1
rich==12.6.0
SecretStorage==3.3.3
sip==6.6.2
sip==6.7.4
six==1.16.0
toml==0.10.2
tomli==2.0.1
twine==4.0.1
typing_extensions==4.3.0
typing_extensions==4.4.0
uritemplate==4.1.1
# urllib3==1.26.11
# urllib3==1.26.12
webencodings==0.5.1
zipp==3.8.1
zipp==3.10.0

View File

@ -2,12 +2,12 @@
attrs==22.1.0
flake8==5.0.4
flake8-bugbear==22.7.1
flake8-builtins==1.5.3
flake8-comprehensions==3.10.0
flake8-bugbear==22.10.27
flake8-builtins==2.0.1
flake8-comprehensions==3.10.1
flake8-copyright==0.2.3
flake8-debugger==4.1.2
flake8-deprecated==1.3
flake8-deprecated==2.0.1
flake8-docstrings==1.6.0
flake8-future-import==0.4.7
flake8-plugin-utils==1.3.2

View File

@ -3,7 +3,7 @@ flake8-bugbear
flake8-builtins
flake8-comprehensions
flake8-debugger
flake8-deprecated
flake8-deprecated!=2.0.0
flake8-docstrings
flake8-copyright
flake8-future-import

View File

@ -1,18 +1,18 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
chardet==5.0.0
diff-cover==6.5.1
importlib-metadata==4.12.0
importlib-resources==5.9.0
diff-cover==7.0.2
importlib-metadata==5.0.0
importlib-resources==5.10.0
Jinja2==3.1.2
lxml==4.9.1
MarkupSafe==2.1.1
mypy==0.971
mypy==0.990
mypy-extensions==0.4.3
pluggy==1.0.0
Pygments==2.13.0
PyQt5-stubs==5.15.6.0
tomli==2.0.1
types-PyYAML==6.0.11
typing_extensions==4.3.0
zipp==3.8.1
types-PyYAML==6.0.12.2
typing_extensions==4.4.0
zipp==3.10.0

View File

@ -1,5 +1,5 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
altgraph==0.17.2
pyinstaller==5.3
pyinstaller-hooks-contrib==2022.8
altgraph==0.17.3
pyinstaller==5.6.2
pyinstaller-hooks-contrib==2022.13

View File

@ -1,30 +1,30 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
astroid==2.11.7
certifi==2022.6.15
astroid==2.12.12
certifi==2022.9.24
cffi==1.15.1
charset-normalizer==2.1.1
cryptography==37.0.4
dill==0.3.5.1
cryptography==38.0.3
dill==0.3.6
future==0.18.2
github3.py==3.2.0
idna==3.3
idna==3.4
isort==5.10.1
lazy-object-proxy==1.7.1
lazy-object-proxy==1.8.0
mccabe==0.7.0
pefile==2022.5.30
platformdirs==2.5.2
platformdirs==2.5.4
pycparser==2.21
PyJWT==2.4.0
pylint==2.14.5
PyJWT==2.6.0
pylint==2.15.5
python-dateutil==2.8.2
./scripts/dev/pylint_checkers
requests==2.28.1
six==1.16.0
tomli==2.0.1
tomlkit==0.11.4
tomlkit==0.11.6
typed-ast==1.5.4 ; python_version<"3.8"
typing_extensions==4.3.0
typing_extensions==4.4.0
uritemplate==4.1.1
# urllib3==1.26.11
# urllib3==1.26.12
wrapt==1.14.1

View File

@ -1,10 +1,10 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
build==0.8.0
certifi==2022.6.15
build==0.9.0
certifi==2022.9.24
charset-normalizer==2.1.1
docutils==0.19
idna==3.3
idna==3.4
packaging==21.3
pep517==0.13.0
Pygments==2.13.0
@ -12,4 +12,4 @@ pyparsing==3.0.9
pyroma==4.0
requests==2.28.1
tomli==2.0.1
urllib3==1.26.11
urllib3==1.26.12

View File

@ -4,8 +4,13 @@ PyYAML
## Only used on macOS to make borderless windows resizable
# Not needed anymore with Qt 6.3, but we can't express that
# here, and it won't hurt either.
pyobjc-core
pyobjc-framework-Cocoa
## our recompile_requirements.py can't really deal with
## platform-specific dependencies unfortunately...
# pyobjc-core
# pyobjc-framework-Cocoa
#@ add: # Unpinned due to recompile_requirements.py limitations
#@ add: pyobjc-core ; sys_platform=="darwin"
#@ add: pyobjc-framework-Cocoa ; sys_platform=="darwin"
## stdlib backports
importlib-resources
@ -22,5 +27,3 @@ typing_extensions # from importlib-metadata
#@ markers: importlib-resources python_version=="3.7.*" or python_version=="3.8.*"
#@ markers: importlib-metadata python_version=="3.7.*"
#@ markers: typing_extensions python_version<"3.8"
#@ markers: pyobjc-core sys_platform=="darwin"
#@ markers: pyobjc-framework-Cocoa sys_platform=="darwin"

View File

@ -1,27 +1,27 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
alabaster==0.7.12
Babel==2.10.3
certifi==2022.6.15
Babel==2.11.0
certifi==2022.9.24
charset-normalizer==2.1.1
docutils==0.19
idna==3.3
idna==3.4
imagesize==1.4.1
importlib-metadata==4.12.0
importlib-metadata==5.0.0
Jinja2==3.1.2
MarkupSafe==2.1.1
packaging==21.3
Pygments==2.13.0
pyparsing==3.0.9
pytz==2022.2.1
pytz==2022.6
requests==2.28.1
snowballstemmer==2.2.0
Sphinx==5.1.1
Sphinx==5.3.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
urllib3==1.26.11
zipp==3.8.1
urllib3==1.26.12
zipp==3.10.0

View File

@ -9,7 +9,9 @@ git+https://github.com/HypothesisWorks/hypothesis.git#subdirectory=hypothesis-py
git+https://github.com/pytest-dev/pytest.git
git+https://github.com/pytest-dev/pytest-bdd.git
git+https://github.com/ionelmc/pytest-benchmark.git
git+https://github.com/pytest-dev/pytest-instafail.git
# WORKAROUND for pytest-instafail using deprectated pytest functionality
# See https://github.com/pytest-dev/pytest-instafail/pull/26
git+https://github.com/The-Compiler/pytest-instafail.git@new-hookimpl
git+https://github.com/pytest-dev/pytest-mock.git
git+https://github.com/pytest-dev/pytest-qt.git
git+https://github.com/pytest-dev/pytest-rerunfailures.git

View File

@ -2,47 +2,44 @@
attrs==22.1.0
beautifulsoup4==4.11.1
certifi==2022.6.15
certifi==2022.9.24
charset-normalizer==2.1.1
cheroot==8.6.0
click==8.1.3
coverage==6.4.4
exceptiongroup==1.0.0rc8
coverage==6.5.0
exceptiongroup==1.0.2
execnet==1.9.0
filelock==3.8.0
Flask==2.2.2
glob2==0.7
hunter==3.4.3
hypothesis==6.54.4
idna==3.3
importlib-metadata==4.12.0
hunter==3.5.1
hypothesis==6.56.4
idna==3.4
importlib-metadata==5.0.0
iniconfig==1.1.1
itsdangerous==2.1.2
jaraco.functools==3.5.1
jaraco.functools==3.5.2
# Jinja2==3.1.2
Mako==1.2.1
Mako==1.2.3
manhole==1.8.0
# MarkupSafe==2.1.1
more-itertools==8.14.0
more-itertools==9.0.0
packaging==21.3
parse==1.19.0
parse-type==0.6.0
pluggy==1.0.0
py==1.11.0
py-cpuinfo==8.0.0
py-cpuinfo==9.0.0
Pygments==2.13.0
pyparsing==3.0.9
pytest==7.1.2
pytest-bdd==6.0.1
pytest-benchmark==3.4.1
pytest-cov==3.0.0
pytest-forked==1.4.0
pytest==7.2.0
pytest-bdd==6.1.1
pytest-benchmark==4.0.0
pytest-cov==4.0.0
pytest-instafail==0.4.2
pytest-mock==3.8.2
pytest-qt==4.1.0
pytest-mock==3.10.0
pytest-qt==4.2.0
pytest-repeat==0.9.1
pytest-rerunfailures==10.2
pytest-xdist==2.5.0
pytest-xdist==3.0.2
pytest-xvfb==2.0.0
PyVirtualDisplay==3.0
requests==2.28.1
@ -50,10 +47,11 @@ requests-file==1.5.1
six==1.16.0
sortedcontainers==2.4.0
soupsieve==2.3.2.post1
tldextract==3.3.1
tldextract==3.4.0
toml==0.10.2
tomli==2.0.1
urllib3==1.26.11
vulture==2.5
typing_extensions==4.4.0
urllib3==1.26.12
vulture==2.6
Werkzeug==2.2.2
zipp==3.8.1
zipp==3.10.0

View File

@ -1,16 +1,16 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
distlib==0.3.5
distlib==0.3.6
filelock==3.8.0
packaging==21.3
pip==22.2.2
platformdirs==2.5.2
pip==22.3.1
platformdirs==2.5.4
pluggy==1.0.0
py==1.11.0
pyparsing==3.0.9
setuptools==65.2.0
setuptools==65.5.1
six==1.16.0
toml==0.10.2
tox==3.25.1
virtualenv==20.16.3
wheel==0.37.1
tomli==2.0.1
tox==3.27.0
virtualenv==20.16.7
wheel==0.38.4

View File

@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
toml==0.10.2
vulture==2.5
vulture==2.6

View File

@ -1,5 +1,5 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
pathspec==0.9.0
pathspec==0.10.2
PyYAML==6.0
yamllint==1.27.1
yamllint==1.28.0

View File

@ -80,7 +80,7 @@ The following userscripts can be found on their own repositories.
- [1password](https://github.com/tomoakley/dotfiles/blob/master/qutebrowser/userscripts/1password):
Integration with 1password on macOS.
- [localhost](https://github.com/SidharthArya/.qutebrowser/blob/master/userscripts/localhost):
Quickly navigate to localhost:port. For reference: [A quicker way to reach localhost with qutebrowser](https://sidhartharya.me/a-quicker-way-to-reach-localhost-with-qutebrowser/)
Quickly navigate to localhost:port. For reference: [A quicker way to reach localhost with qutebrowser](https://blog.sidhartharya.com/a-quicker-way-to-reach-localhost-with-qutebrowser/)
- [untrack-url](https://github.com/qutebrowser/qutebrowser/discussions/6555),
convert various URLs (YouTube/Reddit/Twitter/Instagram/Google Maps) to other
services (Invidious, Teddit, Nitter, Bibliogram, OpenStreetMap).
@ -100,6 +100,12 @@ The following userscripts can be found on their own repositories.
- [qute-containers](https://github.com/s-praveen-kumar/qute-containers):
A simple interface to manage browser containers by manipulating the basedir
parameter.
- [qutebrowser-metascript](https://codeberg.org/mister_monster/qutebrowser-metascript):
A user configurable arbitrary sequential command running userscript for qutebrowser
- [tab-manager](https://codeberg.org/mister_monster/tab-manager):
More powerfully manage single window sessions
- [qutebrowser-url-mutator](https://codeberg.org/mister_monster/qutebrowser-url-mutator):
automatically mutates input URLs based on configurable rules
[Zotero]: https://www.zotero.org/
[Pocket]: https://getpocket.com/

View File

@ -47,7 +47,7 @@ with codecs.open(os.environ['QUTE_HTML'], 'r', 'utf-8') as source:
try:
from breadability.readable import Article as reader
doc = reader(data)
doc = reader(data, os.environ['QUTE_URL'])
title = doc._original_document.title
content = HEADER % title + doc.readable + "</html>"
except ImportError:

View File

@ -35,6 +35,7 @@ markers =
fake_os: Fake utils.is_* to a fake operating system
unicode_locale: Tests which need a unicode locale to work
qtwebkit_pdf_imageformat_skip: Broken on QtWebKit with PDF image format plugin installed
qtwebkit_openssl3_skip: Broken due to cheroot bug with OpenSSL 3 on QtWebKit
windows_skip: Tests which should be skipped on Windows
qt5_only: Tests which should only run with Qt 5
qt6_only: Tests which should only run with Qt 6
@ -62,4 +63,6 @@ filterwarnings =
# https://github.com/HypothesisWorks/hypothesis/issues/3309
ignore:module 'sre_constants' is deprecated:DeprecationWarning
ignore:module 'sre_parse' is deprecated:DeprecationWarning
# https://github.com/pytest-dev/pytest-instafail/pull/26
ignore:The hookimpl pytest_.* uses old-style configuration options:pytest.PytestDeprecationWarning:pytest_instafail
faulthandler_timeout = 90

View File

@ -233,7 +233,7 @@ class argument: # noqa: N801,N806 pylint: disable=invalid-name
self._argname))
if not hasattr(func, 'qute_args'):
func.qute_args = {} # type: ignore[attr-defined]
elif func.qute_args is None: # type: ignore[attr-defined]
elif func.qute_args is None:
raise ValueError("@cmdutils.argument got called above (after) "
"@cmdutils.register for {}!".format(funcname))

View File

@ -1191,8 +1191,9 @@ class CommandDispatcher:
env['QUTE_TAB_INDEX'] = str(idx + 1)
env['QUTE_TITLE'] = self._tabbed_browser.widget.page_title(idx)
# FIXME:qtwebengine: If tab is None, run_async will fail!
tab = self._tabbed_browser.widget.currentWidget()
if tab is None:
raise cmdutils.CommandError("No current tab!")
try:
url = self._tabbed_browser.current_url()

View File

@ -165,7 +165,6 @@ class Completer(QObject):
# cursor is in a space between two existing words
parts.insert(i, '')
prefix = [x.strip() for x in parts[:i]]
# pylint: disable-next=unnecessary-list-index-lookup
center = parts[i].strip()
# strip trailing whitespace included as a separate token
postfix = [x.strip() for x in parts[i+1:] if not x.isspace()]

View File

@ -1507,11 +1507,10 @@ fileselect.handler:
- default: "Use the default file selector."
- external: "Use an external command."
desc: >-
Handler for selecting file(s) in forms.
If `external`, then the commands specified by
`fileselect.single_file.command` and
`fileselect.multiple_files.command` are used to select one or
multiple files respectively.
Handler for selecting file(s) in forms. If `external`, then the commands
specified by `fileselect.single_file.command`,
`fileselect.multiple_files.command` and `fileselect.folder.command` are
used to select one file, multiple files, and folders, respectively.
fileselect.single_file.command:
type:

View File

@ -170,8 +170,7 @@ class StateConfig(configparser.ConfigParser):
"""Detect a qutebrowser version change."""
old_qutebrowser_version = self['general'].get('version', None)
if old_qutebrowser_version is None:
# https://github.com/python/typeshed/issues/2093
return # type: ignore[unreachable]
return
try:
old_version = utils.VersionNumber.parse(old_qutebrowser_version)

View File

@ -197,8 +197,12 @@ window._qutebrowser.webelem = (function() {
try {
frame.document; // eslint-disable-line no-unused-expressions
return true;
} catch (err) {
return false;
} catch (exc) {
if (exc instanceof DOMException && exc.name === "SecurityError") {
// FIXME:qtwebengine This does not work for cross-origin frames.
return false;
}
throw exc;
}
}

View File

@ -287,6 +287,8 @@ class StatusBar(QWidget):
self.backforward, self.tabindex,
self.keystring, self.prog, self.clock, *self._text_widgets]:
assert isinstance(widget, QWidget)
if widget in [self.prog, self.backforward]:
widget.enabled = False # type: ignore[attr-defined]
widget.hide()
self._hbox.removeWidget(widget)
self._text_widgets.clear()

View File

@ -806,10 +806,22 @@ class TabBarStyle(QCommonStyle):
'itemPixmapRect', 'itemTextRect', 'polish', 'styleHint',
'subControlRect', 'unpolish', 'drawItemText',
'sizeFromContents', 'drawPrimitive']:
target = getattr(self._style, method)
setattr(self, method, functools.partial(target))
setattr(self, method, functools.partial(self._fusion_call, method))
super().__init__()
def _fusion_call(self, method: str, *args: Any) -> Any:
"""Wrap a call to self._style to log RuntimeErrors.
WORKAROUND for https://github.com/qutebrowser/qutebrowser/issues/5124
"""
target = getattr(self._style, method)
try:
return target(*args)
except RuntimeError:
info = f"self._style.{method}{args}"
log.misc.warning(f"Got RuntimeError while calling {info}")
raise
def _draw_indicator(self, layouts, opt, p):
"""Draw the tab indicator.

View File

@ -49,7 +49,9 @@ def check_python_version():
version_str = '.'.join(map(str, sys.version_info[:3]))
text = ("At least Python 3.7 is required to run qutebrowser, but " +
"it's running with " + version_str + ".\n")
if Tk and '--no-err-windows' not in sys.argv: # pragma: no cover
show_errors = '--no-err-windows' not in sys.argv
if Tk and show_errors: # type: ignore[truthy-function] # pragma: no cover
root = Tk()
root.withdraw()
messagebox.showerror("qutebrowser: Fatal error!", text)

View File

@ -266,18 +266,21 @@ class GUIProcess(QObject):
QProcess.ProcessError.WriteError: f"Write error for {what}",
QProcess.ProcessError.ReadError: f"Read error for {what}",
}
error_string = self._proc.errorString()
msg = ': '.join([error_descriptions[error], error_string])
# We can't get some kind of error code from Qt...
# https://bugreports.qt.io/browse/QTBUG-44769
# but we pre-resolve the executable in Python, which also checks if it's
# runnable.
if self.resolved_cmd is None: # pragma: no branch
msg += f'\nHint: Make sure {self.cmd!r} exists and is executable'
if self.resolved_cmd is None:
# No point in showing the "No program defined" we got due to
# passing None into Qt.
error_string = f"{self.cmd!r} doesn't exist or isn't executable"
if version.is_flatpak():
msg += ' inside the Flatpak container'
error_string += " inside the Flatpak container"
else: # pragma: no cover
error_string = self._proc.errorString()
msg = ': '.join([error_descriptions[error], error_string])
message.error(msg)
def _elide_output(self, output: str) -> str:

View File

@ -170,7 +170,7 @@ def _get_tab_registry(win_id: _WindowTab,
window: Optional[QWidget] = QApplication.activeWindow()
if window is None or not hasattr(window, 'win_id'):
raise RegistryUnavailableError('tab')
win_id = window.win_id # type: ignore[attr-defined]
win_id = window.win_id
elif win_id is None:
raise TypeError("window is None with scope tab!")

View File

@ -55,7 +55,7 @@ try:
CSafeDumper as YamlDumper)
YAML_C_EXT = True
except ImportError: # pragma: no cover
from yaml import (SafeLoader as YamlLoader, # type: ignore[misc]
from yaml import (SafeLoader as YamlLoader, # type: ignore[assignment]
SafeDumper as YamlDumper)
YAML_C_EXT = False

View File

@ -1,14 +1,15 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
adblock==0.6.0
colorama==0.4.5
importlib-metadata==4.12.0 ; python_version=="3.7.*"
importlib-resources==5.9.0 ; python_version=="3.7.*" or python_version=="3.8.*"
colorama==0.4.6
importlib-metadata==5.0.0 ; python_version=="3.7.*"
importlib-resources==5.10.0 ; python_version=="3.7.*" or python_version=="3.8.*"
Jinja2==3.1.2
MarkupSafe==2.1.1
Pygments==2.13.0
pyobjc-core==8.5 ; sys_platform=="darwin"
pyobjc-framework-Cocoa==8.5 ; sys_platform=="darwin"
PyYAML==6.0
typing_extensions==4.3.0 ; python_version<"3.8"
zipp==3.8.1
typing_extensions==4.4.0 ; python_version<"3.8"
zipp==3.10.0
# Unpinned due to recompile_requirements.py limitations
pyobjc-core ; sys_platform=="darwin"
pyobjc-framework-Cocoa ; sys_platform=="darwin"

View File

@ -73,7 +73,7 @@ class AsciiDoc:
def cleanup(self) -> None:
"""Clean up the temporary home directory for asciidoc."""
if self._homedir is not None and not self._failed:
shutil.rmtree(str(self._homedir))
shutil.rmtree(self._homedir)
def build(self) -> None:
"""Build either the website or the docs."""
@ -119,7 +119,7 @@ class AsciiDoc:
for filename in ['cheatsheet-big.png', 'cheatsheet-small.png']:
src = REPO_ROOT / 'doc' / 'img' / filename
dst = dst_path / filename
shutil.copy(str(src), str(dst))
shutil.copy(src, dst)
def _build_website_file(self, root: pathlib.Path, filename: str) -> None:
"""Build a single website file."""
@ -131,7 +131,7 @@ class AsciiDoc:
assert self._tempdir is not None # for mypy
modified_src = self._tempdir / src.name
shutil.copy(str(REPO_ROOT / 'www' / 'header.asciidoc'), modified_src)
shutil.copy(REPO_ROOT / 'www' / 'header.asciidoc', modified_src)
outfp = io.StringIO()

View File

@ -8,7 +8,6 @@
"mccabe": "https://github.com/PyCQA/mccabe#changes",
"pytest-cov": "https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst",
"pytest-xdist": "https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst",
"pytest-forked": "https://github.com/pytest-dev/pytest-forked/blob/master/CHANGELOG.rst",
"pytest-xvfb": "https://github.com/The-Compiler/pytest-xvfb/blob/master/CHANGELOG.rst",
"PyVirtualDisplay": "https://github.com/ponty/PyVirtualDisplay/commits/master",
"execnet": "https://execnet.readthedocs.io/en/latest/changelog.html",
@ -24,11 +23,10 @@
"soupsieve": "https://facelessuser.github.io/soupsieve/about/changelog/",
"Flask": "https://flask.palletsprojects.com/en/latest/changes/",
"Mako": "https://docs.makotemplates.org/en/latest/changelog.html",
"glob2": "https://github.com/miracle2k/python-glob2/blob/master/CHANGES",
"hypothesis": "https://hypothesis.readthedocs.io/en/latest/changes.html",
"exceptiongroup": "https://github.com/agronholm/exceptiongroup/blob/main/CHANGES.rst",
"mypy": "https://mypy-lang.blogspot.com/",
"types-PyYAML": "https://github.com/python/typeshed/commits/master/stubs/PyYAML",
"types-PyYAML": "https://github.com/python/typeshed/commits/main/stubs/PyYAML",
"pytest": "https://docs.pytest.org/en/latest/changelog.html",
"iniconfig": "https://github.com/pytest-dev/iniconfig/blob/master/CHANGELOG",
"tox": "https://tox.readthedocs.io/en/latest/changelog.html",
@ -150,6 +148,7 @@
"bleach": "https://github.com/mozilla/bleach/blob/main/CHANGES",
"jeepney": "https://gitlab.com/takluyver/jeepney/-/blob/master/docs/release-notes.rst",
"keyring": "https://github.com/jaraco/keyring/blob/main/CHANGES.rst",
"jaraco.classes": "https://github.com/jaraco/jaraco.classes/blob/main/CHANGES.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",
"requests-toolbelt": "https://github.com/requests/toolbelt/blob/master/HISTORY.rst",

View File

@ -15,7 +15,8 @@ RUN pacman -Suyy --noconfirm \
{% else %}
qt5-base \
qt5-declarative \
{% if webengine %}qt5-webengine python-pyqt5-webengine{% else %}qt5-webkit{% endif %} \
{% if webengine %}
qt5-webengine python-pyqtwebengine \
python-pyqt5 \
{% endif %}
xorg-xinit \
@ -25,6 +26,18 @@ RUN pacman -Suyy --noconfirm \
libyaml \
xorg-xdpyinfo
{% if not webengine %}
RUN pacman -U --noconfirm \
https://archive.archlinux.org/packages/q/qt5-webkit/qt5-webkit-5.212.0alpha4-18-x86_64.pkg.tar.zst \
https://archive.archlinux.org/packages/p/python-pyqt5/python-pyqt5-5.15.7-2-x86_64.pkg.tar.zst
{% endif %}
{% if webengine %}
RUN python3 -c "from PyQt5 import QtWebEngineCore, QtWebEngineWidgets"
{% else %}
RUN python3 -c "from PyQt5 import QtWebKit, QtWebKitWidgets"
{% endif %}
RUN useradd user -u 1001 && \
mkdir /home/user && \
chown user:users /home/user

View File

@ -27,7 +27,7 @@ import jinja2
def main():
with open('Dockerfile.j2') as f:
template = jinja2.Template(f.read())
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
image = sys.argv[1]
config = {

View File

@ -38,7 +38,7 @@ from scripts import utils
from scripts.dev import recompile_requirements
BINARY_EXTS = {'.png', '.icns', '.ico', '.bmp', '.gz', '.bin', '.pdf',
'.sqlite', '.woff2', '.whl'}
'.sqlite', '.woff2', '.whl', '.egg'}
def _get_files(
@ -64,7 +64,7 @@ def _get_files(
continue
try:
with tokenize.open(str(path)):
with tokenize.open(path):
pass
except SyntaxError as e:
# Could not find encoding
@ -275,7 +275,7 @@ def check_spelling(args: argparse.Namespace) -> Optional[bool]:
try:
ok = True
for path in _get_files(verbose=args.verbose, ignored=ignored):
with tokenize.open(str(path)) as f:
with tokenize.open(path) as f:
if not _check_spelling_file(path, f, patterns):
ok = False
print()
@ -325,7 +325,7 @@ def check_vcs_conflict(args: argparse.Namespace) -> Optional[bool]:
if path.suffix in {'.rst', '.asciidoc'}:
# False positives
continue
with tokenize.open(str(path)) as f:
with tokenize.open(path) as f:
for line in f:
if any(line.startswith(c * 7) for c in '<>=|'):
print("Found conflict marker in {}".format(path))

View File

@ -42,6 +42,7 @@ def wrap(ini, sub, string):
return textwrap.wrap(string, width=80, initial_indent=ini, subsequent_indent=sub)
# pylint: disable-next=missing-timeout
response = requests.get('https://raw.githubusercontent.com/Kikobeats/top-user-agents/master/index.json')
if response.status_code != 200:

View File

@ -40,7 +40,7 @@ from qutebrowser.config import configdata
from qutebrowser.utils import standarddir
API_URL = 'https://chromium.googlesource.com/chromium/deps/hunspell_dictionaries.git/+/master/'
API_URL = 'https://chromium.googlesource.com/chromium/deps/hunspell_dictionaries.git/+/main/'
class InvalidLanguageError(Exception):

View File

@ -197,7 +197,7 @@ def delete_old_venv(venv_dir: pathlib.Path) -> None:
'remove it.'.format(venv_dir))
print_command('rm -r', venv_dir, venv=False)
shutil.rmtree(str(venv_dir))
shutil.rmtree(venv_dir)
def create_venv(venv_dir: pathlib.Path, use_virtualenv: bool = False) -> None:

View File

@ -22,6 +22,7 @@
import os
import pathlib
import sys
import ssl
import pytest
import hypothesis
@ -122,6 +123,10 @@ def _apply_platform_markers(config, item):
f"Only runs on Qt 6, not {machinery.WRAPPER}"),
('qt5_xfail', pytest.mark.xfail, machinery.IS_QT5, "Fails on Qt 5"),
('qt6_xfail', pytest.mark.skipif, machinery.IS_QT6, "Fails on Qt 6"),
('qtwebkit_openssl3_skip',
pytest.mark.skipif,
not config.webengine and ssl.OPENSSL_VERSION_INFO[0] == 3,
"Failing due to cheroot: https://github.com/cherrypy/cheroot/issues/346"),
]
for searched_marker, new_marker_kind, condition, default_reason in markers:

View File

@ -171,6 +171,7 @@ Feature: Prompts
Then the error "Certificate error: *" should be shown
And the page should contain the plaintext "Hello World via SSL!"
@qtwebkit_openssl3_skip
Scenario: SSL error with content.tls.certificate_errors = block
When I clear SSL errors
And I set content.tls.certificate_errors to block
@ -186,6 +187,7 @@ Feature: Prompts
And I wait until the SSL page finished loading
Then the page should contain the plaintext "Hello World via SSL!"
@qtwebkit_openssl3_skip
Scenario: SSL error with content.tls.certificate_errors = ask -> no
When I clear SSL errors
And I set content.tls.certificate_errors to ask
@ -194,6 +196,7 @@ Feature: Prompts
And I run :prompt-accept no
Then a SSL error page should be shown
@qtwebkit_openssl3_skip
Scenario: SSL error with content.tls.certificate_errors = ask -> abort
When I clear SSL errors
And I set content.tls.certificate_errors to ask
@ -221,6 +224,7 @@ Feature: Prompts
Then the javascript message "Script loaded" should be logged
And the page should contain the plaintext "Script loaded"
@qtwebkit_openssl3_skip
Scenario: SSL resource error with content.tls.certificate_errors = ask -> no
When I clear SSL errors
And I set content.tls.certificate_errors to ask
@ -231,6 +235,7 @@ Feature: Prompts
Then the javascript message "Script loaded" should not be logged
And the page should contain the plaintext "Script not loaded"
@qtwebkit_openssl3_skip
Scenario: SSL resource error with content.tls.certificate_errors = ask-block-thirdparty
When I clear SSL errors
And I set content.tls.certificate_errors to ask-block-thirdparty

View File

@ -38,7 +38,7 @@ def download_dir(tmpdir):
downloads.ensure(dir=True)
(downloads / 'subdir').ensure(dir=True)
try:
os.mkfifo(str(downloads / 'fifo'))
os.mkfifo(downloads / 'fifo')
except AttributeError:
pass
unwritable = downloads / 'unwritable'
@ -79,7 +79,7 @@ def download_ssl_redirect(server, ssl_server, quteproc):
@bdd.when("the unwritable dir is unwritable")
def check_unwritable(tmpdir):
unwritable = tmpdir / 'downloads' / 'unwritable'
if os.access(str(unwritable), os.W_OK):
if os.access(unwritable, os.W_OK):
# Docker container or similar
pytest.skip("Unwritable dir was writable")
@ -173,4 +173,4 @@ def delete_file(tmpdir, filename):
def fifo_should_be_fifo(tmpdir):
download_dir = tmpdir / 'downloads'
assert download_dir.exists()
assert not os.path.isfile(str(download_dir / 'fifo'))
assert not os.path.isfile(download_dir / 'fifo')

View File

@ -67,4 +67,5 @@ def check_history(quteproc, server, tmpdir, expected):
@bdd.then("the history should be empty")
def check_history_empty(quteproc, server, tmpdir):
quteproc.wait_for(message='DELETE FROM History', category='sql')
check_history(quteproc, server, tmpdir, '')

View File

@ -36,7 +36,7 @@ import os.path
import dataclasses
import pytest
import py.path # pylint: disable=no-name-in-module
import py.path
from qutebrowser.qt.core import QSize, Qt
from qutebrowser.qt.widgets import QWidget, QHBoxLayout, QVBoxLayout
from qutebrowser.qt.network import QNetworkCookieJar
@ -639,7 +639,7 @@ def redirect_webengine_data(data_tmpdir, monkeypatch):
def short_tmpdir():
"""A short temporary directory for a XDG_RUNTIME_DIR."""
with tempfile.TemporaryDirectory() as tdir:
yield py.path.local(tdir) # pylint: disable=no-member
yield py.path.local(tdir)
class ModelValidator:
@ -720,7 +720,7 @@ def state_config(data_tmpdir, monkeypatch):
@pytest.fixture
def unwritable_tmp_path(tmp_path):
tmp_path.chmod(0)
if os.access(str(tmp_path), os.W_OK):
if os.access(tmp_path, os.W_OK):
# Docker container or similar
pytest.skip("Directory was still writable")

View File

@ -220,11 +220,11 @@ def nop_contextmanager():
def change_cwd(path):
"""Use a path as current working directory."""
old_cwd = pathlib.Path.cwd()
os.chdir(str(path))
os.chdir(path)
try:
yield
finally:
os.chdir(str(old_cwd))
os.chdir(old_cwd)
@contextlib.contextmanager

View File

@ -178,7 +178,7 @@ def unreadable_file(tmpdir):
unreadable_file = tmpdir / 'unreadable'
unreadable_file.ensure()
unreadable_file.chmod(0)
if os.access(str(unreadable_file), os.R_OK):
if os.access(unreadable_file, os.R_OK):
# Docker container or similar
pytest.skip("File was still readable")

View File

@ -23,7 +23,7 @@ import os
import time
import logging
import py.path # pylint: disable=no-name-in-module
import py.path
from qutebrowser.qt.core import QUrl, QUrlQuery
import pytest
@ -223,7 +223,7 @@ class TestPDFJSHandler:
@pytest.fixture
def download_tmpdir(self):
tdir = downloads.temp_download_manager.get_tmpdir()
yield py.path.local(tdir.name) # pylint: disable=no-member
yield py.path.local(tdir.name)
tdir.cleanup()
def test_existing_resource(self):

View File

@ -48,7 +48,7 @@ def test_get_file_list(tmpdir, create_file, create_dir, filterfunc, expected):
if create_file or create_dir:
path.ensure(dir=create_dir)
all_files = os.listdir(str(tmpdir))
all_files = os.listdir(tmpdir)
result = filescheme.get_file_list(str(tmpdir), all_files, filterfunc)
item = {'name': 'foo', 'absname': str(path)}

View File

@ -201,6 +201,10 @@ def test_killed_command(qtbot, tmp_path, py_proc, runner, caplog):
runner.store_text('Hello World')
runner.store_html('')
# For some reason, this tends to be flaky on Windows, and we got the
# directoryChanged signal *without* the file existing (wut?)...
qtbot.wait_until(data_file.exists)
# Make sure the PID was written to the file, not just the file created
time.sleep(0.5)

View File

@ -596,7 +596,7 @@ class TestYaml:
def unreadable_autoconfig(self, autoconfig):
autoconfig.fobj.ensure()
autoconfig.fobj.chmod(0)
if os.access(str(autoconfig.fobj), os.R_OK):
if os.access(autoconfig.fobj, os.R_OK):
# Docker container or similar
pytest.skip("File was still readable")

View File

@ -31,55 +31,72 @@ def backforward_widget(qtbot):
return widget
@pytest.fixture
def tabs(tabbed_browser_stubs):
tabbed_browser = tabbed_browser_stubs[0]
tabbed_browser.widget.current_index = 1
return tabbed_browser
@pytest.mark.parametrize('can_go_back, can_go_forward, expected_text', [
(False, False, ''),
(True, False, '[<]'),
(False, True, '[>]'),
(True, True, '[<>]'),
])
def test_backforward_widget(backforward_widget, tabbed_browser_stubs,
fake_web_tab, can_go_back, can_go_forward,
expected_text):
def test_widget_state(backforward_widget, tabs,
fake_web_tab, can_go_back, can_go_forward,
expected_text):
"""Ensure the Backforward widget shows the correct text."""
tab = fake_web_tab(can_go_back=can_go_back, can_go_forward=can_go_forward)
tabbed_browser = tabbed_browser_stubs[0]
tabbed_browser.widget.current_index = 1
tabbed_browser.widget.tabs = [tab]
tabs.widget.tabs = [tab]
backforward_widget.enabled = True
backforward_widget.on_tab_cur_url_changed(tabbed_browser)
backforward_widget.on_tab_cur_url_changed(tabs)
assert backforward_widget.text() == expected_text
assert backforward_widget.isVisible() == bool(expected_text)
# Check that the widget stays hidden if not in the statusbar
backforward_widget.enabled = False
backforward_widget.hide()
backforward_widget.on_tab_cur_url_changed(tabbed_browser)
assert backforward_widget.isHidden()
# Check that the widget gets reset if empty.
if can_go_back and can_go_forward:
tab = fake_web_tab(can_go_back=False, can_go_forward=False)
tabbed_browser.widget.tabs = [tab]
backforward_widget.enabled = True
backforward_widget.on_tab_cur_url_changed(tabbed_browser)
assert backforward_widget.text() == ''
assert not backforward_widget.isVisible()
def test_state_changes_on_tab_change(backforward_widget, tabs, fake_web_tab):
"""Test we go invisible when switching to a tab without history."""
tab_with_history = fake_web_tab(can_go_back=True, can_go_forward=True)
tab_without_history = fake_web_tab(can_go_back=False, can_go_forward=False)
tabs.widget.tabs = [tab_with_history]
backforward_widget.enabled = True
backforward_widget.on_tab_cur_url_changed(tabs)
assert backforward_widget.isVisible()
tabs.widget.tabs = [tab_without_history]
backforward_widget.on_tab_cur_url_changed(tabs)
assert backforward_widget.text() == ''
assert not backforward_widget.isVisible()
def test_none_tab(backforward_widget, tabbed_browser_stubs, fake_web_tab):
def test_none_tab(backforward_widget, tabs, fake_web_tab):
"""Make sure nothing crashes when passing None as tab."""
tab = fake_web_tab(can_go_back=True, can_go_forward=True)
tabbed_browser = tabbed_browser_stubs[0]
tabbed_browser.widget.current_index = 1
tabbed_browser.widget.tabs = [tab]
tabs.widget.tabs = [tab]
backforward_widget.enabled = True
backforward_widget.on_tab_cur_url_changed(tabbed_browser)
backforward_widget.on_tab_cur_url_changed(tabs)
assert backforward_widget.text() == '[<>]'
assert backforward_widget.isVisible()
tabbed_browser.widget.current_index = -1
backforward_widget.on_tab_cur_url_changed(tabbed_browser)
tabs.widget.current_index = -1
backforward_widget.on_tab_cur_url_changed(tabs)
assert backforward_widget.text() == ''
assert not backforward_widget.isVisible()
def test_not_shown_when_disabled(backforward_widget, tabs, fake_web_tab):
"""The widget shouldn't get shown on an event when it's disabled."""
tab = fake_web_tab(can_go_back=True, can_go_forward=True)
tabs.widget.tabs = [tab]
backforward_widget.enabled = False
backforward_widget.on_tab_cur_url_changed(tabs)
assert not backforward_widget.isVisible()
backforward_widget.on_tab_changed(tab)
assert not backforward_widget.isVisible()

View File

@ -69,6 +69,14 @@ def test_tab_changed(fake_web_tab, progress_widget, progress, load_status,
assert actual == expected
def test_not_shown_when_disabled(progress_widget, fake_web_tab):
"""The widget shouldn't get shown on an event when it's disabled."""
tab = fake_web_tab(progress=15, load_status=usertypes.LoadStatus.loading)
progress_widget.enabled = False
progress_widget.on_tab_changed(tab)
assert not progress_widget.isVisible()
def test_progress_affecting_statusbar_height(config_stub, fake_statusbar,
progress_widget):
"""Make sure the statusbar stays the same height when progress is shown.

View File

@ -128,7 +128,7 @@ class TestFileHandling:
filename = pathlib.Path(editor._filename)
assert filename.exists()
filename.chmod(0o277)
if os.access(str(filename), os.R_OK):
if os.access(filename, os.R_OK):
# Docker container or similar
pytest.skip("File was still readable")

View File

@ -403,16 +403,15 @@ def test_failing_to_start(qtbot, proc, caplog, message_mock, monkeypatch, is_fla
with qtbot.wait_signal(proc.error, timeout=5000):
proc.start('this_does_not_exist_either', [])
msg = message_mock.getmsg(usertypes.MessageLevel.error)
assert msg.text.startswith(
"Testprocess 'this_does_not_exist_either' failed to start:")
expected_msg = (
"Testprocess 'this_does_not_exist_either' failed to start:"
" 'this_does_not_exist_either' doesn't exist or isn't executable"
)
if is_flatpak:
expected_msg += " inside the Flatpak container"
if not utils.is_windows:
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)
msg = message_mock.getmsg(usertypes.MessageLevel.error)
assert msg.text == expected_msg
assert not proc.outcome.running
assert proc.outcome.status is None