Merge remote-tracking branch 'upstream/main' into feat/68_permissions_askeverytime

This commit is contained in:
toofar 2024-10-29 10:22:44 +13:00
commit 7535207fd3
184 changed files with 741 additions and 713 deletions

View File

@ -58,7 +58,7 @@ ignore =
PT004,
PT011,
PT012
min-version = 3.8.0
min-version = 3.9.0
max-complexity = 12
per-file-ignores =
qutebrowser/api/hook.py : N801

View File

@ -50,7 +50,7 @@ jobs:
python-version: '3.10'
- uses: actions/setup-node@v4
with:
node-version: '16.x'
node-version: '20.x'
if: "matrix.testenv == 'eslint'"
- name: Set up problem matchers
run: "python scripts/dev/ci/problemmatchers.py ${{ matrix.testenv }} ${{ runner.temp }}"
@ -144,10 +144,10 @@ jobs:
fail-fast: false
matrix:
include:
### PyQt 5.15.2 (Python 3.8)
- testenv: py38-pyqt5152
### PyQt 5.15.2 (Python 3.9)
- testenv: py39-pyqt5152
os: ubuntu-20.04
python: "3.8"
python: "3.9"
### PyQt 5.15 (Python 3.10, with coverage)
# FIXME:qt6
# - testenv: py310-pyqt515-cov
@ -157,14 +157,14 @@ jobs:
- testenv: py311-pyqt515
os: ubuntu-20.04
python: "3.11"
### PyQt 6.2 (Python 3.8)
- testenv: py38-pyqt62
### PyQt 6.2 (Python 3.9)
- testenv: py39-pyqt62
os: ubuntu-20.04
python: "3.8"
### PyQt 6.3 (Python 3.8)
- testenv: py38-pyqt63
python: "3.9"
### PyQt 6.3 (Python 3.9)
- testenv: py39-pyqt63
os: ubuntu-20.04
python: "3.8"
python: "3.9"
## PyQt 6.4 (Python 3.9)
- testenv: py39-pyqt64
os: ubuntu-20.04

View File

@ -14,20 +14,6 @@ jobs:
fail-fast: false
matrix:
include:
- os: macos-12
toxenv: build-release-qt5
name: qt5-macos
- os: windows-2019
toxenv: build-release-qt5
name: qt5-windows
- os: macos-12
args: --debug
toxenv: build-release-qt5
name: qt5-macos-debug
- os: windows-2019
args: --debug
toxenv: build-release-qt5
name: qt5-windows-debug
- os: macos-12
toxenv: build-release
name: macos-intel

View File

@ -21,10 +21,10 @@ jobs:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Python 3.8
- name: Set up Python 3.9
uses: actions/setup-python@v5
with:
python-version: '3.8'
python-version: '3.9'
- name: Recompile requirements
run: "python3 scripts/dev/recompile_requirements.py ${{ github.event.input.environments }}"
id: requirements
@ -41,7 +41,7 @@ jobs:
- name: Run qutebrowser smoke test
run: "xvfb-run .venv/bin/python3 -m qutebrowser --no-err-windows --nowindow --temp-basedir about:blank ':later 500 quit'"
- name: Create pull request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
committer: qutebrowser bot <bot@qutebrowser.org>
author: qutebrowser bot <bot@qutebrowser.org>

View File

@ -19,7 +19,6 @@ on:
default: '3.12'
type: choice
options:
- '3.8'
- '3.9'
- '3.10'
- '3.11'

View File

@ -1,5 +1,5 @@
[mypy]
python_version = 3.8
python_version = 3.9
### --strict
warn_unused_configs = True

View File

@ -16,7 +16,7 @@ load-plugins=qute_pylint.config,
pylint.extensions.dunder
persistent=n
py-version=3.8
py-version=3.9
[MESSAGES CONTROL]
enable=all
@ -71,7 +71,8 @@ argument-rgx=[a-z_][a-z0-9_]{0,30}$
variable-rgx=[a-z_][a-z0-9_]{0,30}$
docstring-min-length=3
no-docstring-rgx=(^_|^main$)
class-const-naming-style = snake_case
class-const-naming-style=snake_case
max-positional-arguments=7
[FORMAT]
# FIXME:v4 (lint) down to 88 again once we use black

View File

@ -84,7 +84,7 @@ Requirements
The following software and libraries are required to run qutebrowser:
* https://www.python.org/[Python] 3.8 or newer
* https://www.python.org/[Python] 3.9 or newer
* https://www.qt.io/[Qt], either 6.2.0 or newer, or 5.15.0 or newer, with the following modules:
- QtCore / qtbase
- QtQuick (part of qtbase or qtdeclarative in some distributions)
@ -105,10 +105,6 @@ websites and using it for transmission of sensitive data._
* https://palletsprojects.com/p/jinja/[jinja2]
* https://github.com/yaml/pyyaml[PyYAML]
On Python 3.8, the following backport is also required:
* https://importlib-resources.readthedocs.io/[importlib_resources]
On macOS, the following libraries are also required:
* https://pyobjc.readthedocs.io/en/latest/[pyobjc-core and pyobjc-framework-Cocoa]

View File

@ -22,11 +22,17 @@ v3.4.0 (unreleased)
Deprecated
~~~~~~~~~~
- **In either this (v3.4.0) or the next release (v3.5.0)**, support for Python
3.8 will be dropped, and Python 3.9 will be required.
- **In the next release (v3.5.0)**, support for macOS 12 Monterey will be
dropped, and binaries will be built on macOS 13 Ventura.
Removed
~~~~~~~
- Support for Python 3.8 is dropped, and Python 3.9 is now required.
- When using the installer on Windows 10, build 1809 or newer is now required
(previous versions required 1607 or newer, but that's not officialy supported by
Qt upstream).
Added
~~~~~
@ -38,8 +44,18 @@ Added
Changed
~~~~~~~
- The `.desktop` file now also declares qutebrowser as a valid viewer for
`image/webp`.
- Updated mimetype information for getting a suitable extension when downloading
a `data:` URL.
- The `content.javascript.clipboard` setting now defaults to "ask".
Fixed
~~~~~
- Crash with recent Jinja/Markupsafe versions when viewing a finished userscript
(or potentially editor) process via `:process`.
[[v3.3.1]]
v3.3.1 (2024-10-12)

View File

@ -111,9 +111,9 @@ unittests and several linters/checkers.
Currently, the following tox environments are available:
* Tests using https://www.pytest.org[pytest]:
- `py38`, `py39`, ...: Run pytest for python 3.8/3.9/... with the system-wide PyQt.
- `py38-pyqt515`, ..., `py38-pyqt65`: Run pytest with the given PyQt version (`py39-*` etc. also works).
- `py38-pyqt515-cov`: Run with coverage support (other Python/PyQt versions work too).
- `py39`, `py310`, ...: Run pytest for python 3.9/3.10/... with the system-wide PyQt.
- `py39-pyqt515`, ..., `py39-pyqt65`: Run pytest with the given PyQt version (`py310-*` etc. also works).
- `py39-pyqt515-cov`: Run with coverage support (other Python/PyQt versions work too).
* `flake8`: Run various linting checks via https://pypi.python.org/pypi/flake8[flake8].
* `vulture`: Run https://pypi.python.org/pypi/vulture[vulture] to find
unused code portions.
@ -171,16 +171,16 @@ Examples:
----
# run only pytest tests which failed in last run:
tox -e py38 -- --lf
tox -e py39 -- --lf
# run only the end2end feature tests:
tox -e py38 -- tests/end2end/features
tox -e py39 -- tests/end2end/features
# run everything with undo in the generated name, based on the scenario text
tox -e py38 -- tests/end2end/features/test_tabs_bdd.py -k undo
tox -e py39 -- tests/end2end/features/test_tabs_bdd.py -k undo
# run coverage test for specific file (updates htmlcov/index.html)
tox -e py38-cov -- tests/unit/browser/test_webelem.py
tox -e py39-cov -- tests/unit/browser/test_webelem.py
----
Specifying the backend for tests

View File

@ -452,7 +452,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]
- https://git.sr.ht/~willvaughn/dots/tree/main/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

@ -3891,7 +3891,7 @@ Chromium has various sandboxing layers, which should be enabled for normal brows
Open `chrome://sandbox` to see the current sandbox status.
Changing this setting is only recommended if you know what you're doing, as it **disables one of Chromium's security layers**. To avoid sandboxing being accidentally disabled persistently, this setting can only be set via `config.py`, not via `:set`.
See the Chromium documentation for more details:
- https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/linux/sandboxing.md[Linux] - https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/design/sandbox.md[Windows] - https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/design/sandbox_faq.md[FAQ (Windows-centric)]
- https://chromium.googlesource.com/chromium/src/\+/HEAD/sandbox/linux/README.md[Linux] - https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/design/sandbox.md[Windows] - https://chromium.googlesource.com/chromium/src/\+/HEAD/sandbox/mac/README.md[Mac] - https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/design/sandbox_faq.md[FAQ (Windows-centric)]
This setting requires a restart.

View File

@ -438,7 +438,7 @@ This installs all needed Python dependencies in a `.venv` subfolder
This comes with an up-to-date Qt/PyQt including a pre-compiled QtWebEngine
binary, but has a few caveats:
- Make sure your `python3` is Python 3.8 or newer, otherwise you'll get a "No
- Make sure your `python3` is Python 3.9 or newer, otherwise you'll get a "No
matching distribution found" error and/or qutebrowser will not run.
- It only works on 64-bit x86 systems, with other architectures you'll get the
same error.

View File

@ -432,32 +432,18 @@ Function .onInit
StrCpy $KeepReg 1
; OS version check
${If} ${RunningX64}
; https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa#remarks
GetWinVer $R0 Major
!if "${QT5}" == "True"
IntCmpU $R0 6 0 _os_check_fail _os_check_pass
GetWinVer $R1 Minor
IntCmpU $R1 2 _os_check_pass _os_check_fail _os_check_pass
!else
IntCmpU $R0 10 0 _os_check_fail _os_check_pass
GetWinVer $R1 Build
${If} $R1 >= 22000 ; Windows 11 21H2
Goto _os_check_pass
${ElseIf} $R1 >= 14393 ; Windows 10 1607
${AndIf} ${IsNativeAMD64} ; Windows 10 has no x86_64 emulation on arm64
Goto _os_check_pass
${EndIf}
!endif
; https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa#remarks
; https://learn.microsoft.com/en-us/windows/release-health/release-information
; https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
${If} ${AtLeastWin11}
Goto _os_check_pass
${ElseIf} ${IsNativeAMD64} ; Windows 10 has no x86_64 emulation on arm64
${AndIf} ${AtLeastWin10}
${AndIf} ${AtLeastBuild} 17763 ; Windows 10 1809 (also in error message below)
Goto _os_check_pass
${EndIf}
_os_check_fail:
!if "${QT5}" == "True"
MessageBox MB_OK|MB_ICONSTOP "This version of ${PRODUCT_NAME} requires a 64-bit$\r$\n\
version of Windows 8 or later."
!else
MessageBox MB_OK|MB_ICONSTOP "This version of ${PRODUCT_NAME} requires a 64-bit$\r$\n\
version of Windows 10 1607 or later."
!endif
MessageBox MB_OK|MB_ICONSTOP "This version of ${PRODUCT_NAME} requires a 64-bit$\r$\n\
version of Windows 10 1809 or later."
Abort
_os_check_pass:

View File

@ -131,9 +131,6 @@ ShowUninstDetails hide
!define /ifndef DIST_DIR ".\..\..\dist\${PRODUCT_NAME}-${VERSION}"
!endif
; If not defined, assume Qt6 (requires a more recent windows version)
!define /ifndef QT5 "False"
; Pack the exe header with upx if UPX is defined.
!ifdef UPX
!packhdr "$%TEMP%\exehead.tmp" '"upx" "--ultra-brute" "$%TEMP%\exehead.tmp"'

View File

@ -48,7 +48,7 @@ Categories=Network;WebBrowser;
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;
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rdf+xml;image/gif;image/webp;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/qute;
Keywords=Browser
Actions=new-window;preferences;

View File

@ -1,9 +1,9 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
build==1.2.2
check-manifest==0.49
build==1.2.2.post1
check-manifest==0.50
importlib_metadata==8.5.0
packaging==24.1
pyproject_hooks==1.2.0
tomli==2.0.1
tomli==2.0.2
zipp==3.20.2

View File

@ -2,13 +2,13 @@
autocommand==2.2.2
backports.tarfile==1.2.0
build==1.2.2
build==1.2.2.post1
bump2version==1.0.1
certifi==2024.8.30
cffi==1.17.1
charset-normalizer==3.3.2
cryptography==43.0.1
docutils==0.20.1
charset-normalizer==3.4.0
cryptography==43.0.3
docutils==0.21.2
github3.py==4.0.1
hunter==3.7.0
idna==3.10
@ -37,15 +37,15 @@ Pympler==1.1
pyproject_hooks==1.2.0
PyQt-builder==1.16.4
python-dateutil==2.9.0.post0
readme_renderer==43.0
readme_renderer==44.0
requests==2.32.3
requests-toolbelt==1.0.0
rfc3986==2.0.0
rich==13.8.1
rich==13.9.2
SecretStorage==3.3.3
sip==6.8.6
six==1.16.0
tomli==2.0.1
tomli==2.0.2
twine==5.1.1
typeguard==4.3.0
typing_extensions==4.12.2

View File

@ -9,6 +9,7 @@ twine
# Included to override setuptools' vendored version that is being included in
# the lock file by pip freeze.
importlib_resources
platformdirs
# Already included via test requirements

View File

@ -2,20 +2,18 @@
chardet==5.2.0
diff_cover==9.2.0
importlib_resources==6.4.5
Jinja2==3.1.4
lxml==5.3.0
MarkupSafe==2.1.5
mypy==1.11.2
MarkupSafe==3.0.2
mypy==1.12.1
mypy-extensions==1.0.0
pluggy==1.5.0
Pygments==2.18.0
PyQt5-stubs==5.15.6.0
tomli==2.0.1
tomli==2.0.2
types-colorama==0.4.15.20240311
types-docutils==0.21.0.20240907
types-docutils==0.21.0.20241005
types-Pygments==2.18.0.20240506
types-PyYAML==6.0.12.20240917
types-setuptools==75.1.0.20240917
types-setuptools==75.2.0.20241019
typing_extensions==4.12.2
zipp==3.20.2

View File

@ -6,6 +6,3 @@ PyQt5-stubs
types-PyYAML
types-colorama
types-Pygments
# So stubs are available even on newer Python versions
importlib_resources

View File

@ -3,6 +3,6 @@
altgraph==0.17.4
importlib_metadata==8.5.0
packaging==24.1
pyinstaller==6.10.0
pyinstaller-hooks-contrib==2024.8
pyinstaller==6.11.0
pyinstaller-hooks-contrib==2024.9
zipp==3.20.2

View File

@ -1,10 +1,10 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
astroid==3.2.4
astroid==3.3.5
certifi==2024.8.30
cffi==1.17.1
charset-normalizer==3.3.2
cryptography==43.0.1
charset-normalizer==3.4.0
cryptography==43.0.3
dill==0.3.9
github3.py==4.0.1
idna==3.10
@ -14,12 +14,12 @@ pefile==2024.8.26
platformdirs==4.3.6
pycparser==2.22
PyJWT==2.9.0
pylint==3.2.7
pylint==3.3.1
python-dateutil==2.9.0.post0
./scripts/dev/pylint_checkers
requests==2.32.3
six==1.16.0
tomli==2.0.1
tomli==2.0.2
tomlkit==0.13.2
typing_extensions==4.12.2
uritemplate==4.1.1

View File

@ -7,7 +7,6 @@ pefile
# fix qute-pylint location
#@ replace: qute[_-]pylint.* ./scripts/dev/pylint_checkers
#@ markers: typed-ast python_version<"3.8"
# Already included via test requirements
#@ ignore: urllib3

View File

@ -1,9 +1,9 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
build==1.2.2
build==1.2.2.post1
certifi==2024.8.30
charset-normalizer==3.3.2
docutils==0.20.1
charset-normalizer==3.4.0
docutils==0.21.2
idna==3.10
importlib_metadata==8.5.0
packaging==24.1
@ -11,7 +11,7 @@ Pygments==2.18.0
pyproject_hooks==1.2.0
pyroma==4.2
requests==2.32.3
tomli==2.0.1
trove-classifiers==2024.9.12
tomli==2.0.2
trove-classifiers==2024.10.16
urllib3==2.2.3
zipp==3.20.2

View File

@ -12,12 +12,7 @@ PyYAML
#@ add: pyobjc-core ; sys_platform=="darwin"
#@ add: pyobjc-framework-Cocoa ; sys_platform=="darwin"
## stdlib backports
importlib_resources
## Optional dependencies
Pygments # For :view-source --pygments or on QtWebKit
colorama # Colored log output on Windows
adblock # Improved adblocking
#@ markers: importlib_resources python_version=="3.8.*"

View File

@ -1,26 +1,26 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
alabaster==0.7.13
alabaster==0.7.16
babel==2.16.0
certifi==2024.8.30
charset-normalizer==3.3.2
docutils==0.20.1
charset-normalizer==3.4.0
docutils==0.21.2
idna==3.10
imagesize==1.4.1
importlib_metadata==8.5.0
Jinja2==3.1.4
MarkupSafe==2.1.5
MarkupSafe==3.0.2
packaging==24.1
Pygments==2.18.0
pytz==2024.2
requests==2.32.3
snowballstemmer==2.2.0
Sphinx==7.1.2
sphinxcontrib-applehelp==1.0.4
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.1
Sphinx==7.4.7
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.0.2
urllib3==2.2.3
zipp==3.20.2

View File

@ -7,7 +7,11 @@ git+https://github.com/pallets/flask.git
git+https://github.com/pallets/werkzeug.git # transitive dep, but needed to work
git+https://github.com/HypothesisWorks/hypothesis.git#subdirectory=hypothesis-python
git+https://github.com/pytest-dev/pytest.git
git+https://github.com/pytest-dev/pytest-bdd.git
# https://github.com/qutebrowser/qutebrowser/issues/8342
# git+https://github.com/pytest-dev/pytest-bdd.git
pytest-bdd
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

View File

@ -6,19 +6,19 @@ backports.tarfile==1.2.0
beautifulsoup4==4.12.3
blinker==1.8.2
certifi==2024.8.30
charset-normalizer==3.3.2
charset-normalizer==3.4.0
cheroot==10.0.1
click==8.1.7
coverage==7.6.1
coverage==7.6.4
exceptiongroup==1.2.2
execnet==2.1.1
filelock==3.16.1
Flask==3.0.3
hunter==3.7.0
hypothesis==6.112.2
hypothesis==6.115.3
idna==3.10
importlib_metadata==8.5.0
importlib_resources==6.4.5 ; python_version=="3.8.*"
importlib_resources==6.4.5
inflect==7.3.1
iniconfig==2.0.0
itsdangerous==2.2.0
@ -29,13 +29,13 @@ jaraco.text==3.12.1
# Jinja2==3.1.4
Mako==1.3.5
manhole==1.8.1
# MarkupSafe==2.1.5
# MarkupSafe==3.0.2
more-itertools==10.5.0
packaging==24.1
parse==1.20.2
parse_type==0.6.3
parse_type==0.6.4
pillow==11.0.0
platformdirs==4.3.6
pillow==10.4.0
pluggy==1.5.0
py-cpuinfo==9.0.0
Pygments==2.18.0
@ -57,10 +57,10 @@ six==1.16.0
sortedcontainers==2.4.0
soupsieve==2.6
tldextract==5.1.2
tomli==2.0.1
tomli==2.0.2
typeguard==4.3.0
typing_extensions==4.12.2
urllib3==2.2.3
vulture==2.12
vulture==2.13
Werkzeug==3.0.4
zipp==3.20.2

View File

@ -39,7 +39,6 @@ tldextract
# Include them here even though we don't need them to make sure we at least
# get an up to date version.
importlib_resources
#@ markers: importlib_resources python_version=="3.8.*"
jaraco.context
platformdirs

View File

@ -3,15 +3,16 @@
cachetools==5.5.0
chardet==5.2.0
colorama==0.4.6
distlib==0.3.8
distlib==0.3.9
filelock==3.16.1
packaging==24.1
pip==24.2
platformdirs==4.3.6
pluggy==1.5.0
pyproject-api==1.8.0
setuptools==75.1.0
tomli==2.0.1
tox==4.20.0
virtualenv==20.26.6
setuptools==75.2.0
tomli==2.0.2
tox==4.23.0
typing_extensions==4.12.2
virtualenv==20.27.0
wheel==0.44.0

View File

@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
tomli==2.0.1
vulture==2.12
tomli==2.0.2
vulture==2.13

View File

@ -35,7 +35,8 @@ Possible values:
import inspect
from typing import Any, Callable, Iterable, Protocol, Optional, Dict, cast
from typing import Any, Protocol, Optional, cast
from collections.abc import Iterable, Callable
from qutebrowser.utils import qtutils
from qutebrowser.commands import command, cmdexc
@ -101,7 +102,7 @@ class _CmdHandlerType(Protocol):
Below, we cast the decorated function to _CmdHandlerType to make mypy aware of this.
"""
qute_args: Optional[Dict[str, 'command.ArgInfo']]
qute_args: Optional[dict[str, 'command.ArgInfo']]
def __call__(self, *args: Any, **kwargs: Any) -> Any:
...

View File

@ -7,7 +7,8 @@
"""Hooks for extensions."""
import importlib
from typing import Callable, Any
from typing import Any
from collections.abc import Callable
from qutebrowser.extensions import loader

View File

@ -29,7 +29,8 @@ import tempfile
import pathlib
import datetime
import argparse
from typing import Iterable, Optional, List, Tuple
from typing import Optional
from collections.abc import Iterable
from qutebrowser.qt import machinery
from qutebrowser.qt.widgets import QApplication, QWidget
@ -330,7 +331,7 @@ def _open_special_pages(args):
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='last-focused')
pages: List[Tuple[str, bool, str]] = [
pages: list[tuple[str, bool, str]] = [
# state, condition, URL
('quickstart-done',
True,

View File

@ -9,8 +9,8 @@ import pathlib
import itertools
import functools
import dataclasses
from typing import (cast, TYPE_CHECKING, Any, Callable, Iterable, List, Optional,
Sequence, Set, Type, Union, Tuple)
from typing import (cast, TYPE_CHECKING, Any, Optional, Union)
from collections.abc import Iterable, Sequence, Callable
from qutebrowser.qt import machinery
from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt,
@ -60,7 +60,7 @@ def create(win_id: int,
mode_manager = modeman.instance(win_id)
if objects.backend == usertypes.Backend.QtWebEngine:
from qutebrowser.browser.webengine import webenginetab
tab_class: Type[AbstractTab] = webenginetab.WebEngineTab
tab_class: type[AbstractTab] = webenginetab.WebEngineTab
elif objects.backend == usertypes.Backend.QtWebKit:
from qutebrowser.browser.webkit import webkittab
tab_class = webkittab.WebKitTab
@ -142,7 +142,7 @@ class AbstractAction:
"""Attribute ``action`` of AbstractTab for Qt WebActions."""
action_base: Type[Union['QWebPage.WebAction', 'QWebEnginePage.WebAction']]
action_base: type[Union['QWebPage.WebAction', 'QWebEnginePage.WebAction']]
def __init__(self, tab: 'AbstractTab') -> None:
self._widget = cast(_WidgetType, None)
@ -639,7 +639,7 @@ class AbstractScroller(QObject):
def pos_px(self) -> QPoint:
raise NotImplementedError
def pos_perc(self) -> Tuple[int, int]:
def pos_perc(self) -> tuple[int, int]:
raise NotImplementedError
def to_perc(self, x: float = None, y: float = None) -> None:
@ -765,10 +765,10 @@ class AbstractHistory:
def _go_to_item(self, item: Any) -> None:
raise NotImplementedError
def back_items(self) -> List[Any]:
def back_items(self) -> list[Any]:
raise NotImplementedError
def forward_items(self) -> List[Any]:
def forward_items(self) -> list[Any]:
raise NotImplementedError
@ -1018,7 +1018,7 @@ class AbstractTab(QWidget):
# Note that we remember hosts here, without scheme/port:
# QtWebEngine/Chromium also only remembers hostnames, and certificates are
# for a given hostname anyways.
_insecure_hosts: Set[str] = set()
_insecure_hosts: set[str] = set()
# Sub-APIs initialized by subclasses
history: AbstractHistory

View File

@ -2,12 +2,15 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
# pylint: disable=too-many-positional-arguments
"""Command dispatcher for TabbedBrowser."""
import os.path
import shlex
import functools
from typing import cast, Callable, Dict, Union, Optional
from typing import cast, Union, Optional
from collections.abc import Callable
from qutebrowser.qt.widgets import QApplication, QTabBar
from qutebrowser.qt.core import Qt, QUrl, QEvent, QUrlQuery
@ -636,7 +639,7 @@ class CommandDispatcher:
widget = self._current_widget()
url = self._current_url()
handlers: Dict[str, Callable[..., QUrl]] = {
handlers: dict[str, Callable[..., QUrl]] = {
'prev': functools.partial(navigate.prevnext, prev=True),
'next': functools.partial(navigate.prevnext, prev=False),
'up': navigate.path_up,
@ -1136,8 +1139,7 @@ class CommandDispatcher:
else:
cmd = os.path.expanduser(cmd)
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
output_messages=output_messages,
parent=self._tabbed_browser)
output_messages=output_messages)
if detach:
ok = proc.start_detached(cmd, args)
if not ok:

View File

@ -13,7 +13,8 @@ import functools
import pathlib
import tempfile
import enum
from typing import Any, Dict, IO, List, MutableSequence, Optional, Union
from typing import Any, IO, Optional, Union
from collections.abc import MutableSequence
from qutebrowser.qt.core import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
QTimer, QAbstractListModel, QUrl)
@ -447,7 +448,7 @@ class AbstractDownloadItem(QObject):
UnsupportedAttribute, IO[bytes], None
] = UnsupportedAttribute()
self.raw_headers: Union[
UnsupportedAttribute, Dict[bytes, bytes]
UnsupportedAttribute, dict[bytes, bytes]
] = UnsupportedAttribute()
self._filename: Optional[str] = None
@ -899,7 +900,7 @@ class AbstractDownloadManager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self.downloads: List[AbstractDownloadItem] = []
self.downloads: list[AbstractDownloadItem] = []
self._update_timer = usertypes.Timer(self, 'download-update')
self._update_timer.timeout.connect(self._update_gui)
self._update_timer.setInterval(_REFRESH_INTERVAL)

View File

@ -5,7 +5,8 @@
"""The ListView to display downloads in."""
import functools
from typing import Callable, MutableSequence, Tuple, Union
from typing import Union
from collections.abc import MutableSequence, Callable
from qutebrowser.qt.core import pyqtSlot, QSize, Qt
from qutebrowser.qt.widgets import QListView, QSizePolicy, QMenu, QStyleFactory
@ -17,8 +18,8 @@ from qutebrowser.utils import qtutils, utils
_ActionListType = MutableSequence[
Union[
Tuple[None, None], # separator
Tuple[str, Callable[[], None]],
tuple[None, None], # separator
tuple[str, Callable[[], None]],
]
]

View File

@ -12,7 +12,8 @@ import functools
import glob
import textwrap
import dataclasses
from typing import cast, List, Sequence, Tuple, Optional
from typing import cast, Optional
from collections.abc import Sequence
from qutebrowser.qt.core import pyqtSignal, QObject, QUrl
@ -207,9 +208,9 @@ class MatchingScripts:
"""All userscripts registered to run on a particular url."""
url: QUrl
start: List[GreasemonkeyScript] = dataclasses.field(default_factory=list)
end: List[GreasemonkeyScript] = dataclasses.field(default_factory=list)
idle: List[GreasemonkeyScript] = dataclasses.field(default_factory=list)
start: list[GreasemonkeyScript] = dataclasses.field(default_factory=list)
end: list[GreasemonkeyScript] = dataclasses.field(default_factory=list)
idle: list[GreasemonkeyScript] = dataclasses.field(default_factory=list)
@dataclasses.dataclass
@ -217,8 +218,8 @@ class LoadResults:
"""The results of loading all Greasemonkey scripts."""
successful: List[GreasemonkeyScript] = dataclasses.field(default_factory=list)
errors: List[Tuple[str, str]] = dataclasses.field(default_factory=list)
successful: list[GreasemonkeyScript] = dataclasses.field(default_factory=list)
errors: list[tuple[str, str]] = dataclasses.field(default_factory=list)
def successful_str(self) -> str:
"""Get a string with all successfully loaded scripts.
@ -294,10 +295,10 @@ class GreasemonkeyManager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._run_start: List[GreasemonkeyScript] = []
self._run_end: List[GreasemonkeyScript] = []
self._run_idle: List[GreasemonkeyScript] = []
self._in_progress_dls: List[downloads.AbstractDownloadItem] = []
self._run_start: list[GreasemonkeyScript] = []
self._run_end: list[GreasemonkeyScript] = []
self._run_idle: list[GreasemonkeyScript] = []
self._in_progress_dls: list[downloads.AbstractDownloadItem] = []
def load_scripts(self, *, force: bool = False) -> LoadResults:
"""Re-read Greasemonkey scripts from disk.

View File

@ -12,8 +12,15 @@ import html
import enum
import dataclasses
from string import ascii_lowercase
from typing import (TYPE_CHECKING, Callable, Dict, Iterable, Iterator, List, Mapping,
MutableSequence, Optional, Sequence, Set)
from typing import (TYPE_CHECKING, Optional)
from collections.abc import (
Iterable,
Iterator,
Mapping,
MutableSequence,
Sequence,
Callable,
)
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, Qt, QUrl
from qutebrowser.qt.widgets import QLabel
@ -175,11 +182,11 @@ class HintContext:
add_history: bool
first: bool
baseurl: QUrl
args: List[str]
args: list[str]
group: str
all_labels: List[HintLabel] = dataclasses.field(default_factory=list)
labels: Dict[str, HintLabel] = dataclasses.field(default_factory=dict)
all_labels: list[HintLabel] = dataclasses.field(default_factory=list)
labels: dict[str, HintLabel] = dataclasses.field(default_factory=dict)
to_follow: Optional[str] = None
first_run: bool = True
filterstr: Optional[str] = None
@ -1033,7 +1040,7 @@ class WordHinter:
def __init__(self) -> None:
# will be initialized on first use.
self.words: Set[str] = set()
self.words: set[str] = set()
self.dictionary = None
def ensure_initialized(self) -> None:
@ -1143,7 +1150,7 @@ class WordHinter:
"""
self.ensure_initialized()
hints = []
used_hints: Set[str] = set()
used_hints: set[str] = set()
words = iter(self.words)
for elem in elems:
hint = self.new_hint_for(elem, used_hints, words)

View File

@ -8,7 +8,8 @@ import os
import time
import contextlib
import pathlib
from typing import cast, Mapping, MutableSequence, Optional
from typing import cast, Optional
from collections.abc import Mapping, MutableSequence
from qutebrowser.qt import machinery
from qutebrowser.qt.core import pyqtSlot, QUrl, QObject, pyqtSignal

View File

@ -6,7 +6,7 @@
import re
import posixpath
from typing import Optional, Set
from typing import Optional
from qutebrowser.qt.core import QUrl
@ -79,7 +79,7 @@ def incdec(url, count, inc_or_dec):
inc_or_dec: Either 'increment' or 'decrement'.
"""
urlutils.ensure_valid(url)
segments: Optional[Set[str]] = (
segments: Optional[set[str]] = (
set(config.val.url.incdec_segments)
)

View File

@ -242,7 +242,7 @@ class PACFetcher(QObject):
pac_prefix = "pac+"
assert url.scheme().startswith(pac_prefix)
url.setScheme(url.scheme()[len(pac_prefix):])
url.setScheme(url.scheme().removeprefix(pac_prefix))
self._pac_url = url
with qtlog.disable_qt_msghandler():

View File

@ -4,7 +4,7 @@
"""Handling of proxies."""
from typing import Optional, List
from typing import Optional
from qutebrowser.qt.core import QUrl, pyqtSlot
from qutebrowser.qt.network import QNetworkProxy, QNetworkProxyFactory, QNetworkProxyQuery
@ -71,7 +71,7 @@ class ProxyFactory(QNetworkProxyFactory):
capabilities &= ~lookup_cap
proxy.setCapabilities(capabilities)
def queryProxy(self, query: QNetworkProxyQuery = QNetworkProxyQuery()) -> List[QNetworkProxy]:
def queryProxy(self, query: QNetworkProxyQuery = QNetworkProxyQuery()) -> list[QNetworkProxy]:
"""Get the QNetworkProxies for a query.
Args:

View File

@ -9,7 +9,7 @@ import os.path
import shutil
import functools
import dataclasses
from typing import Dict, IO, Optional
from typing import IO, Optional
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, QTimer, QUrl
from qutebrowser.qt.widgets import QApplication
@ -73,7 +73,7 @@ class DownloadItem(downloads.AbstractDownloadItem):
"""
super().__init__(manager=manager, parent=manager)
self.fileobj: Optional[IO[bytes]] = None
self.raw_headers: Dict[bytes, bytes] = {}
self.raw_headers: dict[bytes, bytes] = {}
self._autoclose = True
self._retry_info = None

View File

@ -18,7 +18,8 @@ import textwrap
import urllib
import collections
import secrets
from typing import TypeVar, Callable, Dict, List, Optional, Union, Sequence, Tuple
from typing import TypeVar, Optional, Union
from collections.abc import Sequence, Callable
from qutebrowser.qt.core import QUrlQuery, QUrl
@ -35,7 +36,7 @@ pyeval_output = ":pyeval was never called"
csrf_token: Optional[str] = None
_HANDLERS: Dict[str, "_HandlerCallable"] = {}
_HANDLERS: dict[str, "_HandlerCallable"] = {}
class Error(Exception):
@ -77,7 +78,7 @@ class Redirect(Exception):
# Return value: (mimetype, data) (encoded as utf-8 if a str is returned)
_HandlerRet = Tuple[str, Union[str, bytes]]
_HandlerRet = tuple[str, Union[str, bytes]]
_HandlerCallable = Callable[[QUrl], _HandlerRet]
_Handler = TypeVar('_Handler', bound=_HandlerCallable)
@ -105,7 +106,7 @@ class add_handler: # noqa: N801,N806 pylint: disable=invalid-name
return self._function(url)
def data_for_url(url: QUrl) -> Tuple[str, bytes]:
def data_for_url(url: QUrl) -> tuple[str, bytes]:
"""Get the data to show for the given URL.
Args:
@ -180,7 +181,7 @@ def qute_bookmarks(_url: QUrl) -> _HandlerRet:
@add_handler('tabs')
def qute_tabs(_url: QUrl) -> _HandlerRet:
"""Handler for qute://tabs. Display information about all open tabs."""
tabs: Dict[str, List[Tuple[str, str]]] = collections.defaultdict(list)
tabs: dict[str, list[tuple[str, str]]] = collections.defaultdict(list)
for win_id, window in objreg.window_registry.items():
if sip.isdeleted(window):
continue
@ -201,7 +202,7 @@ def qute_tabs(_url: QUrl) -> _HandlerRet:
def history_data(
start_time: float,
offset: int = None
) -> Sequence[Dict[str, Union[str, int]]]:
) -> Sequence[dict[str, Union[str, int]]]:
"""Return history data.
Arguments:

View File

@ -10,7 +10,8 @@ import html
import enum
import netrc
import tempfile
from typing import Callable, Mapping, List, Optional, Iterable, Iterator
from typing import Optional
from collections.abc import Mapping, Iterable, Iterator, Callable
from qutebrowser.qt.core import QUrl, pyqtBoundSignal
@ -457,7 +458,7 @@ class FileSelectionMode(enum.Enum):
folder = enum.auto()
def choose_file(qb_mode: FileSelectionMode) -> List[str]:
def choose_file(qb_mode: FileSelectionMode) -> list[str]:
"""Select file(s)/folder for up-/downloading, using an external command.
Args:
@ -497,10 +498,10 @@ def choose_file(qb_mode: FileSelectionMode) -> List[str]:
def _execute_fileselect_command(
command: List[str],
command: list[str],
qb_mode: FileSelectionMode,
tmpfilename: Optional[str] = None
) -> List[str]:
) -> list[str]:
"""Execute external command to choose file.
Args:
@ -534,7 +535,7 @@ def _execute_fileselect_command(
def _validated_selected_files(
qb_mode: FileSelectionMode,
selected_files: List[str],
selected_files: list[str],
) -> Iterator[str]:
"""Validates selected files if they are.

View File

@ -15,7 +15,7 @@ import os.path
import html
import functools
import collections
from typing import MutableMapping
from collections.abc import MutableMapping
from qutebrowser.qt.core import pyqtSignal, QUrl, QObject

View File

@ -4,7 +4,8 @@
"""Generic web element related code."""
from typing import Iterator, Optional, Set, TYPE_CHECKING, Union, Dict
from typing import Optional, TYPE_CHECKING, Union
from collections.abc import Iterator
import collections.abc
from qutebrowser.qt import machinery
@ -93,7 +94,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a
"""Get the geometry for this element."""
raise NotImplementedError
def classes(self) -> Set[str]:
def classes(self) -> set[str]:
"""Get a set of classes assigned to this element."""
raise NotImplementedError
@ -336,7 +337,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a
log.webelem.debug("Sending fake click to {!r} at position {} with "
"target {}".format(self, pos, click_target))
target_modifiers: Dict[usertypes.ClickTarget, KeyboardModifierType] = {
target_modifiers: dict[usertypes.ClickTarget, KeyboardModifierType] = {
usertypes.ClickTarget.normal: Qt.KeyboardModifier.NoModifier,
usertypes.ClickTarget.window: Qt.KeyboardModifier.AltModifier | Qt.KeyboardModifier.ShiftModifier,
usertypes.ClickTarget.tab: Qt.KeyboardModifier.ControlModifier,

View File

@ -125,8 +125,8 @@ import copy
import enum
import dataclasses
import collections
from typing import (Any, Iterator, Mapping, MutableMapping, Optional, Set, Tuple, Union,
Sequence, List)
from typing import (Any, Optional, Union)
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
from qutebrowser.config import config
from qutebrowser.utils import usertypes, utils, log, version
@ -212,7 +212,7 @@ class _Setting:
return str(value)
return str(self.mapping[value])
def chromium_tuple(self, value: Any) -> Optional[Tuple[str, str]]:
def chromium_tuple(self, value: Any) -> Optional[tuple[str, str]]:
"""Get the Chromium key and value, or None if no value should be set."""
if self.mapping is not None and self.mapping[value] is None:
return None
@ -242,7 +242,7 @@ class _Definition:
def __init__(
self,
*args: _Setting,
mandatory: Set[str],
mandatory: set[str],
prefix: str,
switch_names: Mapping[Optional[str], str] = None,
) -> None:
@ -255,7 +255,7 @@ class _Definition:
else:
self._switch_names = {None: _BLINK_SETTINGS}
def prefixed_settings(self) -> Iterator[Tuple[str, _Setting]]:
def prefixed_settings(self) -> Iterator[tuple[str, _Setting]]:
"""Get all "prepared" settings.
Yields tuples which contain the Chromium setting key (e.g. 'blink-settings' or
@ -399,7 +399,7 @@ def settings(
*,
versions: version.WebEngineVersions,
special_flags: Sequence[str],
) -> Mapping[str, Sequence[Tuple[str, str]]]:
) -> Mapping[str, Sequence[tuple[str, str]]]:
"""Get necessary blink settings to configure dark mode for QtWebEngine.
Args:
@ -413,12 +413,12 @@ def settings(
variant = _variant(versions)
log.init.debug(f"Darkmode variant: {variant.name}")
result: Mapping[str, List[Tuple[str, str]]] = collections.defaultdict(list)
result: Mapping[str, list[tuple[str, str]]] = collections.defaultdict(list)
blink_settings_flag = f'--{_BLINK_SETTINGS}='
for flag in special_flags:
if flag.startswith(blink_settings_flag):
for pair in flag[len(blink_settings_flag):].split(','):
for pair in flag.removeprefix(blink_settings_flag).split(','):
key, val = pair.split('=', maxsplit=1)
result[_BLINK_SETTINGS].append((key, val))

View File

@ -33,7 +33,8 @@ import dataclasses
import itertools
import functools
import subprocess
from typing import Any, List, Dict, Optional, Iterator, Type, TYPE_CHECKING
from typing import Any, Optional, TYPE_CHECKING
from collections.abc import Iterator
from qutebrowser.qt import machinery
from qutebrowser.qt.core import (Qt, QObject, QVariant, QMetaType, QByteArray, pyqtSlot,
@ -195,7 +196,7 @@ class NotificationBridgePresenter(QObject):
def __init__(self, parent: QObject = None) -> None:
super().__init__(parent)
self._active_notifications: Dict[int, 'QWebEngineNotification'] = {}
self._active_notifications: dict[int, 'QWebEngineNotification'] = {}
self._adapter: Optional[AbstractNotificationAdapter] = None
config.instance.changed.connect(self._init_adapter)
@ -232,8 +233,8 @@ class NotificationBridgePresenter(QObject):
def _get_adapter_candidates(
self,
setting: str,
) -> List[Type[AbstractNotificationAdapter]]:
candidates: Dict[str, List[Type[AbstractNotificationAdapter]]] = {
) -> list[type[AbstractNotificationAdapter]]:
candidates: dict[str, list[type[AbstractNotificationAdapter]]] = {
"libnotify": [
DBusNotificationAdapter,
SystrayNotificationAdapter,
@ -665,7 +666,7 @@ class _ServerCapabilities:
kde_origin_name: bool
@classmethod
def from_list(cls, capabilities: List[str]) -> "_ServerCapabilities":
def from_list(cls, capabilities: list[str]) -> "_ServerCapabilities":
return cls(
actions='actions' in capabilities,
body_markup='body-markup' in capabilities,
@ -951,10 +952,10 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
qtutils.extract_enum_val(QMetaType.Type.QStringList),
)
def _get_hints_arg(self, *, origin_url: QUrl, icon: QImage) -> Dict[str, Any]:
def _get_hints_arg(self, *, origin_url: QUrl, icon: QImage) -> dict[str, Any]:
"""Get the hints argument for present()."""
origin_url_str = origin_url.toDisplayString()
hints: Dict[str, Any] = {
hints: dict[str, Any] = {
# Include the origin in case the user wants to do different things
# with different origin's notifications.
"x-qutebrowser-origin": origin_url_str,
@ -984,7 +985,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
title: str,
body: str,
actions: QDBusArgument,
hints: Dict[str, Any],
hints: dict[str, Any],
timeout: int,
) -> Any:
"""Wrapper around DBus call to use keyword args."""

View File

@ -5,7 +5,8 @@
"""QtWebEngine specific part of the web element API."""
from typing import (
TYPE_CHECKING, Any, Callable, Dict, Iterator, Optional, Set, Tuple, Union)
TYPE_CHECKING, Any, Optional, Union)
from collections.abc import Iterator, Callable
from qutebrowser.qt.core import QRect, QEventLoop
from qutebrowser.qt.widgets import QApplication
@ -24,11 +25,11 @@ class WebEngineElement(webelem.AbstractWebElement):
_tab: "webenginetab.WebEngineTab"
def __init__(self, js_dict: Dict[str, Any],
def __init__(self, js_dict: dict[str, Any],
tab: 'webenginetab.WebEngineTab') -> None:
super().__init__(tab)
# Do some sanity checks on the data we get from JS
js_dict_types: Dict[str, Union[type, Tuple[type, ...]]] = {
js_dict_types: dict[str, Union[type, tuple[type, ...]]] = {
'id': int,
'text': str,
'value': (str, int, float),
@ -105,7 +106,7 @@ class WebEngineElement(webelem.AbstractWebElement):
log.stub()
return QRect()
def classes(self) -> Set[str]:
def classes(self) -> set[str]:
"""Get a list of classes assigned to this element."""
return set(self._js_dict['class_name'].split())

View File

@ -12,7 +12,7 @@ Module attributes:
import os
import operator
import pathlib
from typing import cast, Any, List, Optional, Tuple, Union, TYPE_CHECKING
from typing import cast, Any, Optional, Union, TYPE_CHECKING
from qutebrowser.qt import machinery
from qutebrowser.qt.gui import QFont
@ -543,7 +543,7 @@ def _init_default_settings():
- Make sure the devtools always get images/JS permissions.
- On Qt 6, make sure files in the data path can load external resources.
"""
devtools_settings: List[Tuple[str, Any]] = [
devtools_settings: list[tuple[str, Any]] = [
('content.javascript.enabled', True),
('content.images', True),
('content.cookies.accept', 'all'),
@ -556,7 +556,7 @@ def _init_default_settings():
hide_userconfig=True)
if machinery.IS_QT6:
userscripts_settings: List[Tuple[str, Any]] = [
userscripts_settings: list[tuple[str, Any]] = [
("content.local_content_can_access_remote_urls", True),
("content.local_content_can_access_file_urls", False),
]

View File

@ -5,7 +5,8 @@
"""The main browser widget for QtWebEngine."""
import mimetypes
from typing import List, Iterable, Optional
from typing import Optional
from collections.abc import Iterable
from qutebrowser.qt import machinery
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QUrl
@ -316,7 +317,7 @@ class WebEnginePage(QWebEnginePage):
mode: QWebEnginePage.FileSelectionMode,
old_files: Iterable[Optional[str]],
accepted_mimetypes: Iterable[Optional[str]],
) -> List[str]:
) -> list[str]:
"""Override chooseFiles to (optionally) invoke custom file uploader."""
accepted_mimetypes_filtered = [m for m in accepted_mimetypes if m is not None]
old_files_filtered = [f for f in old_files if f is not None]

View File

@ -4,7 +4,8 @@
"""A wrapper over a list of QSslErrors."""
from typing import Sequence, Optional
from typing import Optional
from collections.abc import Sequence
from qutebrowser.qt.network import QSslError, QNetworkReply

View File

@ -4,7 +4,7 @@
"""Handling of HTTP cookies."""
from typing import Sequence
from collections.abc import Sequence
from qutebrowser.qt.network import QNetworkCookie, QNetworkCookieJar
from qutebrowser.qt.core import pyqtSignal, QDateTime

View File

@ -8,7 +8,6 @@ import email.headerregistry
import email.errors
import dataclasses
import os.path
from typing import Type
from qutebrowser.qt.network import QNetworkRequest
@ -25,7 +24,7 @@ class DefectWrapper:
"""Wrapper around a email.error for comparison."""
error_class: Type[email.errors.MessageDefect]
error_class: type[email.errors.MessageDefect]
line: str
def __eq__(self, other):

View File

@ -19,7 +19,7 @@ import email.mime.multipart
import email.message
import quopri
import dataclasses
from typing import MutableMapping, Set, Tuple, Callable
from collections.abc import MutableMapping, Callable
from qutebrowser.qt.core import QUrl
@ -177,7 +177,7 @@ class MHTMLWriter:
return msg
_PendingDownloadType = Set[Tuple[QUrl, downloads.AbstractDownloadItem]]
_PendingDownloadType = set[tuple[QUrl, downloads.AbstractDownloadItem]]
class _Downloader:

View File

@ -7,7 +7,8 @@
import collections
import html
import dataclasses
from typing import TYPE_CHECKING, Dict, MutableMapping, Optional, Set
from typing import TYPE_CHECKING, Optional
from collections.abc import MutableMapping
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, QUrl, QByteArray
from qutebrowser.qt.network import (QNetworkAccessManager, QNetworkReply, QSslConfiguration,
@ -29,7 +30,7 @@ if TYPE_CHECKING:
HOSTBLOCK_ERROR_STRING = '%HOSTBLOCK%'
_proxy_auth_cache: Dict['ProxyId', 'prompt.AuthInfo'] = {}
_proxy_auth_cache: dict['ProxyId', 'prompt.AuthInfo'] = {}
@dataclasses.dataclass(frozen=True)
@ -110,7 +111,7 @@ def init():
_SavedErrorsType = MutableMapping[
urlutils.HostTupleType,
Set[certificateerror.CertificateErrorWrapper],
set[certificateerror.CertificateErrorWrapper],
]

View File

@ -4,7 +4,8 @@
"""Utilities related to QWebHistory."""
from typing import Any, List, Mapping
from typing import Any
from collections.abc import Mapping
from qutebrowser.qt.core import QByteArray, QDataStream, QIODevice, QUrl
@ -66,7 +67,7 @@ def serialize(items):
"""
data = QByteArray()
stream = QDataStream(data, QIODevice.OpenModeFlag.ReadWrite)
user_data: List[Mapping[str, Any]] = []
user_data: list[Mapping[str, Any]] = []
current_idx = None

View File

@ -4,7 +4,8 @@
"""QtWebKit specific part of the web element API."""
from typing import cast, TYPE_CHECKING, Iterator, List, Optional, Set
from typing import cast, TYPE_CHECKING, Optional
from collections.abc import Iterator
from qutebrowser.qt.core import QRect, Qt
# pylint: disable=no-name-in-module
@ -90,7 +91,7 @@ class WebKitElement(webelem.AbstractWebElement):
self._check_vanished()
return self._elem.geometry()
def classes(self) -> Set[str]:
def classes(self) -> set[str]:
self._check_vanished()
return set(self._elem.classes())
@ -364,7 +365,7 @@ class WebKitElement(webelem.AbstractWebElement):
super()._click_fake_event(click_target)
def get_child_frames(startframe: QWebFrame) -> List[QWebFrame]:
def get_child_frames(startframe: QWebFrame) -> list[QWebFrame]:
"""Get all children recursively of a given QWebFrame.
Loosely based on https://blog.nextgenetics.net/?e=64
@ -378,7 +379,7 @@ def get_child_frames(startframe: QWebFrame) -> List[QWebFrame]:
results = []
frames = [startframe]
while frames:
new_frames: List[QWebFrame] = []
new_frames: list[QWebFrame] = []
for frame in frames:
results.append(frame)
new_frames += frame.childFrames()

View File

@ -7,7 +7,8 @@
import re
import functools
import xml.etree.ElementTree
from typing import cast, Iterable, Optional
from typing import cast, Optional
from collections.abc import Iterable
from qutebrowser.qt.core import pyqtSlot, Qt, QUrl, QPoint, QTimer, QSizeF, QSize
from qutebrowser.qt.gui import QIcon

View File

@ -7,7 +7,6 @@
Defined here to avoid circular dependency hell.
"""
from typing import List
import difflib
@ -21,7 +20,7 @@ class NoSuchCommandError(Error):
"""Raised when a command isn't found."""
@classmethod
def for_cmd(cls, cmd: str, all_commands: List[str] = None) -> "NoSuchCommandError":
def for_cmd(cls, cmd: str, all_commands: list[str] = None) -> "NoSuchCommandError":
"""Raise an exception for the given command."""
suffix = ''
if all_commands:

View File

@ -9,8 +9,8 @@ import collections
import traceback
import typing
import dataclasses
from typing import (Any, MutableMapping, MutableSequence, Tuple, Union, List, Optional,
Callable)
from typing import (Any, Union, Optional)
from collections.abc import MutableMapping, MutableSequence, Callable
from qutebrowser.api import cmdutils
from qutebrowser.commands import cmdexc, argparser
@ -30,7 +30,7 @@ class ArgInfo:
metavar: Optional[str] = None
flag: Optional[str] = None
completion: Optional[Callable[..., completionmodel.CompletionModel]] = None
choices: Optional[List[str]] = None
choices: Optional[list[str]] = None
class Command:
@ -105,10 +105,10 @@ class Command:
self.parser.add_argument('-h', '--help', action=argparser.HelpAction,
default=argparser.SUPPRESS, nargs=0,
help=argparser.SUPPRESS)
self.opt_args: MutableMapping[str, Tuple[str, str]] = collections.OrderedDict()
self.opt_args: MutableMapping[str, tuple[str, str]] = collections.OrderedDict()
self.namespace = None
self._count = None
self.pos_args: MutableSequence[Tuple[str, str]] = []
self.pos_args: MutableSequence[tuple[str, str]] = []
self.flags_with_args: MutableSequence[str] = []
self._has_vararg = False

View File

@ -5,7 +5,7 @@
"""Module for parsing commands entered into the browser."""
import dataclasses
from typing import List, Iterator
from collections.abc import Iterator
from qutebrowser.commands import cmdexc, command
from qutebrowser.misc import split, objects
@ -18,8 +18,8 @@ class ParseResult:
"""The result of parsing a commandline."""
cmd: command.Command
args: List[str]
cmdline: List[str]
args: list[str]
cmdline: list[str]
class CommandParser:
@ -107,7 +107,7 @@ class CommandParser:
for sub in sub_texts:
yield self.parse(sub, **kwargs)
def parse_all(self, text: str, **kwargs: bool) -> List[ParseResult]:
def parse_all(self, text: str, **kwargs: bool) -> list[ParseResult]:
"""Wrapper over _parse_all_gen."""
return list(self._parse_all_gen(text, **kwargs))
@ -161,7 +161,7 @@ class CommandParser:
cmdstr = matches[0]
return cmdstr
def _split_args(self, cmd: command.Command, argstr: str, keep: bool) -> List[str]:
def _split_args(self, cmd: command.Command, argstr: str, keep: bool) -> list[str]:
"""Split the arguments from an arg string.
Args:

View File

@ -7,7 +7,8 @@
import traceback
import re
import contextlib
from typing import TYPE_CHECKING, Callable, Dict, Tuple, Iterator, Mapping, MutableMapping
from typing import TYPE_CHECKING
from collections.abc import Iterator, Mapping, MutableMapping, Callable
from qutebrowser.qt.core import pyqtSlot, QUrl, QObject
@ -21,7 +22,7 @@ if TYPE_CHECKING:
_ReplacementFunction = Callable[['tabbedbrowser.TabbedBrowser'], str]
last_command: Dict[usertypes.KeyMode, Tuple[str, int]] = {}
last_command: dict[usertypes.KeyMode, tuple[str, int]] = {}
def _url(tabbed_browser):
@ -38,7 +39,7 @@ def _url(tabbed_browser):
def _init_variable_replacements() -> Mapping[str, _ReplacementFunction]:
"""Return a dict from variable replacements to fns processing them."""
replacements: Dict[str, _ReplacementFunction] = {
replacements: dict[str, _ReplacementFunction] = {
'url': lambda tb: _url(tb).toString(
QUrl.ComponentFormattingOption.FullyEncoded | QUrl.UrlFormattingOption.RemovePassword),
'url:pretty': lambda tb: _url(tb).toString(

View File

@ -7,7 +7,8 @@
import os
import os.path
import tempfile
from typing import cast, Any, MutableMapping, Tuple
from typing import cast, Any
from collections.abc import MutableMapping
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, QSocketNotifier
@ -106,7 +107,7 @@ class _BaseUserscriptRunner(QObject):
self._env: MutableMapping[str, str] = {}
self._text_stored = False
self._html_stored = False
self._args: Tuple[Any, ...] = ()
self._args: tuple[Any, ...] = ()
self._kwargs = {}
def store_text(self, text):
@ -155,7 +156,7 @@ class _BaseUserscriptRunner(QObject):
self.proc = guiprocess.GUIProcess(
'userscript', additional_env=self._env,
output_messages=output_messages, verbose=verbose, parent=self)
output_messages=output_messages, verbose=verbose)
self.proc.finished.connect(self.on_proc_finished)
self.proc.error.connect(self.on_proc_error)
self.proc.start(cmd, args)

View File

@ -127,7 +127,7 @@ class Completer(QObject):
Return:
([parts_before_cursor], 'part_under_cursor', [parts_after_cursor])
"""
text = self._cmd.text()[len(self._cmd.prefix()):]
text = self._cmd.text().removeprefix(self._cmd.prefix())
if not text or not text.strip():
# Only ":", empty part under the cursor with nothing before/after
return [], '', []

View File

@ -4,7 +4,8 @@
"""Models for the command completion."""
from typing import Sequence, Optional
from typing import Optional
from collections.abc import Sequence
from qutebrowser.completion.models.util import DeleteFuncType
from qutebrowser.qt.core import QAbstractItemModel

View File

@ -4,7 +4,8 @@
"""A model that proxies access to one or more completion categories."""
from typing import MutableSequence, overload, Optional, Any, cast
from typing import overload, Optional, Any, cast
from collections.abc import MutableSequence
from qutebrowser.qt import machinery
from qutebrowser.qt.core import Qt, QModelIndex, QAbstractItemModel, QObject

View File

@ -14,7 +14,8 @@ is harder to achieve via pathlib.
import glob
import os
import os.path
from typing import List, Optional, Iterable
from typing import Optional
from collections.abc import Iterable
from qutebrowser.qt.core import QAbstractListModel, QModelIndex, QObject, Qt, QUrl
@ -28,7 +29,7 @@ class FilePathCategory(QAbstractListModel, BaseCategory):
def __init__(self, name: str, parent: QObject = None) -> None:
super().__init__(parent)
self._paths: List[str] = []
self._paths: list[str] = []
self.name = name
self.columns_to_filter = [0]

View File

@ -5,7 +5,7 @@
"""Completion category that uses a list of tuples as a data source."""
import re
from typing import Iterable, Tuple
from collections.abc import Iterable
from qutebrowser.qt.core import QSortFilterProxyModel, QRegularExpression
from qutebrowser.qt.gui import QStandardItem, QStandardItemModel
@ -21,7 +21,7 @@ class ListCategory(QSortFilterProxyModel, BaseCategory):
def __init__(self,
name: str,
items: Iterable[Tuple[str, ...]],
items: Iterable[tuple[str, ...]],
sort: bool = True,
delete_func: util.DeleteFuncType = None,
parent: QWidget = None):

View File

@ -6,7 +6,7 @@
import datetime
import itertools
from typing import List, Sequence, Tuple
from collections.abc import Sequence
from qutebrowser.config import config, configdata
from qutebrowser.utils import objreg, log, utils
@ -113,7 +113,7 @@ def _tabs(*, win_id_filter=lambda _win_id: True, add_win_id=True, cur_win_id=Non
tabs_are_windows = config.val.tabs.tabs_are_windows
# list storing all single-tabbed windows when tabs_are_windows
windows: List[Tuple[str, str, str, str]] = []
windows: list[tuple[str, str, str, str]] = []
for win_id in objreg.window_registry:
if not win_id_filter(win_id):
@ -123,7 +123,7 @@ def _tabs(*, win_id_filter=lambda _win_id: True, add_win_id=True, cur_win_id=Non
window=win_id)
if tabbed_browser.is_shutting_down:
continue
tab_entries: List[Tuple[str, str, str, str]] = []
tab_entries: list[tuple[str, str, str, str]] = []
for idx in range(tabbed_browser.widget.count()):
tab = tabbed_browser.widget.widget(idx)
tab_str = ("{}/{}".format(win_id, idx + 1) if add_win_id

View File

@ -4,7 +4,7 @@
"""Function to return the url completion model for the `open` command."""
from typing import Dict, Sequence
from collections.abc import Sequence
from qutebrowser.completion.models import (completionmodel, filepathcategory,
listcategory, histcategory,
@ -58,7 +58,7 @@ def url(*, info):
in sorted(config.val.url.searchengines.items())
if k != 'DEFAULT']
categories = config.val.completion.open_categories
models: Dict[str, BaseCategory] = {}
models: dict[str, BaseCategory] = {}
if searchengines and 'searchengines' in categories:
models['searchengines'] = listcategory.ListCategory(

View File

@ -4,7 +4,7 @@
"""Utility functions for completion models."""
from typing import Callable, Sequence
from collections.abc import Sequence, Callable
from qutebrowser.utils import usertypes
from qutebrowser.misc import objects

View File

@ -10,7 +10,8 @@ import pathlib
import functools
import contextlib
import subprocess
from typing import Optional, IO, Iterator
from typing import Optional, IO
from collections.abc import Iterator
from qutebrowser.qt.core import QUrl

View File

@ -9,7 +9,7 @@ import posixpath
import zipfile
import logging
import pathlib
from typing import cast, IO, Set
from typing import cast, IO
from qutebrowser.qt.core import QUrl
@ -92,8 +92,8 @@ class HostBlocker:
) -> None:
self.enabled = _should_be_used()
self._has_basedir = has_basedir
self._blocked_hosts: Set[str] = set()
self._config_blocked_hosts: Set[str] = set()
self._blocked_hosts: set[str] = set()
self._config_blocked_hosts: set[str] = set()
self._local_hosts_file = str(data_dir / "blocked-hosts")
self.update_files()
@ -139,7 +139,7 @@ class HostBlocker:
)
info.block()
def _read_hosts_line(self, raw_line: bytes) -> Set[str]:
def _read_hosts_line(self, raw_line: bytes) -> set[str]:
"""Read hosts from the given line.
Args:
@ -175,7 +175,7 @@ class HostBlocker:
return filtered_hosts
def _read_hosts_file(self, filename: str, target: Set[str]) -> bool:
def _read_hosts_file(self, filename: str, target: set[str]) -> bool:
"""Read hosts from the given filename.
Args:

View File

@ -11,7 +11,8 @@ import os
import signal
import logging
import pathlib
from typing import Optional, Sequence, Callable
from typing import Optional
from collections.abc import Sequence, Callable
try:
import hunter

View File

@ -5,7 +5,8 @@
"""Bridge to provide readline-like shortcuts for QLineEdits."""
import os
from typing import Iterable, Optional, MutableMapping, Any, Callable
from typing import Optional, Any
from collections.abc import Iterable, MutableMapping, Callable
from qutebrowser.qt.widgets import QApplication, QLineEdit

View File

@ -4,7 +4,7 @@
"""Scrolling-related commands."""
from typing import Dict, Callable
from collections.abc import Callable
from qutebrowser.api import cmdutils, apitypes
@ -41,7 +41,7 @@ def scroll(tab: apitypes.Tab, direction: str, count: int = 1) -> None:
count: multiplier
"""
# FIXME:mypy Use a callback protocol to enforce having 'count'?
funcs: Dict[str, Callable[..., None]] = {
funcs: dict[str, Callable[..., None]] = {
'up': tab.scroller.up,
'down': tab.scroller.down,
'left': tab.scroller.left,

View File

@ -6,7 +6,7 @@
import os
import functools
from typing import IO, List, Optional
from typing import IO, Optional
from qutebrowser.qt.core import QUrl, QObject, pyqtSignal
@ -47,11 +47,11 @@ class BlocklistDownloads(QObject):
single_download_finished = pyqtSignal(object) # arg: the file object
all_downloads_finished = pyqtSignal(int) # arg: download count
def __init__(self, urls: List[QUrl], parent: Optional[QObject] = None) -> None:
def __init__(self, urls: list[QUrl], parent: Optional[QObject] = None) -> None:
super().__init__(parent)
self._urls = urls
self._in_progress: List[downloads.TempDownload] = []
self._in_progress: list[downloads.TempDownload] = []
self._done_count = 0
self._finished_registering_downloads = False
self._started = False

View File

@ -7,8 +7,8 @@
import copy
import contextlib
import functools
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Mapping,
MutableMapping, MutableSequence, Optional, Tuple, cast)
from typing import (TYPE_CHECKING, Any, Optional, cast)
from collections.abc import Iterator, Mapping, MutableMapping, MutableSequence, Callable
from qutebrowser.qt.core import pyqtSignal, QObject, QUrl
@ -29,7 +29,7 @@ key_instance = cast('KeyConfig', None)
cache = cast('configcache.ConfigCache', None)
# Keeping track of all change filters to validate them later.
change_filters: List["change_filter"] = []
change_filters: list["change_filter"] = []
# Sentinel
UNSET = object()
@ -131,7 +131,7 @@ class KeyConfig:
_config: The Config object to be used.
"""
_ReverseBindings = Dict[str, MutableSequence[str]]
_ReverseBindings = dict[str, MutableSequence[str]]
def __init__(self, config: 'Config') -> None:
self._config = config
@ -143,7 +143,7 @@ class KeyConfig:
if mode not in configdata.DATA['bindings.default'].default:
raise configexc.KeybindingError("Invalid mode {}!".format(mode))
def get_bindings_for(self, mode: str) -> Dict[keyutils.KeySequence, str]:
def get_bindings_for(self, mode: str) -> dict[keyutils.KeySequence, str]:
"""Get the combined bindings for the given mode."""
bindings = dict(val.bindings.default[mode])
for key, binding in val.bindings.commands[mode].items():
@ -291,7 +291,7 @@ class Config(QObject):
yaml_config: 'configfiles.YamlConfig',
parent: QObject = None) -> None:
super().__init__(parent)
self._mutables: MutableMapping[str, Tuple[Any, Any]] = {}
self._mutables: MutableMapping[str, tuple[Any, Any]] = {}
self._yaml = yaml_config
self._init_values()
self.yaml_loaded = False
@ -554,7 +554,7 @@ class Config(QObject):
Return:
The changed config part as string.
"""
lines: List[str] = []
lines: list[str] = []
for values in sorted(self, key=lambda v: v.opt.name):
lines += values.dump(include_hidden=include_hidden)

View File

@ -4,7 +4,7 @@
"""Implementation of a basic config cache."""
from typing import Any, Dict
from typing import Any
from qutebrowser.config import config
@ -22,7 +22,7 @@ class ConfigCache:
"""
def __init__(self) -> None:
self._cache: Dict[str, Any] = {}
self._cache: dict[str, Any] = {}
config.instance.changed.connect(self._on_config_changed)
def _on_config_changed(self, attr: str) -> None:

View File

@ -6,7 +6,8 @@
import os.path
import contextlib
from typing import TYPE_CHECKING, Iterator, List, Optional, Any, Tuple
from typing import TYPE_CHECKING, Optional, Any
from collections.abc import Iterator
from qutebrowser.qt.core import QUrl, QUrlQuery
@ -473,7 +474,7 @@ class ConfigCommands:
raise cmdutils.CommandError("{} already exists - use --force to "
"overwrite!".format(filename))
options: List[Tuple[Optional[urlmatch.UrlPattern], configdata.Option, Any]] = []
options: list[tuple[Optional[urlmatch.UrlPattern], configdata.Option, Any]] = []
if defaults:
options = [(None, opt, opt.default)
for _name, opt in sorted(configdata.DATA.items())]

View File

@ -9,8 +9,8 @@ Module attributes:
DATA: A dict of Option objects after init() has been called.
"""
from typing import (Any, Dict, Iterable, List, Mapping, MutableMapping, Optional,
Sequence, Tuple, Union, NoReturn, cast)
from typing import (Any, Optional, Union, NoReturn, cast)
from collections.abc import Iterable, Mapping, MutableMapping, Sequence
import functools
import dataclasses
@ -53,8 +53,8 @@ class Migrations:
deleted: A list of option names which have been removed.
"""
renamed: Dict[str, str] = dataclasses.field(default_factory=dict)
deleted: List[str] = dataclasses.field(default_factory=list)
renamed: dict[str, str] = dataclasses.field(default_factory=dict)
deleted: list[str] = dataclasses.field(default_factory=list)
def _raise_invalid_node(name: str, what: str, node: Any) -> NoReturn:
@ -186,7 +186,7 @@ def _parse_yaml_backends(
def _read_yaml(
yaml_data: str,
) -> Tuple[Mapping[str, Option], Migrations]:
) -> tuple[Mapping[str, Option], Migrations]:
"""Read config data from a YAML file.
Args:

View File

@ -322,8 +322,9 @@ qt.chromium.sandboxing:
See the Chromium documentation for more details:
- https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/linux/sandboxing.md[Linux]
- https://chromium.googlesource.com/chromium/src/\+/HEAD/sandbox/linux/README.md[Linux]
- https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/design/sandbox.md[Windows]
- https://chromium.googlesource.com/chromium/src/\+/HEAD/sandbox/mac/README.md[Mac]
- https://chromium.googlesource.com/chromium/src/\+/HEAD/docs/design/sandbox_faq.md[FAQ (Windows-centric)]
# yamllint enable rule:line-length

View File

@ -6,7 +6,8 @@
import difflib
import dataclasses
from typing import Any, Mapping, Optional, Sequence, Union, List
from typing import Any, Optional, Union
from collections.abc import Mapping, Sequence
from qutebrowser.utils import usertypes, log
@ -77,7 +78,7 @@ class NoOptionError(Error):
"""Raised when an option was not found."""
def __init__(self, option: str, *,
all_names: List[str] = None,
all_names: list[str] = None,
deleted: bool = False,
renamed: str = None) -> None:
if deleted:

View File

@ -14,8 +14,8 @@ import traceback
import configparser
import contextlib
import re
from typing import (TYPE_CHECKING, Any, Dict, Iterable, Iterator, List, Mapping,
MutableMapping, Optional, Tuple, cast)
from typing import (TYPE_CHECKING, Any, Optional, cast)
from collections.abc import Iterable, Iterator, Mapping, MutableMapping
import yaml
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, QSettings, qVersion
@ -34,7 +34,7 @@ if TYPE_CHECKING:
state = cast('StateConfig', None)
_SettingsType = Dict[str, Dict[str, Any]]
_SettingsType = dict[str, dict[str, Any]]
class VersionChange(enum.Enum):
@ -55,7 +55,7 @@ class VersionChange(enum.Enum):
This is intended to use filters like "major" (show major only), "minor" (show
major/minor) or "patch" (show all changes).
"""
allowed_values: Dict[str, List[VersionChange]] = {
allowed_values: dict[str, list[VersionChange]] = {
'major': [VersionChange.major],
'minor': [VersionChange.major, VersionChange.minor],
'patch': [VersionChange.major, VersionChange.minor, VersionChange.patch],
@ -250,7 +250,7 @@ class YamlConfig(QObject):
'autoconfig.yml')
self._dirty = False
self._values: Dict[str, configutils.Values] = {}
self._values: dict[str, configutils.Values] = {}
for name, opt in configdata.DATA.items():
self._values[name] = configutils.Values(opt)
@ -702,7 +702,7 @@ class ConfigAPI:
):
self._config = conf
self._keyconfig = keyconfig
self.errors: List[configexc.ConfigErrorDesc] = []
self.errors: list[configexc.ConfigErrorDesc] = []
self.configdir = pathlib.Path(standarddir.config())
self.datadir = pathlib.Path(standarddir.data())
self._warn_autoconfig = warn_autoconfig
@ -803,8 +803,8 @@ class ConfigPyWriter:
def __init__(
self,
options: List[
Tuple[
options: list[
tuple[
Optional[urlmatch.UrlPattern],
configdata.Option,
Any

View File

@ -36,8 +36,9 @@ import functools
import operator
import json
import dataclasses
from typing import (Any, Callable, Dict as DictType, Iterable, Iterator,
List as ListType, Optional, Pattern, Sequence, Tuple, Union)
from typing import Any, Optional, Union
from re import Pattern
from collections.abc import Iterable, Iterator, Sequence, Callable
import yaml
from qutebrowser.qt.core import QUrl, Qt
@ -65,7 +66,7 @@ BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True,
'0': False, 'no': False, 'false': False, 'off': False}
_Completions = Optional[Iterable[Tuple[str, str]]]
_Completions = Optional[Iterable[tuple[str, str]]]
_StrUnset = Union[str, usertypes.Unset]
_UnsetNone = Union[None, usertypes.Unset]
_StrUnsetNone = Union[str, _UnsetNone]
@ -102,16 +103,16 @@ class ValidValues:
self,
*values: Union[
str,
DictType[str, Optional[str]],
Tuple[str, Optional[str]],
dict[str, Optional[str]],
tuple[str, Optional[str]],
],
generate_docs: bool = True,
others_permitted: bool = False
) -> None:
if not values:
raise ValueError("ValidValues with no values makes no sense!")
self.descriptions: DictType[str, str] = {}
self.values: ListType[str] = []
self.descriptions: dict[str, str] = {}
self.values: list[str] = []
self.generate_docs = generate_docs
self.others_permitted = others_permitted
for value in values:
@ -189,7 +190,7 @@ class BaseType:
def _basic_py_validation(
self, value: Any,
pytype: Union[type, Tuple[type, ...]]) -> None:
pytype: Union[type, tuple[type, ...]]) -> None:
"""Do some basic validation for Python values (emptyness, type).
Arguments:
@ -355,7 +356,7 @@ class MappingType(BaseType):
MAPPING: A mapping from config values to (translated_value, docs) tuples.
"""
MAPPING: DictType[str, Tuple[Any, Optional[str]]] = {}
MAPPING: dict[str, tuple[Any, Optional[str]]] = {}
def __init__(
self, *,
@ -507,7 +508,7 @@ class List(BaseType):
def get_valid_values(self) -> Optional[ValidValues]:
return self.valtype.get_valid_values()
def from_str(self, value: str) -> Optional[ListType]:
def from_str(self, value: str) -> Optional[list]:
self._basic_str_validation(value)
if not value:
return None
@ -522,15 +523,15 @@ class List(BaseType):
self.to_py(yaml_val)
return yaml_val
def from_obj(self, value: Optional[ListType]) -> ListType:
def from_obj(self, value: Optional[list]) -> list:
if value is None:
return []
return [self.valtype.from_obj(v) for v in value]
def to_py(
self,
value: Union[ListType, usertypes.Unset]
) -> Union[ListType, usertypes.Unset]:
value: Union[list, usertypes.Unset]
) -> Union[list, usertypes.Unset]:
self._basic_py_validation(value, list)
if isinstance(value, usertypes.Unset):
return value
@ -545,13 +546,13 @@ class List(BaseType):
"be set!".format(self.length))
return [self.valtype.to_py(v) for v in value]
def to_str(self, value: ListType) -> str:
def to_str(self, value: list) -> str:
if not value:
# An empty list is treated just like None -> empty string
return ''
return json.dumps(value)
def to_doc(self, value: ListType, indent: int = 0) -> str:
def to_doc(self, value: list, indent: int = 0) -> str:
if not value:
return 'empty'
@ -596,7 +597,7 @@ class ListOrValue(BaseType):
self.listtype = List(valtype=valtype, none_ok=none_ok, **kwargs)
self.valtype = valtype
def _val_and_type(self, value: Any) -> Tuple[Any, BaseType]:
def _val_and_type(self, value: Any) -> tuple[Any, BaseType]:
"""Get the value and type to use for to_str/to_doc/from_str."""
if isinstance(value, list):
if len(value) == 1:
@ -677,15 +678,15 @@ class FlagList(List):
)
self.valtype.valid_values = valid_values
def _check_duplicates(self, values: ListType) -> None:
def _check_duplicates(self, values: list) -> None:
if len(set(values)) != len(values):
raise configexc.ValidationError(
values, "List contains duplicate values!")
def to_py(
self,
value: Union[usertypes.Unset, ListType],
) -> Union[usertypes.Unset, ListType]:
value: Union[usertypes.Unset, list],
) -> Union[usertypes.Unset, list]:
vals = super().to_py(value)
if not isinstance(vals, usertypes.Unset):
self._check_duplicates(vals)
@ -1121,7 +1122,7 @@ class QtColor(BaseType):
kind = value[:openparen]
vals = value[openparen+1:-1].split(',')
converters: DictType[str, Callable[..., QColor]] = {
converters: dict[str, Callable[..., QColor]] = {
'rgba': QColor.fromRgb,
'rgb': QColor.fromRgb,
'hsva': QColor.fromHsv,
@ -1211,7 +1212,7 @@ class FontBase(BaseType):
(?P<family>.+) # mandatory font family""", re.VERBOSE)
@classmethod
def set_defaults(cls, default_family: ListType[str], default_size: str) -> None:
def set_defaults(cls, default_family: list[str], default_size: str) -> None:
"""Make sure default_family/default_size are available.
If the given family value (fonts.default_family in the config) is
@ -1384,7 +1385,7 @@ class Dict(BaseType):
self.fixed_keys = fixed_keys
self.required_keys = required_keys
def _validate_keys(self, value: DictType) -> None:
def _validate_keys(self, value: dict) -> None:
if (self.fixed_keys is not None and not
set(value.keys()).issubset(self.fixed_keys)):
raise configexc.ValidationError(
@ -1395,7 +1396,7 @@ class Dict(BaseType):
raise configexc.ValidationError(
value, "Required keys {}".format(self.required_keys))
def from_str(self, value: str) -> Optional[DictType]:
def from_str(self, value: str) -> Optional[dict]:
self._basic_str_validation(value)
if not value:
return None
@ -1410,14 +1411,14 @@ class Dict(BaseType):
self.to_py(yaml_val)
return yaml_val
def from_obj(self, value: Optional[DictType]) -> DictType:
def from_obj(self, value: Optional[dict]) -> dict:
if value is None:
return {}
return {self.keytype.from_obj(key): self.valtype.from_obj(val)
for key, val in value.items()}
def _fill_fixed_keys(self, value: DictType) -> DictType:
def _fill_fixed_keys(self, value: dict) -> dict:
"""Fill missing fixed keys with a None-value."""
if self.fixed_keys is None:
return value
@ -1428,8 +1429,8 @@ class Dict(BaseType):
def to_py(
self,
value: Union[DictType, _UnsetNone]
) -> Union[DictType, usertypes.Unset]:
value: Union[dict, _UnsetNone]
) -> Union[dict, usertypes.Unset]:
self._basic_py_validation(value, dict)
if isinstance(value, usertypes.Unset):
return value
@ -1445,13 +1446,13 @@ class Dict(BaseType):
for key, val in value.items()}
return self._fill_fixed_keys(d)
def to_str(self, value: DictType) -> str:
def to_str(self, value: dict) -> str:
if not value:
# An empty Dict is treated just like None -> empty string
return ''
return json.dumps(value, sort_keys=True)
def to_doc(self, value: DictType, indent: int = 0) -> str:
def to_doc(self, value: dict, indent: int = 0) -> str:
if not value:
return 'empty'
lines = ['\n']
@ -1605,8 +1606,8 @@ class ShellCommand(List):
def to_py(
self,
value: Union[ListType, usertypes.Unset],
) -> Union[ListType, usertypes.Unset]:
value: Union[list, usertypes.Unset],
) -> Union[list, usertypes.Unset]:
py_value = super().to_py(value)
if isinstance(py_value, usertypes.Unset):
return py_value
@ -1763,7 +1764,7 @@ class Padding(Dict):
def to_py( # type: ignore[override]
self,
value: Union[DictType, _UnsetNone],
value: Union[dict, _UnsetNone],
) -> Union[usertypes.Unset, PaddingValues]:
d = super().to_py(value)
if isinstance(d, usertypes.Unset):
@ -1916,8 +1917,8 @@ class ConfirmQuit(FlagList):
def to_py(
self,
value: Union[usertypes.Unset, ListType],
) -> Union[ListType, usertypes.Unset]:
value: Union[usertypes.Unset, list],
) -> Union[list, usertypes.Unset]:
values = super().to_py(value)
if isinstance(values, usertypes.Unset):
return values

View File

@ -9,8 +9,8 @@ import collections
import itertools
import operator
from typing import (
TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Sequence, Set, Union,
MutableMapping)
TYPE_CHECKING, Any, Optional, Union)
from collections.abc import Iterator, Sequence, MutableMapping
from qutebrowser.qt.core import QUrl
from qutebrowser.qt.gui import QFontDatabase
@ -78,8 +78,8 @@ class Values:
self._vmap: MutableMapping[
Values._VmapKeyType, ScopedValue] = collections.OrderedDict()
# A map from domain parts to rules that fall under them.
self._domain_map: Dict[
Optional[str], Set[ScopedValue]] = collections.defaultdict(set)
self._domain_map: dict[
Optional[str], set[ScopedValue]] = collections.defaultdict(set)
for scoped in values:
self._add_scoped(scoped)
@ -203,7 +203,7 @@ class Values:
return self._get_fallback(fallback)
qtutils.ensure_valid(url)
candidates: List[ScopedValue] = []
candidates: list[ScopedValue] = []
# Urls trailing with '.' are equivalent to non-trailing types.
# urlutils strips them, so in order to match we will need to as well.
widened_hosts = urlutils.widened_hostnames(url.host().rstrip('.'))

View File

@ -8,7 +8,11 @@ import os
import sys
import argparse
import pathlib
from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Union, Callable
# Using deprecated typing.Callable as a WORKAROUND because
# collections.abc.Callable inside Optional[...]/Union[...]
# is broken on Python 3.9.0 and 3.9.1
from typing import Any, Optional, Union, Callable
from collections.abc import Iterator, Sequence
from qutebrowser.qt import machinery
from qutebrowser.qt.core import QLocale
@ -23,7 +27,7 @@ _DISABLE_FEATURES = '--disable-features='
_BLINK_SETTINGS = '--blink-settings='
def qt_args(namespace: argparse.Namespace) -> List[str]:
def qt_args(namespace: argparse.Namespace) -> list[str]:
"""Get the Qt QApplication arguments based on an argparse namespace.
Args:
@ -77,7 +81,7 @@ def qt_args(namespace: argparse.Namespace) -> List[str]:
def _qtwebengine_features(
versions: version.WebEngineVersions,
special_flags: Sequence[str],
) -> Tuple[Sequence[str], Sequence[str]]:
) -> tuple[Sequence[str], Sequence[str]]:
"""Get a tuple of --enable-features/--disable-features flags for QtWebEngine.
Args:
@ -91,10 +95,10 @@ def _qtwebengine_features(
for flag in special_flags:
if flag.startswith(_ENABLE_FEATURES):
flag = flag[len(_ENABLE_FEATURES):]
flag = flag.removeprefix(_ENABLE_FEATURES)
enabled_features += flag.split(',')
elif flag.startswith(_DISABLE_FEATURES):
flag = flag[len(_DISABLE_FEATURES):]
flag = flag.removeprefix(_DISABLE_FEATURES)
disabled_features += flag.split(',')
elif flag.startswith(_BLINK_SETTINGS):
pass
@ -285,7 +289,7 @@ _SettingValueType = Union[
Optional[str],
],
]
_WEBENGINE_SETTINGS: Dict[str, Dict[Any, Optional[_SettingValueType]]] = {
_WEBENGINE_SETTINGS: dict[str, dict[Any, Optional[_SettingValueType]]] = {
'qt.force_software_rendering': {
'software-opengl': None,
'qt-quick': None,

View File

@ -5,7 +5,7 @@
"""Handling of Qt qss stylesheets."""
import functools
from typing import Optional, FrozenSet
from typing import Optional
from qutebrowser.qt.core import pyqtSlot, QObject
from qutebrowser.qt.widgets import QWidget
@ -72,7 +72,7 @@ class _StyleSheetObserver(QObject):
self._stylesheet = stylesheet
if update:
self._options: Optional[FrozenSet[str]] = jinja.template_config_variables(
self._options: Optional[frozenset[str]] = jinja.template_config_variables(
self._stylesheet)
else:
self._options = None

View File

@ -8,7 +8,8 @@ import re
import argparse
import functools
import dataclasses
from typing import Any, Callable, Dict, Optional, Union
from typing import Any, Optional, Union
from collections.abc import Callable
from qutebrowser.qt.core import QUrl, pyqtSlot, qVersion
from qutebrowser.qt.gui import QFont
@ -86,10 +87,10 @@ class AbstractSettings:
"""Abstract base class for settings set via QWeb(Engine)Settings."""
_ATTRIBUTES: Dict[str, AttributeInfo] = {}
_FONT_SIZES: Dict[str, Any] = {}
_FONT_FAMILIES: Dict[str, Any] = {}
_FONT_TO_QFONT: Dict[Any, QFont.StyleHint] = {}
_ATTRIBUTES: dict[str, AttributeInfo] = {}
_FONT_SIZES: dict[str, Any] = {}
_FONT_FAMILIES: dict[str, Any] = {}
_FONT_TO_QFONT: dict[Any, QFont.StyleHint] = {}
def __init__(self, settings: Any) -> None:
self._settings = settings

View File

@ -6,7 +6,8 @@
import enum
import dataclasses
from typing import Callable, List, Optional
from typing import Optional
from collections.abc import Callable
from qutebrowser.qt.core import QUrl
@ -89,7 +90,7 @@ class Request:
InterceptorType = Callable[[Request], None]
_interceptors: List[InterceptorType] = []
_interceptors: list[InterceptorType] = []
def register(interceptor: InterceptorType) -> None:

View File

@ -10,7 +10,8 @@ import pathlib
import importlib
import argparse
import dataclasses
from typing import Callable, Iterator, List, Optional, Tuple
from typing import Optional
from collections.abc import Iterator, Callable
from qutebrowser.qt.core import pyqtSlot
@ -21,7 +22,7 @@ from qutebrowser.misc import objects
# ModuleInfo objects for all loaded plugins
_module_infos: List["ModuleInfo"] = []
_module_infos: list["ModuleInfo"] = []
InitHookType = Callable[['InitContext'], None]
ConfigChangedHookType = Callable[[], None]
@ -47,8 +48,8 @@ class ModuleInfo:
skip_hooks: bool = False
init_hook: Optional[InitHookType] = None
config_changed_hooks: List[
Tuple[
config_changed_hooks: list[
tuple[
Optional[str],
ConfigChangedHookType,
]

View File

@ -8,7 +8,8 @@ import string
import types
import dataclasses
import traceback
from typing import Mapping, MutableMapping, Optional, Sequence
from typing import Optional
from collections.abc import Mapping, MutableMapping, Sequence
from qutebrowser.qt.core import QObject, pyqtSignal
from qutebrowser.qt.gui import QKeySequence, QKeyEvent

View File

@ -18,7 +18,8 @@ handle what we actually think we do.
import itertools
import dataclasses
from typing import Iterator, Iterable, List, Mapping, Optional, Union, overload, cast
from typing import Optional, Union, overload, cast
from collections.abc import Iterator, Iterable, Mapping
from qutebrowser.qt import machinery
from qutebrowser.qt.core import Qt, QEvent
@ -523,7 +524,7 @@ class KeySequence:
_MAX_LEN = 4
def __init__(self, *keys: KeyInfo) -> None:
self._sequences: List[QKeySequence] = []
self._sequences: list[QKeySequence] = []
for sub in utils.chunk(keys, self._MAX_LEN):
try:
args = [info.to_qt() for info in sub]
@ -546,7 +547,7 @@ class KeySequence:
"""Iterate over KeyInfo objects."""
# FIXME:mypy Stubs seem to be unaware that iterating a QKeySequence produces
# _KeyInfoType
sequences = cast(List[Iterable[_KeyInfoType]], self._sequences)
sequences = cast(list[Iterable[_KeyInfoType]], self._sequences)
for combination in itertools.chain.from_iterable(sequences):
yield KeyInfo.from_qt(combination)
@ -719,7 +720,7 @@ class KeySequence:
mappings: Mapping['KeySequence', 'KeySequence']
) -> 'KeySequence':
"""Get a new KeySequence with the given mappings applied."""
infos: List[KeyInfo] = []
infos: list[KeyInfo] = []
for info in self:
key_seq = KeySequence(info)
if key_seq in mappings:

View File

@ -5,7 +5,7 @@
"""Keyboard macro system."""
from typing import cast, Dict, List, Optional, Tuple
from typing import cast, Optional
from qutebrowser.commands import runners
from qutebrowser.api import cmdutils
@ -13,7 +13,7 @@ from qutebrowser.keyinput import modeman
from qutebrowser.utils import message, objreg, usertypes
_CommandType = Tuple[str, int] # command, type
_CommandType = tuple[str, int] # command, type
macro_recorder = cast('MacroRecorder', None)
@ -32,9 +32,9 @@ class MacroRecorder:
"""
def __init__(self) -> None:
self._macros: Dict[str, List[_CommandType]] = {}
self._macros: dict[str, list[_CommandType]] = {}
self._recording_macro: Optional[str] = None
self._macro_count: Dict[int, int] = {}
self._macro_count: dict[int, int] = {}
self._last_register: Optional[str] = None
@cmdutils.register(instance='macro-recorder')

View File

@ -6,7 +6,8 @@
import functools
import dataclasses
from typing import Mapping, Callable, MutableMapping, Union, Set, cast
from typing import Union, cast
from collections.abc import Mapping, MutableMapping, Callable
from qutebrowser.qt import machinery
from qutebrowser.qt.core import pyqtSlot, pyqtSignal, Qt, QObject, QEvent
@ -252,7 +253,7 @@ class ModeManager(QObject):
self.parsers: ParserDictType = {}
self._prev_mode = usertypes.KeyMode.normal
self.mode = usertypes.KeyMode.normal
self._releaseevents_to_pass: Set[KeyEvent] = set()
self._releaseevents_to_pass: set[KeyEvent] = set()
# Set after __init__
self.hintmanager = cast(hints.HintManager, None)

Some files were not shown because too many files have changed in this diff Show More