Compare commits
10 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
8cb4556245 | |
|
|
21ee2d093a | |
|
|
06f77d18d2 | |
|
|
96ce299f3c | |
|
|
a41c14412b | |
|
|
f716467cb9 | |
|
|
6e22ec67b1 | |
|
|
a6736dd0f4 | |
|
|
a8a84b81d1 | |
|
|
649aac0c11 |
|
|
@ -0,0 +1,19 @@
|
|||
[bumpversion]
|
||||
current_version = 3.2.1
|
||||
commit = True
|
||||
message = Release v{new_version}
|
||||
tag = True
|
||||
sign_tags = True
|
||||
tag_name = v{new_version}
|
||||
|
||||
[bumpversion:file:qutebrowser/__init__.py]
|
||||
parse = __version__ = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
||||
|
||||
[bumpversion:file:misc/org.qutebrowser.qutebrowser.appdata.xml]
|
||||
search = <!-- Add new releases here -->
|
||||
replace = <!-- Add new releases here -->
|
||||
<release version="{new_version}" date="{now:%Y-%m-%d}"/>
|
||||
|
||||
[bumpversion:file:doc/changelog.asciidoc]
|
||||
search = (unreleased)
|
||||
replace = ({now:%Y-%m-%d})
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
[tool.bumpversion]
|
||||
current_version = "3.6.3"
|
||||
commit = true
|
||||
message = "Release v{new_version}"
|
||||
tag = true
|
||||
sign_tags = true
|
||||
tag_name = "v{new_version}"
|
||||
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
||||
serialize = ["{major}.{minor}.{patch}"]
|
||||
allow_dirty = false
|
||||
|
||||
[[tool.bumpversion.files]]
|
||||
filename = "qutebrowser/__init__.py"
|
||||
search = "__version__ = \"{current_version}\""
|
||||
replace = "__version__ = \"{new_version}\""
|
||||
|
||||
[[tool.bumpversion.files]]
|
||||
filename = "misc/org.qutebrowser.qutebrowser.appdata.xml"
|
||||
search = "<!-- Add new releases here -->"
|
||||
replace = """<!-- Add new releases here -->
|
||||
<release version='{new_version}' date='{now:%Y-%m-%d}'/>"""
|
||||
|
||||
[[tool.bumpversion.files]]
|
||||
filename = "doc/changelog.asciidoc"
|
||||
search = "(unreleased)"
|
||||
replace = "({now:%Y-%m-%d})"
|
||||
|
|
@ -4,7 +4,6 @@ include =
|
|||
tests/*
|
||||
scripts/*
|
||||
branch = true
|
||||
patch = subprocess
|
||||
omit =
|
||||
qutebrowser/__main__.py
|
||||
*/__init__.py
|
||||
|
|
|
|||
5
.flake8
5
.flake8
|
|
@ -42,7 +42,6 @@ exclude = .*,__pycache__,resources.py
|
|||
# W503: like break before binary operator
|
||||
# W504: line break after binary operator
|
||||
# FI18: __future__ import "annotations" missing
|
||||
# FI58: __future__ import "annotations" present
|
||||
# PT004: fixture '{name}' does not return anything, add leading underscore
|
||||
# PT011: pytest.raises(ValueError) is too broad, set the match parameter or use a more specific exception
|
||||
# PT012: pytest.raises() block should contain a single simple statement
|
||||
|
|
@ -55,11 +54,11 @@ ignore =
|
|||
D102,D103,D106,D107,D104,D105,D209,D211,D401,D402,D403,D412,D413,
|
||||
A003,
|
||||
W503, W504,
|
||||
FI18,FI58,
|
||||
FI18,
|
||||
PT004,
|
||||
PT011,
|
||||
PT012
|
||||
min-version = 3.9.0
|
||||
min-version = 3.8.0
|
||||
max-complexity = 12
|
||||
per-file-ignores =
|
||||
qutebrowser/api/hook.py : N801
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ on:
|
|||
jobs:
|
||||
tests:
|
||||
if: "github.repository == 'qutebrowser/qutebrowser'"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- testenv: bleeding
|
||||
image: "archlinux-webengine-unstable-qt6"
|
||||
- testenv: bleeding-qt5
|
||||
image: "archlinux-webengine-unstable"
|
||||
container:
|
||||
image: "qutebrowser/ci:${{ matrix.image }}"
|
||||
|
|
@ -25,40 +27,25 @@ jobs:
|
|||
PY_COLORS: "1"
|
||||
DOCKER: "${{ matrix.image }}"
|
||||
CI: true
|
||||
TMPDIR: "${{ runner.temp }}"
|
||||
volumes:
|
||||
# Hardcoded because we can't use ${{ runner.temp }} here apparently.
|
||||
- /home/runner/work/_temp/:/home/runner/work/_temp/
|
||||
options: --privileged --tty
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up problem matchers
|
||||
run: "python scripts/dev/ci/problemmatchers.py py3 ${{ runner.temp }}"
|
||||
- name: Upgrade 3rd party assets
|
||||
run: "tox exec -e ${{ matrix.testenv }} -- python scripts/dev/update_3rdparty.py --gh-token ${{ secrets.GITHUB_TOKEN }} --modern-pdfjs"
|
||||
run: "tox exec -e ${{ matrix.testenv }} -- python scripts/dev/update_3rdparty.py --gh-token ${{ secrets.GITHUB_TOKEN }}"
|
||||
if: "endsWith(matrix.image, '-qt6')"
|
||||
- name: Run tox
|
||||
run: dbus-run-session tox -e ${{ matrix.testenv }}
|
||||
- name: Gather info
|
||||
id: info
|
||||
run: |
|
||||
echo "date=$(date +'%Y-%m-%d')" >> "$GITHUB_OUTPUT"
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
||||
shell: bash
|
||||
if: failure()
|
||||
- name: Upload screenshots
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: "end2end-screenshots-${{ steps.info.outputs.date }}-${{ steps.info.outputs.sha_short }}-${{ matrix.image }}"
|
||||
path: |
|
||||
${{ runner.temp }}/pytest-of-user/pytest-current/pytest-screenshots/*.png
|
||||
if-no-files-found: ignore
|
||||
if: failure()
|
||||
irc:
|
||||
timeout-minutes: 2
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [tests]
|
||||
if: "always() && github.repository == 'qutebrowser/qutebrowser'"
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
linters:
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||
timeout-minutes: 10
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -27,6 +27,7 @@ jobs:
|
|||
- testenv: vulture
|
||||
- testenv: misc
|
||||
- testenv: pyroma
|
||||
- testenv: check-manifest
|
||||
- testenv: eslint
|
||||
- testenv: shellcheck
|
||||
args: "-f gcc" # For problem matchers
|
||||
|
|
@ -34,30 +35,30 @@ jobs:
|
|||
- testenv: actionlint
|
||||
- testenv: package
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/cache@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.mypy_cache
|
||||
.tox
|
||||
~/.cache/pip
|
||||
key: "${{ matrix.testenv }}-${{ hashFiles('misc/requirements/requirements-*.txt') }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('scripts/dev/pylint_checkers/qute_pylint/*.py') }}"
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22.x'
|
||||
node-version: '16.x'
|
||||
if: "matrix.testenv == 'eslint'"
|
||||
- name: Set up problem matchers
|
||||
run: "python scripts/dev/ci/problemmatchers.py ${{ matrix.testenv }} ${{ runner.temp }}"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
[[ ${{ matrix.testenv }} == eslint ]] && npm install -g 'eslint@<9.0.0'
|
||||
[[ ${{ matrix.testenv }} == docs ]] && sudo apt-get update && sudo apt-get install --no-install-recommends asciidoc libegl1
|
||||
[[ ${{ matrix.testenv }} == vulture || ${{ matrix.testenv }} == pylint ]] && sudo apt-get update && sudo apt-get install --no-install-recommends libegl1
|
||||
[[ ${{ matrix.testenv }} == docs ]] && sudo apt-get update && sudo apt-get install --no-install-recommends asciidoc libegl1-mesa
|
||||
[[ ${{ matrix.testenv }} == vulture || ${{ matrix.testenv }} == pylint ]] && sudo apt-get update && sudo apt-get install --no-install-recommends libegl1-mesa
|
||||
if [[ ${{ matrix.testenv }} == shellcheck ]]; then
|
||||
scversion="stable"
|
||||
bindir="$HOME/.local/bin"
|
||||
|
|
@ -85,49 +86,39 @@ jobs:
|
|||
tests-docker:
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||
timeout-minutes: 45
|
||||
runs-on: ubuntu-22.04 # not 24.04 because sandboxing fails by default (#8424)
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- testenv: py
|
||||
- testenv: py-qt5
|
||||
image: archlinux-webkit
|
||||
- testenv: py-qt5
|
||||
image: archlinux-webengine
|
||||
- testenv: py
|
||||
- testenv: py-qt5
|
||||
image: archlinux-webengine-unstable
|
||||
- testenv: py
|
||||
image: archlinux-webengine-qt6
|
||||
- testenv: py
|
||||
image: archlinux-webengine-unstable-qt6
|
||||
container:
|
||||
image: "qutebrowser/ci:${{ matrix.image }}"
|
||||
env:
|
||||
DOCKER: "${{ matrix.image }}"
|
||||
CI: true
|
||||
PYTEST_ADDOPTS: "--color=yes"
|
||||
TMPDIR: "${{ runner.temp }}"
|
||||
volumes:
|
||||
# Hardcoded because we can't use ${{ runner.temp }} here apparently.
|
||||
- /home/runner/work/_temp/:/home/runner/work/_temp/
|
||||
options: --privileged --tty
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up problem matchers
|
||||
run: "python scripts/dev/ci/problemmatchers.py tests ${{ runner.temp }}"
|
||||
- name: Run tox
|
||||
run: "dbus-run-session -- tox -e ${{ matrix.testenv }}"
|
||||
- name: Gather info
|
||||
id: info
|
||||
run: |
|
||||
echo "date=$(date +'%Y-%m-%d')" >> "$GITHUB_OUTPUT"
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
||||
shell: bash
|
||||
if: failure()
|
||||
- name: Upload screenshots
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: "end2end-screenshots-${{ steps.info.outputs.date }}-${{ steps.info.outputs.sha_short }}-${{ matrix.image }}"
|
||||
path: |
|
||||
${{ runner.temp }}/pytest-of-user/pytest-current/pytest-screenshots/*.png
|
||||
if-no-files-found: ignore
|
||||
if: failure()
|
||||
|
||||
tests:
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||
|
|
@ -137,10 +128,10 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
### PyQt 5.15.2 (Python 3.9)
|
||||
- testenv: py39-pyqt5152
|
||||
os: ubuntu-22.04
|
||||
python: "3.9"
|
||||
### PyQt 5.15.2 (Python 3.8)
|
||||
- testenv: py38-pyqt5152
|
||||
os: ubuntu-20.04
|
||||
python: "3.8"
|
||||
### PyQt 5.15 (Python 3.10, with coverage)
|
||||
# FIXME:qt6
|
||||
# - testenv: py310-pyqt515-cov
|
||||
|
|
@ -148,19 +139,19 @@ jobs:
|
|||
# python: "3.10"
|
||||
### PyQt 5.15 (Python 3.11)
|
||||
- testenv: py311-pyqt515
|
||||
os: ubuntu-22.04
|
||||
os: ubuntu-20.04
|
||||
python: "3.11"
|
||||
### PyQt 6.2 (Python 3.9)
|
||||
- testenv: py39-pyqt62
|
||||
os: ubuntu-22.04
|
||||
python: "3.9"
|
||||
### PyQt 6.3 (Python 3.9)
|
||||
- testenv: py39-pyqt63
|
||||
os: ubuntu-22.04
|
||||
python: "3.9"
|
||||
### PyQt 6.2 (Python 3.8)
|
||||
- testenv: py38-pyqt62
|
||||
os: ubuntu-20.04
|
||||
python: "3.8"
|
||||
### PyQt 6.3 (Python 3.8)
|
||||
- testenv: py38-pyqt63
|
||||
os: ubuntu-20.04
|
||||
python: "3.8"
|
||||
## PyQt 6.4 (Python 3.9)
|
||||
- testenv: py39-pyqt64
|
||||
os: ubuntu-22.04
|
||||
os: ubuntu-20.04
|
||||
python: "3.9"
|
||||
### PyQt 6.5 (Python 3.10)
|
||||
- testenv: py310-pyqt65
|
||||
|
|
@ -182,45 +173,31 @@ jobs:
|
|||
- testenv: py312-pyqt67
|
||||
os: ubuntu-22.04
|
||||
python: "3.12"
|
||||
### PyQt 6.8 (Python 3.13)
|
||||
- testenv: py313-pyqt68
|
||||
os: ubuntu-24.04
|
||||
python: "3.13"
|
||||
### PyQt 6.8 (Python 3.13)
|
||||
- testenv: py313-pyqt68
|
||||
os: ubuntu-24.04
|
||||
python: "3.13"
|
||||
### PyQt 6.9 (Python 3.14)
|
||||
- testenv: py314-pyqt69
|
||||
os: ubuntu-24.04
|
||||
python: "3.14"
|
||||
### PyQt 6.10 (Python 3.14)
|
||||
- testenv: py314-pyqt610
|
||||
os: ubuntu-24.04
|
||||
python: "3.14"
|
||||
### macOS Sonoma (M1 runner)
|
||||
- testenv: py314-pyqt610
|
||||
os: macos-14
|
||||
python: "3.14"
|
||||
### macOS Big Sur
|
||||
- testenv: py312-pyqt67
|
||||
os: macos-11
|
||||
python: "3.12"
|
||||
args: "tests/unit" # Only run unit tests on macOS
|
||||
### macOS Sequoia (Intel runner)
|
||||
- testenv: py314-pyqt610
|
||||
os: macos-15-intel
|
||||
python: "3.14"
|
||||
### macOS Monterey
|
||||
- testenv: py312-pyqt67
|
||||
os: macos-12
|
||||
python: "3.12"
|
||||
args: "tests/unit" # Only run unit tests on macOS
|
||||
### macOS Sonoma (M1 runner)
|
||||
- testenv: py312-pyqt67
|
||||
os: macos-14
|
||||
python: "3.12"
|
||||
args: "tests/unit" # Only run unit tests on macOS
|
||||
### Windows
|
||||
- testenv: py314-pyqt610
|
||||
os: windows-2022
|
||||
python: "3.14"
|
||||
- testenv: py314-pyqt610
|
||||
os: windows-2025
|
||||
python: "3.14"
|
||||
- testenv: py312-pyqt67
|
||||
os: windows-2019
|
||||
python: "3.12"
|
||||
runs-on: "${{ matrix.os }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/cache@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.mypy_cache
|
||||
|
|
@ -228,7 +205,7 @@ jobs:
|
|||
~/.cache/pip
|
||||
key: "${{ matrix.testenv }}-${{ matrix.os }}-${{ matrix.python }}-${{ hashFiles('misc/requirements/requirements-*.txt') }}-${{ hashFiles('requirements.txt') }}"
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "${{ matrix.python }}"
|
||||
- name: Set up problem matchers
|
||||
|
|
@ -236,7 +213,7 @@ jobs:
|
|||
- name: Install apt dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends libyaml-dev libegl1 libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0 libjpeg-dev
|
||||
sudo apt-get install --no-install-recommends libyaml-dev libegl1-mesa libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0
|
||||
if: "startsWith(matrix.os, 'ubuntu-')"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
|
@ -245,8 +222,6 @@ jobs:
|
|||
- name: Upgrade 3rd party assets
|
||||
run: "tox exec -e ${{ matrix.testenv }} -- python scripts/dev/update_3rdparty.py --gh-token ${{ secrets.GITHUB_TOKEN }}"
|
||||
if: "startsWith(matrix.os, 'windows-')"
|
||||
- name: "Set TMPDIR for pytest"
|
||||
run: 'echo "TMPDIR=${{ runner.temp }}" >> "$GITHUB_ENV"'
|
||||
- name: "Run ${{ matrix.testenv }}"
|
||||
run: "dbus-run-session -- tox -e ${{ matrix.testenv }} -- ${{ matrix.args }}"
|
||||
if: "startsWith(matrix.os, 'ubuntu-')"
|
||||
|
|
@ -258,48 +233,33 @@ jobs:
|
|||
if: "failure()"
|
||||
- name: Upload coverage
|
||||
if: "endsWith(matrix.testenv, '-cov')"
|
||||
uses: codecov/codecov-action@v5
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: "${{ matrix.testenv }}"
|
||||
- name: Gather info
|
||||
id: info
|
||||
run: |
|
||||
echo "date=$(date +'%Y-%m-%d')" >> "$GITHUB_OUTPUT"
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
||||
shell: bash
|
||||
if: failure()
|
||||
- name: Upload screenshots
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: "end2end-screenshots-${{ steps.info.outputs.date }}-${{ steps.info.outputs.sha_short }}-${{ matrix.testenv }}-${{ matrix.os }}"
|
||||
path: |
|
||||
${{ runner.temp }}/pytest-of-runner/pytest-current/pytest-screenshots/*.png
|
||||
if-no-files-found: ignore
|
||||
if: failure()
|
||||
|
||||
codeql:
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||
permissions:
|
||||
security-events: write
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: javascript, python
|
||||
queries: +security-extended
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
irc:
|
||||
timeout-minutes: 2
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [linters, tests, tests-docker, codeql]
|
||||
if: "always() && github.repository_owner == 'qutebrowser'"
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -8,16 +8,19 @@ on:
|
|||
jobs:
|
||||
docker:
|
||||
if: "github.repository == 'qutebrowser/qutebrowser'"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image:
|
||||
- archlinux-webkit
|
||||
- archlinux-webengine
|
||||
- archlinux-webengine-unstable
|
||||
- archlinux-webengine-unstable-qt6
|
||||
- archlinux-webengine-qt6
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- run: pip install jinja2
|
||||
|
|
@ -29,7 +32,7 @@ jobs:
|
|||
with:
|
||||
username: qutebrowser
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- uses: docker/build-push-action@v6
|
||||
- uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: scripts/dev/ci/docker/Dockerfile
|
||||
context: .
|
||||
|
|
@ -39,7 +42,7 @@ jobs:
|
|||
irc:
|
||||
timeout-minutes: 2
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [docker]
|
||||
if: "always() && github.repository == 'qutebrowser/qutebrowser'"
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -14,45 +14,50 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-15-intel
|
||||
- os: macos-11
|
||||
toxenv: build-release-qt5
|
||||
name: qt5-macos
|
||||
- os: windows-2019
|
||||
toxenv: build-release-qt5
|
||||
name: qt5-windows
|
||||
- os: macos-11
|
||||
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-11
|
||||
toxenv: build-release
|
||||
name: macos-intel
|
||||
- os: macos-14
|
||||
toxenv: build-release
|
||||
name: macos-apple-silicon
|
||||
- os: windows-latest
|
||||
- os: windows-2019
|
||||
toxenv: build-release
|
||||
name: windows
|
||||
- os: macos-15-intel
|
||||
- os: macos-11
|
||||
args: --debug
|
||||
toxenv: build-release
|
||||
name: macos-debug-intel
|
||||
- os: macos-14
|
||||
toxenv: build-release
|
||||
name: macos-debug-apple-silicon
|
||||
- os: windows-latest
|
||||
- os: windows-2019
|
||||
args: --debug
|
||||
toxenv: build-release
|
||||
name: windows-debug
|
||||
runs-on: "${{ matrix.os }}"
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- name: Install nsis
|
||||
if: "matrix.os == 'windows-latest'"
|
||||
run: |
|
||||
irm get.scoop.sh | iex
|
||||
scoop update
|
||||
scoop bucket add extras
|
||||
scoop install nsis
|
||||
Add-Content $env:GITHUB_PATH "C:\Users\runneradmin\scoop\shims"
|
||||
shell: pwsh
|
||||
python-version: "3.10"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
|
|
@ -72,7 +77,7 @@ jobs:
|
|||
echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
||||
shell: bash
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: "qutebrowser-nightly-${{ steps.info.outputs.date }}-${{ steps.info.outputs.sha_short }}-${{ matrix.name }}"
|
||||
path: |
|
||||
|
|
@ -84,7 +89,7 @@ jobs:
|
|||
irc:
|
||||
timeout-minutes: 2
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [pyinstaller]
|
||||
if: "always() && github.repository == 'qutebrowser/qutebrowser'"
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -18,20 +18,20 @@ jobs:
|
|||
timeout-minutes: 20
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v6
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.9'
|
||||
python-version: '3.8'
|
||||
- name: Recompile requirements
|
||||
run: "python3 scripts/dev/recompile_requirements.py ${{ github.event.input.environments }}"
|
||||
id: requirements
|
||||
- name: Install apt dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends libyaml-dev libegl1 libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0 asciidoc python3-venv xvfb
|
||||
sudo apt-get install --no-install-recommends libyaml-dev libegl1-mesa libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0 asciidoc python3-venv xvfb
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
|
|
@ -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@v8
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
committer: qutebrowser bot <bot@qutebrowser.org>
|
||||
author: qutebrowser bot <bot@qutebrowser.org>
|
||||
|
|
|
|||
|
|
@ -12,33 +12,30 @@ on:
|
|||
- 'patch'
|
||||
- 'minor'
|
||||
- 'major'
|
||||
- 'reupload' # reupload last release
|
||||
# FIXME do we want a possibility to do prereleases here?
|
||||
python_version:
|
||||
description: 'Python version'
|
||||
required: true
|
||||
default: '3.14'
|
||||
default: '3.12'
|
||||
type: choice
|
||||
options:
|
||||
- '3.8'
|
||||
- '3.9'
|
||||
- '3.10'
|
||||
- '3.11'
|
||||
- '3.12'
|
||||
- '3.13'
|
||||
- '3.14'
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
version: ${{ steps.bump.outputs.version }}
|
||||
version_x: ${{ steps.bump.outputs.version_x }}
|
||||
release_id: ${{ inputs.release_type == 'reupload' && steps.find-release.outputs.result || steps.create-release.outputs.id }}
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
permissions:
|
||||
contents: write # To push release commit/tag
|
||||
steps:
|
||||
- name: Find release branch
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v7
|
||||
id: find-branch
|
||||
with:
|
||||
script: |
|
||||
|
|
@ -62,9 +59,9 @@ jobs:
|
|||
console.log(`sorted: ${sorted}`);
|
||||
return sorted.at(-1);
|
||||
result-encoding: string
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
# Doesn't really matter what we prepare the release with, but let's
|
||||
# use the same version for consistency.
|
||||
|
|
@ -78,7 +75,7 @@ jobs:
|
|||
git config --global user.name "qutebrowser bot"
|
||||
git config --global user.email "bot@qutebrowser.org"
|
||||
- name: Switch to release branch
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ steps.find-branch.outputs.result }}
|
||||
- name: Import GPG Key
|
||||
|
|
@ -86,9 +83,9 @@ jobs:
|
|||
gpg --import <<< "${{ secrets.QUTEBROWSER_BOT_GPGKEY }}"
|
||||
- name: Bump version
|
||||
id: bump
|
||||
run: "tox -e update-version -- ${{ inputs.release_type }}"
|
||||
run: "tox -e update-version -- ${{ github.event.inputs.release_type }}"
|
||||
- name: Check milestone
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const milestones = await github.paginate(github.rest.issues.listMilestones, {
|
||||
|
|
@ -103,74 +100,49 @@ jobs:
|
|||
core.setFailed(`Found open milestone ${milestone.title} with ${milestone.open_issues} open and ${milestone.closed_issues} closed issues!`);
|
||||
}
|
||||
- name: Push release commit/tag
|
||||
if: ${{ inputs.release_type != 'reupload' }}
|
||||
run: |
|
||||
git push origin ${{ steps.find-branch.outputs.result }}
|
||||
git push origin v${{ steps.bump.outputs.version }}
|
||||
- name: Cherry-pick release commit
|
||||
if: ${{ inputs.release_type == 'patch' }}
|
||||
if: ${{ github.event.inputs.release_type == 'patch' }}
|
||||
run: |
|
||||
git fetch origin main
|
||||
git checkout main
|
||||
git cherry-pick -x v${{ steps.bump.outputs.version }}
|
||||
git push origin main
|
||||
git checkout v${{ steps.bump.outputs.version_x }}
|
||||
- name: Create release branch
|
||||
if: ${{ inputs.release_type == 'minor' || inputs.release_type == 'major' }}
|
||||
if: ${{ github.event.inputs.release_type != 'patch' }}
|
||||
run: |
|
||||
git checkout -b v${{ steps.bump.outputs.version_x }}
|
||||
git push --set-upstream origin v${{ steps.bump.outputs.version_x }}
|
||||
- name: Create GitHub draft release
|
||||
if: ${{ inputs.release_type != 'reupload' }}
|
||||
id: create-release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{ steps.bump.outputs.version }}
|
||||
draft: true
|
||||
body: "*Release artifacts for this release are currently being uploaded...*"
|
||||
- name: Find GitHub draft release
|
||||
if: ${{ inputs.release_type == 'reupload' }}
|
||||
id: find-release
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
const releases = await github.paginate(github.rest.repos.listReleases, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
const names = releases.map(release => release.name);
|
||||
console.log(`releases: ${names}`);
|
||||
|
||||
const release = releases.find(release => release.tag_name === "v${{ steps.bump.outputs.version }}");
|
||||
if (release === undefined) {
|
||||
core.setFailed(`No release found with tag v${{ steps.bump.outputs.version }}!`);
|
||||
}
|
||||
if (!release.draft) {
|
||||
core.setFailed(`Release ${release.tag_name} is not a draft release!`);
|
||||
}
|
||||
return release.id;
|
||||
result-encoding: string
|
||||
release:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-14-large # Intel
|
||||
- os: macos-14 # Apple Silicon
|
||||
- os: windows-2022
|
||||
- os: ubuntu-24.04
|
||||
- os: macos-11
|
||||
- os: macos-14
|
||||
- os: windows-2019
|
||||
- os: ubuntu-20.04
|
||||
runs-on: "${{ matrix.os }}"
|
||||
timeout-minutes: 45
|
||||
needs: [prepare]
|
||||
permissions:
|
||||
contents: write # To upload release artifacts
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: v${{ inputs.release_type == 'reupload' && needs.prepare.outputs.version_x || needs.prepare.outputs.version }}
|
||||
ref: v${{ needs.prepare.outputs.version }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ inputs.python_version }}
|
||||
python-version: ${{ github.event.inputs.python_version }}
|
||||
- name: Import GPG Key
|
||||
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
|
||||
run: |
|
||||
|
|
@ -187,7 +159,7 @@ jobs:
|
|||
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends libegl1 libxml2-utils docbook-xml xsltproc docbook-xsl
|
||||
sudo apt-get install --no-install-recommends libegl1-mesa libxml2-utils docbook-xml xsltproc docbook-xsl
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
|
|
@ -195,20 +167,20 @@ jobs:
|
|||
# FIXME consider switching to trusted publishers:
|
||||
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/
|
||||
- name: Build and upload release
|
||||
run: "tox -e build-release -- --upload --no-confirm ${{ inputs.release_type == 'reupload' && '--reupload' || '' }}"
|
||||
run: "tox -e build-release -- --upload --no-confirm"
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.QUTEBROWSER_BOT_PYPI_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
finalize:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 5
|
||||
needs: [prepare, release]
|
||||
permissions:
|
||||
contents: write # To change release
|
||||
steps:
|
||||
- name: Publish final release
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.repos.updateRelease({
|
||||
|
|
@ -221,7 +193,7 @@ jobs:
|
|||
irc:
|
||||
timeout-minutes: 2
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [prepare, release, finalize]
|
||||
if: "${{ always() }}"
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[mypy]
|
||||
python_version = 3.9
|
||||
python_version = 3.8
|
||||
|
||||
### --strict
|
||||
warn_unused_configs = True
|
||||
|
|
@ -20,7 +20,6 @@ strict_equality = True
|
|||
warn_unreachable = True
|
||||
disallow_any_unimported = True
|
||||
enable_error_code = ignore-without-code
|
||||
strict_bytes = True
|
||||
|
||||
### Output
|
||||
show_error_context = True
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ load-plugins=qute_pylint.config,
|
|||
pylint.extensions.dunder
|
||||
|
||||
persistent=n
|
||||
py-version=3.9
|
||||
py-version=3.8
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
enable=all
|
||||
|
|
@ -71,8 +71,7 @@ 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
|
||||
max-positional-arguments=7
|
||||
class-const-naming-style = snake_case
|
||||
|
||||
[FORMAT]
|
||||
# FIXME:v4 (lint) down to 88 again once we use black
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ image:doc/img/hints.png["screenshot 4",width=300,link="doc/img/hints.png"]
|
|||
Downloads
|
||||
---------
|
||||
|
||||
See the https://github.com/qutebrowser/qutebrowser/releases[GitHub releases
|
||||
See the https://github.com/qutebrowser/qutebrowser/releases[github releases
|
||||
page] for available downloads and the link:doc/install.asciidoc[INSTALL] file for
|
||||
detailed instructions on how to get qutebrowser running on various platforms.
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ Requirements
|
|||
|
||||
The following software and libraries are required to run qutebrowser:
|
||||
|
||||
* https://www.python.org/[Python] 3.9 or newer
|
||||
* https://www.python.org/[Python] 3.8 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,6 +105,10 @@ 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]
|
||||
|
|
@ -248,9 +252,9 @@ main inspiration for qutebrowser)
|
|||
https://github.com/akhodakivskiy/VimFx[VimFx] (seems to offer a
|
||||
https://gir.st/blog/legacyfox.htm[hack] to run on modern Firefox releases),
|
||||
https://github.com/shinglyu/QuantumVim[QuantumVim],
|
||||
https://github.com/ueokande/vim-vixen[Vim Vixen],
|
||||
https://github.com/ueokande/vim-vixen[Vim Vixen] (ESR only),
|
||||
https://github.com/amedama41/vvimpulation[VVimpulation],
|
||||
https://krabby.netlify.app/[Krabby]
|
||||
https://krabby.netlify.com/[Krabby]
|
||||
* Chrome/Chromium addons:
|
||||
https://github.com/k2nr/ViChrome/[ViChrome],
|
||||
https://github.com/jinzhu/vrome[Vrome],
|
||||
|
|
|
|||
|
|
@ -15,322 +15,15 @@ breaking changes (such as renamed commands) can happen in minor releases.
|
|||
// `Fixed` for any bug fixes.
|
||||
// `Security` to invite users to upgrade in case of vulnerabilities.
|
||||
|
||||
[[v3.6.4]]
|
||||
v3.6.4 (unreleased)
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- datalist dropdowns not opening correctly on Wayland/Sway (#8831).
|
||||
This was caused by an old workaround for a different QtWebEngine issue,
|
||||
which is now disabled for QtWebEngine 6.6.3 and newer.
|
||||
|
||||
[[v3.6.3]]
|
||||
v3.6.3 (2025-11-30)
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- New `qt.workarounds.disable_accessibility` setting, which disables Chromium
|
||||
accessibility support. By default, is it set to `auto`, which only disables
|
||||
accessibility on Qt versions with known issues. This works around a bug in Qt
|
||||
6.10.1 causing frequent segfaults (#8797).
|
||||
|
||||
[[v3.6.2]]
|
||||
v3.6.2 (2025-11-27)
|
||||
-------------------
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
* Windows and macOS releases now ship with Qt 6.10.1, which include
|
||||
security patches up to Chromium 142.0.7444.162.
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- The version info now includes the Wayland compositor name if wayland-client is
|
||||
available under a different name than `libwayland-client.so` (#8771).
|
||||
- The list of Chromium extensions in `--version` / `:version` now uses the
|
||||
correct Chromium data profile, also fixing a crash with Qt 6.10.1 (#8785).
|
||||
- With Qt 6.10.1, `qt.workarounds.disable_hangouts_extension` now doesn't apply
|
||||
on private profiles, avoiding a Qt bug leading to a crash (#8785).
|
||||
|
||||
[[v3.6.1]]
|
||||
v3.6.1 (2025-11-03)
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- A regression in v3.6.0 where the page didn't have keyboard focus after closing
|
||||
the completion, so e.g. typing in an input field after hinting didn't work.
|
||||
(#8750)
|
||||
|
||||
[[v3.6.0]]
|
||||
v3.6.0 (2025-10-24)
|
||||
-------------------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- The `:version` info now shows additional information:
|
||||
* The X11 window manager / Wayland compositor name (mostly useful for
|
||||
bug/crash reports).
|
||||
* Loaded WebExtensions (partial support landed in QtWebEngine 6.10, no
|
||||
official qutebrowser support yet).
|
||||
- Support for hinting elements which are part of an (open) shadow DOM.
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- The `qutedmenu` userscript now sorts history by the last access time.
|
||||
- Hardware accelerated 2D canvas is now enabled by default on Qt 6.8.2+,
|
||||
as graphic glitches with e.g. PDF.js and Google Sheets should be fixed
|
||||
nowadays. If you still run into issues, please report them and set
|
||||
`qt.workarounds.disable_accelerated_2d_canvas` to `always` to disable it
|
||||
again.
|
||||
- Changes to binary releases:
|
||||
* Windows and macOS releases are now built with Qt 6.10.0, which is based
|
||||
on Chromium 134.0.6998.208 with security patches up to 140.0.7339.207.
|
||||
* Windows and macOS releases are now built with Python 3.14.
|
||||
* Windows releases are now built on Windows Server 2022 (previously 2019),
|
||||
which might break compatibility with older Windows releases (untested).
|
||||
* If using `mkvenv.py` on Linux, note that Qt now requires glibc v2.34 (v2.28
|
||||
previously). This is available down to Ubuntu 22.04 LTS and Debian Bookworm
|
||||
(oldstable), so this should not affect most users of desktop distributions.
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- Fixed crash if two new downloads start while a download prompt is already open
|
||||
(#8674).
|
||||
- Fixed exception when closing a qutebrowser window while a download prompt is
|
||||
still open.
|
||||
- Hopefully proper fix for some web pages jumping to the top when the statusbar
|
||||
is hidden (#8223).
|
||||
- Fix for the page header being shown on YouTube after the fullscreen
|
||||
notification was hidden (#8625).
|
||||
- Fix for videos losing keyboard focus when the fullscreen notification shows
|
||||
(#8174).
|
||||
- The workaround for microphone/camera permissions not being requested with
|
||||
QtWebEngine 6.9 on Google Meet, Zoom, or other pages using the new
|
||||
`<permission>` element now got extended to Qt 6.9.1+ as it's still not fixed
|
||||
upstream. (#8612)
|
||||
- The package version for Jinja 3.3+ is now correctly displayed in `:version`.
|
||||
- Fixed crash with Qt 6.10 (and possibly older Qt versions) when navigating
|
||||
from a `qute://` page to a web page, e.g. when searching on `qute://start`.
|
||||
- On Wayland with Qt <= 6.9, `EGL_PLATFORM=wayland` is now set by qutebrowser to
|
||||
get hardware rendering. Qt 6.10 includes an equivalent fix (#8637).
|
||||
- Added workaround for per-domain User-Agent header not being used on redirects
|
||||
(#8679).
|
||||
- Added site-specific quirk for gitlab.gnome.org agressively blocking old
|
||||
Chromium versions (and thus QtWebEngine) (#8509).
|
||||
- Using `:config-list-remove` with an invalid value for the respective option
|
||||
type now corrently displays an error instead of crashing.
|
||||
|
||||
[[v3.5.1]]
|
||||
v3.5.1 (2025-06-05)
|
||||
-------------------
|
||||
|
||||
Deprecated
|
||||
~~~~~~~~~~
|
||||
|
||||
- QtWebKit (legacy) support got removed from CI and is now untested. If it
|
||||
breaks, it's not going to be fixed, and support will be removed over the next
|
||||
releases.
|
||||
- Qt 5 support is currently still tested, but is also planned to get removed
|
||||
over the next releases. Same goes for support for older Qt 6 versions (likely
|
||||
6.2/6.3/6.4 and perhaps 6.5, see https://github.com/qutebrowser/qutebrowser/issues/8464[#8464]).
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- Windows/macOS releases now bundle Qt 6.9.1, including many graphics-related
|
||||
bugfixes, as well as security patches up to Chromium 136.0.7103.114.
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- A bogus "wildcard call disconnects from destroyed signal" warning from Qt is
|
||||
now suppressed.
|
||||
- PDF.js now loads correctly on Windows installations with broken mimetype
|
||||
configurations.
|
||||
- A "Ignoring new child ..." debug log message which got spammy with Qt 6.9 is
|
||||
now removed.
|
||||
- A unknown crash (possibly related to using devtools) due to weird (Py)Qt
|
||||
behavior now has a workaround.
|
||||
- No "QtWebEngine version mismatch" warning is now logged anymore with newer Qt
|
||||
5.15 releases (but you should still stop using Qt 5).
|
||||
- The PDF.js version can now correctly be extracted/displayed with newer PDF.js
|
||||
versions.
|
||||
- The `qute-bitwarden`, `-lastpass` and `-pass` userscripts now properly avoid
|
||||
a `DeprecationWarning` from the upcoming 6.0 release of `tldextract`. The
|
||||
previous fix in v3.5.1 was insufficient.
|
||||
|
||||
[[v3.5.0]]
|
||||
v3.5.0 (2025-04-12)
|
||||
-------------------
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- Windows/macOS releases are now built with Qt 6.9.0
|
||||
* Based on Chromium 130.0.6723.192
|
||||
* Security fixes up to Chromium 133.0.6943.141
|
||||
* Also fixes issues with opening links on macOS
|
||||
- The `content.headers.user_agent` setting now has a new
|
||||
`{upstream_browser_version_short}` template field, which is the
|
||||
upstream/Chromium version but shortened to only major version.
|
||||
- The default user agent now uses the shortened Chromium version and doesn't
|
||||
expose the `QtWebEngine/...` part anymore, thus making it equal to the
|
||||
corresponding Chromium user agent. This increases compatibilty due to various
|
||||
overzealous "security" products used by a variety of websites that block
|
||||
QtWebEngine, presumably as a bot (known issues existed with Whatsapp Web, UPS,
|
||||
Digitec Galaxus).
|
||||
- Changed features in userscripts:
|
||||
* `qute-bitwarden` now passes your password to the subprocess in an
|
||||
environment variable when unlocking your vault, instead of as a command
|
||||
line argument. (#7781)
|
||||
- New `-D no-system-pdfjs` debug flag to ignore system-wide PDF.js installations
|
||||
for testing.
|
||||
- Polyfill for missing `URL.parse` with PDF.js v5 and QtWebEngine < 6.9. Note
|
||||
this is a "best effort" fix and you should be using the "older browsers"
|
||||
("legacy") build of PDF.js instead.
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- The `ua-slack` site-specific quirk, as things seem to work better nowadays
|
||||
without a quirk needed.
|
||||
- The `ua-whatsapp` site-specific quirk, as it's unneeded with the default UA
|
||||
change described above.
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- Crash when trying to use the `DocumentPictureInPicture` JS API, such as done
|
||||
by the new Google Workspaces Huddle feature. The API is unsupported by
|
||||
QtWebEngine and now correctly disabled on the JS side. (#8449)
|
||||
- Crash when a buggy notification presenter returns a duplicate ID (now an
|
||||
error is shown instead).
|
||||
- Crashes when running `:tab-move` or `:yank title` at startup, before a tab is
|
||||
available.
|
||||
- Crash with `input.insert_mode.auto_load`, when closing a new tab quickly after
|
||||
opening it, but before it was fully loaded. (#3895, #8400)
|
||||
- Workaround for microphone/camera permissions not being requested with
|
||||
QtWebEngine 6.9.0 on Google Meet, Zoom, or other pages using the new
|
||||
`<permission>` element. (#8539)
|
||||
- Resolved issues in userscripts:
|
||||
* `qute-bitwarden` will now prompt a re-login if its cached session has
|
||||
been invalidated since last used. (#8456)
|
||||
* `qute-bitwarden`, `-lastpass` and `-pass` now avoid a
|
||||
`DeprecationWarning` from the upcoming 6.0 release of `tldextract`
|
||||
|
||||
[[v3.4.0]]
|
||||
v3.4.0 (2024-12-14)
|
||||
-------------------
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- Support for Python 3.8 is dropped, and Python 3.9 is now required. (#8325)
|
||||
- Support for macOS 12 Monterey is now dropped, and binaries will be built on
|
||||
macOS 13 Ventura. (#8327)
|
||||
- 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). (#8336)
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- Windows/macOS binaries are now built with Qt 6.8.1. (#8242)
|
||||
- Based on Chromium 122.0.6261.171
|
||||
- With security patches up to 131.0.6778.70
|
||||
- Windows/macOS binaries are now using Python 3.13. (#8205)
|
||||
- The `.desktop` file now also declares qutebrowser as a valid viewer for
|
||||
`image/webp`. (#8340)
|
||||
- Updated mimetype information for getting a suitable extension when downloading
|
||||
a `data:` URL.
|
||||
- The `content.javascript.clipboard` setting now defaults to "ask", which on
|
||||
Qt 6.8+ will prompt the user to grant clipboard access. On older Qt versions,
|
||||
this is still equivalent to `"none"` and needs to be set manually. (#8348)
|
||||
- If a XHR request made via JS sets a custom `Accept-Language` header, it now
|
||||
correctly has precedence over the global `content.headers.accept_language`
|
||||
setting (but not per-domain overrides). This fixes subtle JS issues on
|
||||
websites that rely on the custom header being sent for those requests, and
|
||||
e.g. block the requests server-side otherwise. (#8370)
|
||||
- Our packaging scripts now prefer the "legacy"/"for older browsers" PDF.js
|
||||
build as their normal release only supports the latest Chromium version and
|
||||
might break in qutebrowser on updates. **Note to packagers:** If there's a
|
||||
PDF.js package in your distribution as an (optional) qutebrowser dependency,
|
||||
consider also switching to this variant (same code, built differently).
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- Crash with recent Jinja/Markupsafe versions when viewing a finished userscript
|
||||
(or potentially editor) process via `:process`.
|
||||
- `scripts/open_url_in_instance.sh` now avoids `echo -n`, thus running
|
||||
correctly on POSIX sh. (#8409)
|
||||
- Added a workaround for a bogus QtWebEngine warning about missing spell
|
||||
checking dictionaries. (#8330)
|
||||
|
||||
|
||||
[[v3.3.1]]
|
||||
v3.3.1 (2024-10-12)
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- Updated the workaround for Google sign-in issues.
|
||||
|
||||
[[v3.3.0]]
|
||||
v3.3.0 (2024-10-12)
|
||||
v3.3.0 (2024-06-25)
|
||||
-------------------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- Added the `qt.workarounds.disable_hangouts_extension` setting,
|
||||
for disabling the Google Hangouts extension built into Chromium/QtWebEngine.
|
||||
- Failed end2end tests will now save screenshots of the browser window when
|
||||
run under xvfb (the default on linux). Screenshots will be under
|
||||
`$TEMP/pytest-current/pytest-screenshots/` or attached to the GitHub actions
|
||||
run as an artifact. (#7625)
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- Support for macOS 11 Big Sur is dropped. Binaries are now built on macOS 12
|
||||
Monterey and are unlikely to still run on older macOS versions.
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- The qute-pass userscript now has better support for internationalized domain
|
||||
names when using the pass backend - both domain names and secret paths are
|
||||
normalized before comparing (#8133)
|
||||
- Ignored URL query parameters (via `url.yank_ignored_parameters`) are now
|
||||
respected when yanking any URL (for example, through hints with `hint links
|
||||
yank`). The `{url:yank}` substitution has also been added as a version of
|
||||
`{url}` that respects ignored URL query parameters. (#7879)
|
||||
- Windows and macOS releases now bundle Qt 6.7.3, which includes security fixes
|
||||
up to Chromium 129.0.6668.58.
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- A minor memory leak of QItemSelectionModels triggered by closing the
|
||||
completion dialog has been resolved. (#7950)
|
||||
- The link to the chrome https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns/[URL match pattern]
|
||||
documentation in our settings docs now loads a live page again. (#8268)
|
||||
- A rare crash when on Qt 6, a renderer process terminates with an unknown
|
||||
termination reason.
|
||||
- Updated the workaround for Google sign-in issues.
|
||||
- There is now a separate macOS release built for Apple Silicon. A Universal
|
||||
Binary might follow with a later release.
|
||||
|
||||
[[v3.2.1]]
|
||||
v3.2.1 (2024-06-25)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ If you want to find something useful to do, check the
|
|||
https://github.com/qutebrowser/qutebrowser/issues[issue tracker]. Some
|
||||
pointers:
|
||||
|
||||
* https://github.com/qutebrowser/qutebrowser/contribute[Issues which should
|
||||
* https://github.com/qutebrowser/qutebrowser/labels/easy[Issues which should
|
||||
be easy to solve]
|
||||
* https://github.com/qutebrowser/qutebrowser/labels/component%3A%20docs[Documentation issues which require little/no coding]
|
||||
|
||||
|
|
@ -111,9 +111,9 @@ unittests and several linters/checkers.
|
|||
Currently, the following tox environments are available:
|
||||
|
||||
* Tests using https://www.pytest.org[pytest]:
|
||||
- `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).
|
||||
- `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).
|
||||
* `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.
|
||||
|
|
@ -121,6 +121,8 @@ Currently, the following tox environments are available:
|
|||
* `pyroma`: Check packaging practices with
|
||||
https://pypi.python.org/pypi/pyroma/[pyroma].
|
||||
* `eslint`: Run https://eslint.org/[ESLint] javascript checker.
|
||||
* `check-manifest`: Check MANIFEST.in completeness with
|
||||
https://github.com/mgedmin/check-manifest[check-manifest].
|
||||
* `mkvenv`: Bootstrap a virtualenv for testing.
|
||||
* `misc`: Run `scripts/misc_checks.py` to check for:
|
||||
- untracked git files
|
||||
|
|
@ -169,16 +171,16 @@ Examples:
|
|||
|
||||
----
|
||||
# run only pytest tests which failed in last run:
|
||||
tox -e py39 -- --lf
|
||||
tox -e py38 -- --lf
|
||||
|
||||
# run only the end2end feature tests:
|
||||
tox -e py39 -- tests/end2end/features
|
||||
tox -e py38 -- tests/end2end/features
|
||||
|
||||
# run everything with undo in the generated name, based on the scenario text
|
||||
tox -e py39 -- tests/end2end/features/test_tabs_bdd.py -k undo
|
||||
tox -e py38 -- tests/end2end/features/test_tabs_bdd.py -k undo
|
||||
|
||||
# run coverage test for specific file (updates htmlcov/index.html)
|
||||
tox -e py39-cov -- tests/unit/browser/test_webelem.py
|
||||
tox -e py38-cov -- tests/unit/browser/test_webelem.py
|
||||
----
|
||||
|
||||
Specifying the backend for tests
|
||||
|
|
@ -190,28 +192,6 @@ specific one you can set either of a) the environment variable QUTE_TESTS_BACKEN
|
|||
, or b) the command line argument --qute-backend, to the desired backend
|
||||
(webkit/webengine).
|
||||
|
||||
If you need an environment with webkit installed to do testing while we still
|
||||
support it (see #4039) you can re-use the docker container used for the CI
|
||||
test runs which has PyQt5Webkit installed from the archlinux package archives.
|
||||
Examples:
|
||||
|
||||
----
|
||||
# Get a bash shell in the docker container with
|
||||
# a) the current directory mounted at /work in the container
|
||||
# b) the container using the X11 display :27 (for example, a Xephyr instance) from the host
|
||||
# c) the tox and hypothesis dirs set to somewhere in the container that it can write to
|
||||
# d) the system site packages available in the tox venv so you can use PyQt
|
||||
# from the OS without having to run the link_pyqt script
|
||||
docker run -it -v $PWD:/work:ro -w /work -e QUTE_TESTS_BACKEND=webkit -e DISPLAY=:27 -v /tmp/.X11-unix:/tmp/.X11-unix -e TOX_WORK_DIR="/home/user/.tox" -e HYPOTHESIS_EXAMPLES_DIR="/home/user/.hypothesis/examples" -e VIRTUALENV_SYSTEM_SITE_PACKAGES=True qutebrowser/ci:archlinux-webkit bash
|
||||
|
||||
# Start a qutebrowser temporary basedir in the appropriate tox environment to
|
||||
# play with
|
||||
tox exec -e py-qt5 -- python3 -m qutebrowser -T --backend webkit
|
||||
|
||||
# Run tests, passing positional args through to pytest.
|
||||
tox -e py-qt5 -- tests/unit
|
||||
----
|
||||
|
||||
Profiling
|
||||
~~~~~~~~~
|
||||
|
||||
|
|
@ -602,7 +582,6 @@ Info pages:
|
|||
- chrome://device-log/ (QtWebEngine >= 6.3)
|
||||
- chrome://gpu/
|
||||
- chrome://sandbox/ (Linux only)
|
||||
- chrome://qt/ (QtWebEngine >= 6.7)
|
||||
|
||||
Misc. / Debugging pages:
|
||||
|
||||
|
|
@ -613,7 +592,6 @@ Misc. / Debugging pages:
|
|||
- chrome://ukm/ (QtWebEngine >= 5.15.3)
|
||||
- chrome://user-actions/ (QtWebEngine >= 5.15.3)
|
||||
- chrome://webrtc-logs/ (QtWebEngine >= 5.15.3)
|
||||
- chrome://extensions/ (QtWebEngine >= 6.10)
|
||||
|
||||
Internals pages:
|
||||
|
||||
|
|
@ -789,12 +767,10 @@ New PyQt release
|
|||
qutebrowser release
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Make sure there are no unstaged or unpushed changes.
|
||||
* Make sure CI is reasonably green.
|
||||
* Make sure there are no unstaged changes and the tests are green.
|
||||
* Make sure all issues with the related milestone are closed.
|
||||
* Mark the https://github.com/qutebrowser/qutebrowser/milestones[milestone] as closed.
|
||||
* Consider updating the completions for `content.headers.user_agent` in `configdata.yml`
|
||||
and the Firefox UA in `qutebrowser/browser/webengine/webenginesettings.py`.
|
||||
* Consider updating the completions for `content.headers.user_agent` in `configdata.yml`.
|
||||
* Minor release: Consider updating some files from main:
|
||||
- `misc/requirements/` and `requirements.txt`
|
||||
- `scripts/`
|
||||
|
|
@ -804,8 +780,7 @@ qutebrowser release
|
|||
**Automatic release via GitHub Actions (starting with v3.0.0):**
|
||||
|
||||
* Double check Python version in `.github/workflows/release.yml`
|
||||
* Run the `release` workflow on the `main` branch, e.g. via `gh workflow run release -f release_type=minor` (`release_type` can be `major`, `minor` or `patch`; you can also override `python_version`)
|
||||
* Consider running `gh run watch` or `gh run view --web` to watch the progress
|
||||
* Run the `release` workflow on the `main` branch, e.g. via `gh workflow run release -f release_type=major` (`release_type` can be `major`, `minor` or `patch`; you can also override `python_version`)
|
||||
|
||||
**Manual release:**
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ Why Python?::
|
|||
point, I wasn't comfortable with C++ so that wasn't an alternative.
|
||||
|
||||
But isn't Python too slow for a browser?::
|
||||
https://www.infoworld.com/article/2303031/van-rossum-python-is-not-too-slow-2.html[It's generally less of a problem than one would expect.]
|
||||
https://www.infoworld.com/d/application-development/van-rossum-python-not-too-slow-188715[It's generally less of a problem than one would expect.]
|
||||
Most of the heavy lifting of qutebrowser is done by Qt and
|
||||
QtWebKit/QtWebEngine in C++, with the
|
||||
https://wiki.python.org/moin/GlobalInterpreterLock[GIL] released.
|
||||
|
|
@ -141,7 +141,7 @@ The comma prefix is used to make sure user-defined bindings don't conflict with
|
|||
the built-in ones.
|
||||
+
|
||||
Note that you might need an additional package (e.g.
|
||||
https://archlinux.org/packages/extra/any/yt-dlp/[yt-dlp] on
|
||||
https://www.archlinux.org/packages/community/any/youtube-dl/[youtube-dl] on
|
||||
Archlinux) to play web videos with mpv.
|
||||
+
|
||||
There is a very useful script for mpv, which emulates "unique application"
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ For command arguments, there are also some variables you can use:
|
|||
- `{url:host}`, `{url:domain}`, `{url:auth}`, `{url:scheme}`, `{url:username}`,
|
||||
`{url:password}`, `{url:port}`, `{url:path}` and `{url:query}`
|
||||
expand to the respective parts of the current URL
|
||||
- `{url:yank}` expands to the URL of the current page but strips all the query
|
||||
parameters in the `url.yank_ignored_parameters` setting.
|
||||
- `{title}` expands to the current page's title
|
||||
- `{clipboard}` expands to the clipboard contents
|
||||
- `{primary}` expands to the primary selection contents
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ patterns. The link:settings{outfilesuffix}[settings documentation] marks such
|
|||
settings with "This setting supports URL patterns.
|
||||
|
||||
The syntax is based on Chromium's
|
||||
https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns/[URL pattern syntax].
|
||||
https://developer.chrome.com/docs/extensions/mv3/match_patterns/[URL pattern syntax].
|
||||
As an extension, the scheme and path can be left off as a short-hand syntax, so
|
||||
`example.com` is equivalent to `*://example.com/*`.
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ customizable for a given <<patterns,URL patterns>>.
|
|||
|
||||
[source,python]
|
||||
----
|
||||
config.set('content.images', False, '*://example.com/*')
|
||||
config.set('content.images', False, '*://example.com/')
|
||||
----
|
||||
|
||||
Alternatively, you can use `with config.pattern(...) as p:` to get a shortcut
|
||||
|
|
@ -187,7 +187,7 @@ similar to `c.` which is scoped to the given domain:
|
|||
|
||||
[source,python]
|
||||
----
|
||||
with config.pattern('*://example.com/*') as p:
|
||||
with config.pattern('*://example.com/') as p:
|
||||
p.content.images = False
|
||||
----
|
||||
|
||||
|
|
@ -416,8 +416,6 @@ Pre-built colorschemes
|
|||
- https://github.com/gicrisf/qute-city-lights[City Lights (matte dark)]
|
||||
- https://github.com/catppuccin/qutebrowser[Catppuccin]
|
||||
- https://github.com/iruzo/matrix-qutebrowser[Matrix]
|
||||
- https://github.com/harmtemolder/qutebrowser-solarized[Solarized]
|
||||
- https://github.com/Rehpotsirhc-z/qutebrowser-doom-one[Doom One]
|
||||
|
||||
Avoiding flake8 errors
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -454,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/main/item/.config/qutebrowser/qutemacs.py[willvaughn]
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Getting help
|
|||
You can get help in the IRC channel
|
||||
link:ircs://irc.libera.chat:6697/#qutebrowser[`#qutebrowser`] on
|
||||
https://libera.chat/[Libera Chat]
|
||||
(https://web.libera.chat/#qutebrowser[webchat]),
|
||||
(https://web.libera.chat/#qutebrowser[webchat], https://matrix.to/#qutebrowser:libera.chat[via Matrix]),
|
||||
or by writing a message to the
|
||||
https://listi.jpberlin.de/mailman/listinfo/qutebrowser[mailinglist] at
|
||||
mailto:qutebrowser@lists.qutebrowser.org[].
|
||||
|
|
|
|||
|
|
@ -302,8 +302,6 @@
|
|||
|<<qt.force_software_rendering,qt.force_software_rendering>>|Force software rendering for QtWebEngine.
|
||||
|<<qt.highdpi,qt.highdpi>>|Turn on Qt HighDPI scaling.
|
||||
|<<qt.workarounds.disable_accelerated_2d_canvas,qt.workarounds.disable_accelerated_2d_canvas>>|Disable accelerated 2d canvas to avoid graphical glitches.
|
||||
|<<qt.workarounds.disable_accessibility,qt.workarounds.disable_accessibility>>|Disable accessibility to avoid crashes on Qt 6.10.1.
|
||||
|<<qt.workarounds.disable_hangouts_extension,qt.workarounds.disable_hangouts_extension>>|Disable the Hangouts extension.
|
||||
|<<qt.workarounds.locale,qt.workarounds.locale>>|Work around locale parsing issues in QtWebEngine 5.15.3.
|
||||
|<<qt.workarounds.remove_service_workers,qt.workarounds.remove_service_workers>>|Delete the QtWebEngine Service Worker directory on every start.
|
||||
|<<scrolling.bar,scrolling.bar>>|When/how to show the scrollbar.
|
||||
|
|
@ -357,7 +355,7 @@
|
|||
|<<url.open_base_url,url.open_base_url>>|Open base URL of the searchengine if a searchengine shortcut is invoked without parameters.
|
||||
|<<url.searchengines,url.searchengines>>|Search engines which can be used via the address bar.
|
||||
|<<url.start_pages,url.start_pages>>|Page(s) to open at the start.
|
||||
|<<url.yank_ignored_parameters,url.yank_ignored_parameters>>|URL parameters to strip when yanking a URL.
|
||||
|<<url.yank_ignored_parameters,url.yank_ignored_parameters>>|URL parameters to strip with `:yank url`.
|
||||
|<<window.hide_decoration,window.hide_decoration>>|Hide the window decoration.
|
||||
|<<window.title_format,window.title_format>>|Format to use for the window title. The same placeholders like for
|
||||
|<<window.transparent,window.transparent>>|Set the main window background to transparent.
|
||||
|
|
@ -741,12 +739,12 @@ Default:
|
|||
* +pass:[xO]+: +pass:[cmd-set-text :open -b -r {url:pretty}]+
|
||||
* +pass:[xo]+: +pass:[cmd-set-text -s :open -b]+
|
||||
* +pass:[yD]+: +pass:[yank domain -s]+
|
||||
* +pass:[yM]+: +pass:[yank inline [{title}\]({url:yank}) -s]+
|
||||
* +pass:[yM]+: +pass:[yank inline [{title}\]({url}) -s]+
|
||||
* +pass:[yP]+: +pass:[yank pretty-url -s]+
|
||||
* +pass:[yT]+: +pass:[yank title -s]+
|
||||
* +pass:[yY]+: +pass:[yank -s]+
|
||||
* +pass:[yd]+: +pass:[yank domain]+
|
||||
* +pass:[ym]+: +pass:[yank inline [{title}\]({url:yank})]+
|
||||
* +pass:[ym]+: +pass:[yank inline [{title}\]({url})]+
|
||||
* +pass:[yp]+: +pass:[yank pretty-url]+
|
||||
* +pass:[yt]+: +pass:[yank title]+
|
||||
* +pass:[yy]+: +pass:[yank]+
|
||||
|
|
@ -2276,22 +2274,21 @@ The following placeholders are defined:
|
|||
* `{upstream_browser_key}`: "Version" for QtWebKit, "Chrome" for
|
||||
QtWebEngine.
|
||||
* `{upstream_browser_version}`: The corresponding Safari/Chrome version.
|
||||
* `{upstream_browser_version_short}`: The corresponding Safari/Chrome
|
||||
version, but only with its major version.
|
||||
* `{qutebrowser_version}`: The currently running qutebrowser version.
|
||||
|
||||
The default value is equal to the default user agent of
|
||||
QtWebKit/QtWebEngine, but with the `QtWebEngine/...` part removed for
|
||||
increased compatibility.
|
||||
The default value is equal to the unchanged user agent of
|
||||
QtWebKit/QtWebEngine.
|
||||
|
||||
Note that the value read from JavaScript is always the global value.
|
||||
Note that the value read from JavaScript is always the global value. With
|
||||
QtWebEngine between 5.12 and 5.14 (inclusive), changing the value exposed
|
||||
to JavaScript requires a restart.
|
||||
|
||||
|
||||
This setting supports link:configuring{outfilesuffix}#patterns[URL patterns].
|
||||
|
||||
Type: <<types,FormatString>>
|
||||
|
||||
Default: +pass:[Mozilla/5.0 ({os_info}) AppleWebKit/{webkit_version} (KHTML, like Gecko) {upstream_browser_key}/{upstream_browser_version_short} Safari/{webkit_version}]+
|
||||
Default: +pass:[Mozilla/5.0 ({os_info}) AppleWebKit/{webkit_version} (KHTML, like Gecko) {qt_key}/{qt_version} {upstream_browser_key}/{upstream_browser_version} Safari/{webkit_version}]+
|
||||
|
||||
[[content.hyperlink_auditing]]
|
||||
=== content.hyperlink_auditing
|
||||
|
|
@ -2347,20 +2344,18 @@ Default: +pass:[false]+
|
|||
=== content.javascript.clipboard
|
||||
Allow JavaScript to read from or write to the clipboard.
|
||||
With QtWebEngine, writing the clipboard as response to a user interaction is always allowed.
|
||||
On Qt < 6.8, the `ask` setting is equivalent to `none` and permission needs to be granted manually via this setting.
|
||||
|
||||
This setting supports link:configuring{outfilesuffix}#patterns[URL patterns].
|
||||
|
||||
Type: <<types,JSClipboardPermission>>
|
||||
Type: <<types,String>>
|
||||
|
||||
Valid values:
|
||||
|
||||
* +none+: Disable access to clipboard.
|
||||
* +access+: Allow reading from and writing to the clipboard.
|
||||
* +access-paste+: Allow accessing the clipboard and pasting clipboard content.
|
||||
* +ask+: Prompt when requested (grants 'access-paste' permission).
|
||||
|
||||
Default: +pass:[ask]+
|
||||
Default: +pass:[none]+
|
||||
|
||||
[[content.javascript.enabled]]
|
||||
=== content.javascript.enabled
|
||||
|
|
@ -2769,9 +2764,10 @@ Type: <<types,FlagList>>
|
|||
|
||||
Valid values:
|
||||
|
||||
* +ua-whatsapp+
|
||||
* +ua-google+
|
||||
* +ua-slack+
|
||||
* +ua-googledocs+
|
||||
* +ua-gnome-gitlab+
|
||||
* +js-whatsapp-web+
|
||||
* +js-discord+
|
||||
* +js-string-replaceall+
|
||||
|
|
@ -3894,7 +3890,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/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)]
|
||||
- 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)]
|
||||
|
||||
This setting requires a restart.
|
||||
|
||||
|
|
@ -3992,44 +3988,11 @@ Type: <<types,String>>
|
|||
Valid values:
|
||||
|
||||
* +always+: Disable accelerated 2d canvas
|
||||
* +auto+: Disable on Qt versions with known issues, enable otherwise
|
||||
* +auto+: Disable on Qt6 < 6.6.0, enable otherwise
|
||||
* +never+: Enable accelerated 2d canvas
|
||||
|
||||
Default: +pass:[auto]+
|
||||
|
||||
[[qt.workarounds.disable_accessibility]]
|
||||
=== qt.workarounds.disable_accessibility
|
||||
Disable accessibility to avoid crashes on Qt 6.10.1.
|
||||
|
||||
This setting requires a restart.
|
||||
|
||||
This setting is only available with the QtWebEngine backend.
|
||||
|
||||
Type: <<types,String>>
|
||||
|
||||
Valid values:
|
||||
|
||||
* +always+: Disable renderer accessibility
|
||||
* +auto+: Disable on Qt versions with known issues, enable otherwise
|
||||
* +never+: Enable renderer accessibility
|
||||
|
||||
Default: +pass:[auto]+
|
||||
|
||||
[[qt.workarounds.disable_hangouts_extension]]
|
||||
=== qt.workarounds.disable_hangouts_extension
|
||||
Disable the Hangouts extension.
|
||||
The Hangouts extension provides additional APIs for Google domains only.
|
||||
Hangouts has been replaced with Meet, which appears to work without this extension.
|
||||
Note this setting gets ignored and the Hangouts extension is always disabled to avoid crashes on Qt 6.5.0 to 6.5.3 if dark mode is enabled, as well as on Qt 6.6.0.
|
||||
|
||||
This setting requires a restart.
|
||||
|
||||
This setting is only available with the QtWebEngine backend.
|
||||
|
||||
Type: <<types,Bool>>
|
||||
|
||||
Default: +pass:[false]+
|
||||
|
||||
[[qt.workarounds.locale]]
|
||||
=== qt.workarounds.locale
|
||||
Work around locale parsing issues in QtWebEngine 5.15.3.
|
||||
|
|
@ -4730,7 +4693,7 @@ Default: +pass:[https://start.duckduckgo.com]+
|
|||
|
||||
[[url.yank_ignored_parameters]]
|
||||
=== url.yank_ignored_parameters
|
||||
URL parameters to strip when yanking a URL.
|
||||
URL parameters to strip with `:yank url`.
|
||||
|
||||
Type: <<types,List of String>>
|
||||
|
||||
|
|
@ -4865,7 +4828,6 @@ Lists with duplicate flags are invalid. Each item is checked against the valid v
|
|||
|FuzzyUrl|A URL which gets interpreted as search if needed.
|
||||
|IgnoreCase|Whether to search case insensitively.
|
||||
|Int|Base class for an integer setting.
|
||||
|JSClipboardPermission|Permission for page JS to access the system clipboard.
|
||||
|Key|A name of a key.
|
||||
|List|A list of values.
|
||||
|
||||
|
|
@ -4904,6 +4866,6 @@ See the setting's valid values for more information on allowed values.
|
|||
|Url|A URL as a string.
|
||||
|UrlPattern|A match pattern for a URL.
|
||||
|
||||
See https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns for the allowed syntax.
|
||||
See https://developer.chrome.com/apps/match_patterns for the allowed syntax.
|
||||
|VerticalPosition|The position of the download bar.
|
||||
|==============
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ by Debian's security support.
|
|||
It's recommended to <<tox,install qutebrowser in a virtualenv>> with a newer PyQt/Qt binary instead.
|
||||
If you need proprietary codec support or use an architecture not supported by Qt
|
||||
binaries, starting with Ubuntu 22.04 and Debian Bookworm, it's possible to
|
||||
install Qt 6 via apt. By using `scripts/mkvenv.py` with `--pyqt-type link` you get a
|
||||
install Qt 6 via apt. By using `mkvenv.py` with `--pyqt-type link` you get a
|
||||
newer qutebrowser running with:
|
||||
|
||||
- Ubuntu 22.04, Linux Mint 21: QtWebEngine 6.2.4 (based on Chromium 90 from mid-2021)
|
||||
|
|
@ -54,7 +54,7 @@ newer qutebrowser running with:
|
|||
Note you'll need some basic libraries to use the virtualenv-installed PyQt:
|
||||
|
||||
----
|
||||
# apt install --no-install-recommends git ca-certificates python3 python3-venv libgl1 libxkbcommon-x11-0 libegl1 libfontconfig1 libglib2.0-0 libdbus-1-3 libxcb-cursor0 libxcb-icccm4 libxcb-keysyms1 libxcb-shape0 libnss3 libxcomposite1 libxdamage1 libxrender1 libxrandr2 libxtst6 libxi6 libasound2
|
||||
# apt install --no-install-recommends git ca-certificates python3 python3-venv libgl1 libxkbcommon-x11-0 libegl1-mesa libfontconfig1 libglib2.0-0 libdbus-1-3 libxcb-cursor0 libxcb-icccm4 libxcb-keysyms1 libxcb-shape0 libnss3 libxcomposite1 libxdamage1 libxrender1 libxrandr2 libxtst6 libxi6 libasound2
|
||||
----
|
||||
|
||||
Additional hints
|
||||
|
|
@ -64,9 +64,9 @@ Additional hints
|
|||
However, Qt 6.5 https://www.qt.io/blog/moving-to-openssl-3-in-binary-builds-starting-from-qt-6.5-beta-2[moved to OpenSSL 3]
|
||||
for its binary builds. Thus, you will either need to live with
|
||||
`:adblock-update` and `:download` being broken, or use `--pyqt-version 6.4` for
|
||||
the `scripts/mkvenv.py` script to get an older Qt.
|
||||
the `mkvenv.py` script to get an older Qt.
|
||||
- If running from git, run the following to generate the documentation for the
|
||||
`:help` command (the `scripts/mkvenv.py` script used with a virtualenv install already does
|
||||
`:help` command (the `mkvenv.py` script used with a virtualenv install already does
|
||||
this for you):
|
||||
+
|
||||
----
|
||||
|
|
@ -103,18 +103,12 @@ To be able to play videos with proprietary codecs with QtWebEngine, you will
|
|||
need to install an additional package from the RPM Fusion Free repository.
|
||||
For more information see https://rpmfusion.org/Configuration.
|
||||
|
||||
With Qt 6 (recommended):
|
||||
|
||||
-----
|
||||
# dnf install libavcodec-freeworld
|
||||
-----
|
||||
|
||||
With Qt 5:
|
||||
|
||||
-----
|
||||
# dnf install qt5-qtwebengine-freeworld
|
||||
-----
|
||||
|
||||
It's currently unknown what the Qt 6 equivalent of this is.
|
||||
|
||||
On Archlinux
|
||||
------------
|
||||
|
||||
|
|
@ -168,13 +162,6 @@ need to turn off the `bindist` flag for `dev-qt/qtwebengine`.
|
|||
See the https://wiki.gentoo.org/wiki/Qutebrowser#USE_flags[Gentoo Wiki] for
|
||||
more information.
|
||||
|
||||
To be able to use Kerberos authentication, you will need to turn on the
|
||||
`kerberos` USE-flag system-wide and re-emerge `dev-qt/qtwebengine` after that.
|
||||
|
||||
See the
|
||||
https://wiki.gentoo.org/wiki/Qutebrowser#Kerberos_authentication_does_not_work[
|
||||
Troubleshooting section in Gentoo Wiki] for more information.
|
||||
|
||||
On Void Linux
|
||||
-------------
|
||||
|
||||
|
|
@ -411,7 +398,7 @@ location for a particular application, rather than being installed globally.
|
|||
The `scripts/mkvenv.py` script in this repository can be used to create a
|
||||
virtualenv for qutebrowser and install it (including all dependencies) there.
|
||||
The next couple of sections will explain the most common use-cases - run
|
||||
`scripts/mkvenv.py` with `--help` to see all available options.
|
||||
`mkvenv.py` with `--help` to see all available options.
|
||||
|
||||
Getting the repository
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -444,7 +431,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.9 or newer, otherwise you'll get a "No
|
||||
- Make sure your `python3` is Python 3.8 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.
|
||||
|
|
@ -455,8 +442,8 @@ See the next section for an alternative install method which might help with
|
|||
those issues but result in an older Qt version.
|
||||
|
||||
You can specify a Qt/PyQt version with the `--pyqt-version` flag, see
|
||||
`scripts/mkvenv.py --help` for a list of available versions. By default, the
|
||||
latest version which plays well with qutebrowser is used.
|
||||
`mkvenv.py --help` for a list of available versions. By default, the latest
|
||||
version which plays well with qutebrowser is used.
|
||||
|
||||
NOTE: If the Qt smoke test fails with a _"This application failed to start
|
||||
because no Qt platform plugin could be initialized."_ message, most likely a
|
||||
|
|
@ -466,24 +453,22 @@ failed on ..._ line for details.
|
|||
Installing dependencies (system-wide Qt)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Alternatively, you can use `scripts/mkvenv.py --pyqt-type link` to symlink
|
||||
your local PyQt/Qt install instead of installing PyQt in the virtualenv.
|
||||
However, unless you have a new QtWebKit or QtWebEngine available, qutebrowser
|
||||
will not work. It also typically means you'll be using an older release of
|
||||
QtWebEngine.
|
||||
Alternatively, you can use `mkvenv.py --pyqt-type link` to symlink your local
|
||||
PyQt/Qt install instead of installing PyQt in the virtualenv. However, unless
|
||||
you have a new QtWebKit or QtWebEngine available, qutebrowser will not work. It
|
||||
also typically means you'll be using an older release of QtWebEngine.
|
||||
|
||||
On Windows, run `set PYTHON=C:\path\to\python.exe` (CMD) or `$Env:PYTHON =
|
||||
"..."` (Powershell) first.
|
||||
|
||||
There is a third mode, `scripts/mkvenv.py --pyqt-type source` which uses a
|
||||
system-wide Qt but builds PyQt from source. In most scenarios, this shouldn't
|
||||
be needed.
|
||||
There is a third mode, `mkvenv.py --pyqt-type source` which uses a system-wide
|
||||
Qt but builds PyQt from source. In most scenarios, this shouldn't be needed.
|
||||
|
||||
Creating a wrapper script
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Running `scripts/mkvenv.py` does not install a system-wide `qutebrowser`
|
||||
script. You can launch qutebrowser by doing:
|
||||
Running `mkvenv.py` does not install a system-wide `qutebrowser` script. You can
|
||||
launch qutebrowser by doing:
|
||||
|
||||
----
|
||||
.venv/bin/python3 -m qutebrowser
|
||||
|
|
@ -500,9 +485,9 @@ You can create a simple wrapper script to start qutebrowser somewhere in your
|
|||
Updating
|
||||
~~~~~~~~
|
||||
|
||||
If you cloned the git repository, run `scripts/mkvenv.py --update` which will
|
||||
take care of updating the code (via `git pull`) and recreating the environment
|
||||
with the newest dependencies.
|
||||
If you cloned the git repository, run `mkvenv.py --update` which will take care
|
||||
of updating the code (via `git pull`) and recreating the environment with the
|
||||
newest dependencies.
|
||||
|
||||
Alternatively, you can update your local copy of the code (e.g. by pulling the
|
||||
git repo, or extracting a new version) and the virtualenv should automatically
|
||||
|
|
|
|||
|
|
@ -432,18 +432,32 @@ Function .onInit
|
|||
StrCpy $KeepReg 1
|
||||
|
||||
; OS version check
|
||||
; 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
|
||||
${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
|
||||
${EndIf}
|
||||
MessageBox MB_OK|MB_ICONSTOP "This version of ${PRODUCT_NAME} requires a 64-bit$\r$\n\
|
||||
version of Windows 10 1809 or later."
|
||||
_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
|
||||
Abort
|
||||
_os_check_pass:
|
||||
|
||||
|
|
|
|||
|
|
@ -131,6 +131,9 @@ 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"'
|
||||
|
|
|
|||
|
|
@ -44,15 +44,6 @@
|
|||
</content_rating>
|
||||
<releases>
|
||||
<!-- Add new releases here -->
|
||||
<release version='3.6.3' date='2025-11-30'/>
|
||||
<release version='3.6.2' date='2025-11-27'/>
|
||||
<release version='3.6.1' date='2025-11-03'/>
|
||||
<release version='3.6.0' date='2025-10-24'/>
|
||||
<release version='3.5.1' date='2025-06-05'/>
|
||||
<release version='3.5.0' date='2025-04-12'/>
|
||||
<release version="3.4.0" date="2024-12-14"/>
|
||||
<release version="3.3.1" date="2024-10-12"/>
|
||||
<release version="3.3.0" date="2024-10-12"/>
|
||||
<release version="3.2.1" date="2024-06-25"/>
|
||||
<release version="3.2.0" date="2024-06-03"/>
|
||||
<release version="3.1.0" date="2023-12-08"/>
|
||||
|
|
|
|||
|
|
@ -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/webp;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/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/qute;
|
||||
Keywords=Browser
|
||||
Actions=new-window;preferences;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,66 +25,24 @@ INFO_PLIST_UPDATES = {
|
|||
"CFBundleURLName": "local file URL",
|
||||
"CFBundleURLSchemes": ["file"]
|
||||
}],
|
||||
'CFBundleDocumentTypes': [
|
||||
{
|
||||
"CFBundleTypeIconFile": "document.icns",
|
||||
"CFBundleTypeName": name,
|
||||
"CFBundleTypeRole": "Viewer",
|
||||
"LSItemContentTypes": [content_type],
|
||||
}
|
||||
for name, content_type in [
|
||||
("GIF image", "com.compuserve.gif"),
|
||||
("HTML document", "public.html"),
|
||||
("XHTML document", "public.xhtml"),
|
||||
("JavaScript script", "com.netscape.javascript-source"),
|
||||
("JPEG image", "public.jpeg"),
|
||||
("MHTML document", "org.ietf.mhtml"),
|
||||
("HTML5 Audio (Ogg)", "org.xiph.ogg-audio"),
|
||||
("HTML5 Video (Ogg)", "org.xiph.oggv"),
|
||||
("PNG image", "public.png"),
|
||||
("SVG document", "public.svg-image"),
|
||||
("Plain text document", "public.text"),
|
||||
("HTML5 Video (WebM)", "org.webmproject.webm"),
|
||||
("WebP image", "org.webmproject.webp"),
|
||||
("PDF Document", "com.adobe.pdf"),
|
||||
]
|
||||
],
|
||||
'UTImportedTypeDeclarations': [
|
||||
{
|
||||
"UTTypeConformsTo": ["public.data", "public.content"],
|
||||
"UTTypeDescription": "MIME HTML document",
|
||||
"UTTypeIconFile": "document.icns",
|
||||
"UTTypeIdentifier": "org.ietf.mhtml",
|
||||
"UTTypeReferenceURL": "https://www.ietf.org/rfc/rfc2557",
|
||||
"UTTypeTagSpecification": {
|
||||
"com.apple.ostype": "MHTM",
|
||||
"public.filename-extension": ["mht", "mhtml"],
|
||||
"public.mime-type": ["multipart/related", "application/x-mimearchive"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"UTTypeConformsTo": ["public.audio"],
|
||||
"UTTypeDescription": "Ogg Audio",
|
||||
"UTTypeIconFile": "document.icns",
|
||||
"UTTypeIdentifier": "org.xiph.ogg-audio",
|
||||
"UTTypeReferenceURL": "https://xiph.org/ogg/",
|
||||
"UTTypeTagSpecification": {
|
||||
"public.filename-extension": ["ogg", "oga"],
|
||||
"public.mime-type": ["audio/ogg"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"UTTypeConformsTo": ["public.movie"],
|
||||
"UTTypeDescription": "Ogg Video",
|
||||
"UTTypeIconFile": "document.icns",
|
||||
"UTTypeIdentifier": "org.xiph.ogv",
|
||||
"UTTypeReferenceURL": "https://xiph.org/ogg/",
|
||||
"UTTypeTagSpecification": {
|
||||
"public.filename-extension": ["ogm", "ogv"],
|
||||
"public.mime-type": ["video/ogg"],
|
||||
},
|
||||
},
|
||||
],
|
||||
'CFBundleDocumentTypes': [{
|
||||
"CFBundleTypeExtensions": ["html", "htm"],
|
||||
"CFBundleTypeMIMETypes": ["text/html"],
|
||||
"CFBundleTypeName": "HTML document",
|
||||
"CFBundleTypeOSTypes": ["HTML"],
|
||||
"CFBundleTypeRole": "Viewer",
|
||||
}, {
|
||||
"CFBundleTypeExtensions": ["xhtml"],
|
||||
"CFBundleTypeMIMETypes": ["text/xhtml"],
|
||||
"CFBundleTypeName": "XHTML document",
|
||||
"CFBundleTypeRole": "Viewer",
|
||||
}, {
|
||||
"CFBundleTypeExtensions": ["mhtml"],
|
||||
"CFBundleTypeMIMETypes": ["multipart/related", "application/x-mimearchive", "message/rfc822"],
|
||||
"CFBundleTypeName": "MHTML document",
|
||||
"CFBundleTypeRole": "Viewer",
|
||||
}],
|
||||
|
||||
# https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos
|
||||
#
|
||||
# Keys based on Google Chrome's .app, except Bluetooth keys which seem to
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
build==1.2.1
|
||||
check-manifest==0.49
|
||||
importlib_metadata==7.1.0
|
||||
packaging==24.0
|
||||
pyproject_hooks==1.1.0
|
||||
tomli==2.0.1
|
||||
zipp==3.19.1
|
||||
|
|
@ -0,0 +1 @@
|
|||
check-manifest
|
||||
|
|
@ -1,73 +1,48 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
annotated-types==0.7.0
|
||||
anyio==4.12.0
|
||||
autocommand==2.2.2
|
||||
backports.tarfile==1.2.0
|
||||
bracex==2.6
|
||||
build==1.3.0
|
||||
bump-my-version==1.2.5
|
||||
certifi==2025.11.12
|
||||
cffi==2.0.0
|
||||
charset-normalizer==3.4.4
|
||||
click==8.1.8
|
||||
cryptography==46.0.3
|
||||
docutils==0.22.3
|
||||
exceptiongroup==1.3.1
|
||||
build==1.2.1
|
||||
bump2version==1.0.1
|
||||
certifi==2024.6.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
cryptography==42.0.7
|
||||
docutils==0.20.1
|
||||
github3.py==4.0.1
|
||||
h11==0.16.0
|
||||
httpcore==1.0.9
|
||||
httpx==0.28.1
|
||||
hunter==3.9.0
|
||||
id==1.5.0
|
||||
idna==3.11
|
||||
importlib_metadata==8.7.0
|
||||
importlib_resources==6.5.2
|
||||
inflect==7.3.1
|
||||
hunter==3.7.0
|
||||
idna==3.7
|
||||
importlib_metadata==7.1.0
|
||||
importlib_resources==6.4.0
|
||||
jaraco.classes==3.4.0
|
||||
jaraco.collections==5.1.0
|
||||
jaraco.context==6.0.1
|
||||
jaraco.context==5.3.0
|
||||
jaraco.functools==4.0.1
|
||||
jaraco.text==3.12.1
|
||||
jeepney==0.9.0
|
||||
keyring==25.7.0
|
||||
manhole==1.8.1
|
||||
jeepney==0.8.0
|
||||
keyring==25.2.1
|
||||
manhole==1.8.0
|
||||
markdown-it-py==3.0.0
|
||||
mdurl==0.1.2
|
||||
more-itertools==10.8.0
|
||||
nh3==0.3.2
|
||||
packaging==25.0
|
||||
platformdirs==4.4.0
|
||||
prompt_toolkit==3.0.52
|
||||
pycparser==2.23
|
||||
pydantic==2.12.5
|
||||
pydantic-settings==2.11.0
|
||||
pydantic_core==2.41.5
|
||||
Pygments==2.19.2
|
||||
PyJWT==2.10.1
|
||||
Pympler==1.1
|
||||
pyproject_hooks==1.2.0
|
||||
PyQt-builder==1.19.1
|
||||
more-itertools==10.2.0
|
||||
nh3==0.2.17
|
||||
packaging==24.0
|
||||
pkginfo==1.11.0
|
||||
pycparser==2.22
|
||||
Pygments==2.18.0
|
||||
PyJWT==2.8.0
|
||||
Pympler==1.0.1
|
||||
pyproject_hooks==1.1.0
|
||||
PyQt-builder==1.16.2
|
||||
python-dateutil==2.9.0.post0
|
||||
python-dotenv==1.2.1
|
||||
questionary==2.1.1
|
||||
readme_renderer==44.0
|
||||
requests==2.32.5
|
||||
readme_renderer==43.0
|
||||
requests==2.32.3
|
||||
requests-toolbelt==1.0.0
|
||||
rfc3986==2.0.0
|
||||
rich==14.2.0
|
||||
rich-click==1.9.4
|
||||
rich==13.7.1
|
||||
SecretStorage==3.3.3
|
||||
sip==6.14.0
|
||||
six==1.17.0
|
||||
tomli==2.3.0
|
||||
tomlkit==0.13.3
|
||||
twine==6.2.0
|
||||
typeguard==4.3.0
|
||||
typing-inspection==0.4.2
|
||||
typing_extensions==4.15.0
|
||||
uritemplate==4.2.0
|
||||
# urllib3==2.6.2
|
||||
wcmatch==10.1
|
||||
wcwidth==0.2.14
|
||||
zipp==3.23.0
|
||||
sip==6.8.3
|
||||
six==1.16.0
|
||||
tomli==2.0.1
|
||||
twine==5.1.0
|
||||
typing_extensions==4.12.1
|
||||
uritemplate==4.1.1
|
||||
# urllib3==2.2.1
|
||||
zipp==3.19.1
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
hunter
|
||||
pympler
|
||||
github3.py
|
||||
bump-my-version
|
||||
bump2version
|
||||
requests
|
||||
pyqt-builder
|
||||
build
|
||||
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
|
||||
#@ ignore: urllib3
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
asciidoc==10.2.1
|
||||
asciidoc==10.2.0
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
attrs==25.4.0
|
||||
flake8==7.3.0
|
||||
flake8-bugbear==24.12.12
|
||||
flake8-builtins==3.0.0
|
||||
flake8-comprehensions==3.17.0
|
||||
attrs==23.2.0
|
||||
flake8==7.0.0
|
||||
flake8-bugbear==24.4.26
|
||||
flake8-builtins==2.5.0
|
||||
flake8-comprehensions==3.14.0
|
||||
flake8-debugger==4.1.2
|
||||
flake8-deprecated==2.2.1
|
||||
flake8-docstrings==1.7.0
|
||||
flake8-future-import==0.4.7
|
||||
flake8-plugin-utils==1.3.3
|
||||
flake8-pytest-style==2.1.0
|
||||
flake8-pytest-style==2.0.0
|
||||
flake8-string-format==0.3.0
|
||||
flake8-tidy-imports==4.12.0
|
||||
flake8-tidy-imports==4.10.0
|
||||
flake8-tuple==0.4.1
|
||||
mccabe==0.7.0
|
||||
pep8-naming==0.15.1
|
||||
pycodestyle==2.14.0
|
||||
pep8-naming==0.14.1
|
||||
pycodestyle==2.11.1
|
||||
pydocstyle==6.3.0
|
||||
pyflakes==3.4.0
|
||||
six==1.17.0
|
||||
snowballstemmer==3.0.1
|
||||
pyflakes==3.2.0
|
||||
six==1.16.0
|
||||
snowballstemmer==2.2.0
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
chardet==5.2.0
|
||||
diff_cover==10.0.0
|
||||
Jinja2==3.1.6
|
||||
librt==0.7.3
|
||||
lxml==6.0.2
|
||||
MarkupSafe==3.0.3
|
||||
mypy==1.19.0
|
||||
mypy_extensions==1.1.0
|
||||
pathspec==0.12.1
|
||||
pluggy==1.6.0
|
||||
Pygments==2.19.2
|
||||
diff_cover==9.0.0
|
||||
importlib_resources==6.4.0
|
||||
Jinja2==3.1.4
|
||||
lxml==5.2.2
|
||||
MarkupSafe==2.1.5
|
||||
mypy==1.10.0
|
||||
mypy-extensions==1.0.0
|
||||
pluggy==1.5.0
|
||||
Pygments==2.18.0
|
||||
PyQt5-stubs==5.15.6.0
|
||||
tomli==2.3.0
|
||||
types-colorama==0.4.15.20250801
|
||||
types-docutils==0.22.3.20251115
|
||||
types-Pygments==2.19.0.20251121
|
||||
types-PyYAML==6.0.12.20250915
|
||||
typing_extensions==4.15.0
|
||||
tomli==2.0.1
|
||||
types-colorama==0.4.15.20240311
|
||||
types-docutils==0.21.0.20240423
|
||||
types-Pygments==2.18.0.20240506
|
||||
types-PyYAML==6.0.12.20240311
|
||||
types-setuptools==70.0.0.20240524
|
||||
typing_extensions==4.12.1
|
||||
zipp==3.19.1
|
||||
|
|
|
|||
|
|
@ -6,3 +6,6 @@ PyQt5-stubs
|
|||
types-PyYAML
|
||||
types-colorama
|
||||
types-Pygments
|
||||
|
||||
# So stubs are available even on newer Python versions
|
||||
importlib_resources
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
altgraph==0.17.5
|
||||
importlib_metadata==8.7.0
|
||||
packaging==25.0
|
||||
pyinstaller==6.17.0
|
||||
pyinstaller-hooks-contrib==2025.10
|
||||
zipp==3.23.0
|
||||
altgraph==0.17.4
|
||||
importlib_metadata==7.1.0
|
||||
packaging==24.0
|
||||
pyinstaller==6.7.0
|
||||
pyinstaller-hooks-contrib==2024.6
|
||||
zipp==3.19.1
|
||||
|
|
|
|||
|
|
@ -1,28 +1,26 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
astroid==3.3.11
|
||||
certifi==2025.11.12
|
||||
cffi==2.0.0
|
||||
charset-normalizer==3.4.4
|
||||
cryptography==46.0.3
|
||||
dill==0.4.0
|
||||
astroid==3.2.2
|
||||
certifi==2024.6.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
cryptography==42.0.7
|
||||
dill==0.3.8
|
||||
github3.py==4.0.1
|
||||
idna==3.11
|
||||
importlib_metadata==8.7.0
|
||||
isort==6.1.0
|
||||
idna==3.7
|
||||
isort==5.13.2
|
||||
mccabe==0.7.0
|
||||
pefile==2024.8.26
|
||||
platformdirs==4.4.0
|
||||
pycparser==2.23
|
||||
PyJWT==2.10.1
|
||||
pylint==3.3.9
|
||||
pefile==2023.2.7
|
||||
platformdirs==4.2.2
|
||||
pycparser==2.22
|
||||
PyJWT==2.8.0
|
||||
pylint==3.2.2
|
||||
python-dateutil==2.9.0.post0
|
||||
./scripts/dev/pylint_checkers
|
||||
requests==2.32.5
|
||||
six==1.17.0
|
||||
tomli==2.3.0
|
||||
tomlkit==0.13.3
|
||||
typing_extensions==4.15.0
|
||||
uritemplate==4.2.0
|
||||
# urllib3==2.6.2
|
||||
zipp==3.23.0
|
||||
requests==2.32.3
|
||||
six==1.16.0
|
||||
tomli==2.0.1
|
||||
tomlkit==0.12.5
|
||||
typing_extensions==4.12.1
|
||||
uritemplate==4.1.1
|
||||
# urllib3==2.2.1
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ 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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt5==5.15.2 # rq.filter: == 5.15.2
|
||||
PyQt5_sip==12.17.1
|
||||
PyQt5-sip==12.13.0
|
||||
PyQtWebEngine==5.15.2 # rq.filter: == 5.15.2
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt5==5.15.11 # rq.filter: < 5.16
|
||||
PyQt5-Qt5==5.15.18
|
||||
PyQt5_sip==12.17.1
|
||||
PyQtWebEngine==5.15.7 # rq.filter: < 5.16
|
||||
PyQtWebEngine-Qt5==5.15.18
|
||||
PyQt5==5.15.10 # rq.filter: < 5.16
|
||||
PyQt5-Qt5==5.15.2
|
||||
PyQt5-sip==12.13.0
|
||||
PyQtWebEngine==5.15.6 # rq.filter: < 5.16
|
||||
PyQtWebEngine-Qt5==5.15.2
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt5==5.15.11
|
||||
PyQt5-Qt5==5.15.18
|
||||
PyQt5_sip==12.17.1
|
||||
PyQtWebEngine==5.15.7
|
||||
PyQtWebEngine-Qt5==5.15.18
|
||||
PyQt5==5.15.10
|
||||
PyQt5-Qt5==5.15.2
|
||||
PyQt5-sip==12.13.0
|
||||
PyQtWebEngine==5.15.6
|
||||
PyQtWebEngine-Qt5==5.15.2
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.10.1
|
||||
PyQt6-Qt6==6.10.1
|
||||
PyQt6-WebEngine==6.10.0
|
||||
PyQt6-WebEngine-Qt6==6.10.1
|
||||
PyQt6_sip==13.10.2
|
||||
--extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
PyQt6 >= 6.10, < 6.11
|
||||
PyQt6-Qt6 >= 6.10, < 6.11
|
||||
PyQt6-WebEngine >= 6.10, < 6.11
|
||||
PyQt6-WebEngine-Qt6 >= 6.10, < 6.11
|
||||
|
||||
# WORKAROUND for https://www.riverbankcomputing.com/pipermail/pyqt/2025-October/046347.html
|
||||
#@ add: --extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
--extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
PyQt6==6.2.3
|
||||
PyQt6-Qt6==6.2.4
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.2.1
|
||||
PyQt6-WebEngine-Qt6==6.2.4
|
||||
PyQt6_sip==13.10.2
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
PyQt6==6.3.1
|
||||
PyQt6-Qt6==6.3.2
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.3.1
|
||||
PyQt6-WebEngine-Qt6==6.3.2
|
||||
PyQt6_sip==13.10.2
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
PyQt6==6.4.2
|
||||
PyQt6-Qt6==6.4.3
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.4.0
|
||||
PyQt6-WebEngine-Qt6==6.4.3
|
||||
PyQt6_sip==13.10.2
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
PyQt6==6.5.3
|
||||
PyQt6-Qt6==6.5.3
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.5.0
|
||||
PyQt6-WebEngine-Qt6==6.5.3
|
||||
PyQt6_sip==13.10.2
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
PyQt6==6.6.1
|
||||
PyQt6-Qt6==6.6.3
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.6.0
|
||||
PyQt6-WebEngine-Qt6==6.6.3
|
||||
PyQt6_sip==13.10.2
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.7.1
|
||||
PyQt6-Qt6==6.7.3
|
||||
PyQt6==6.7.0
|
||||
PyQt6-Qt6==6.7.2
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.7.0
|
||||
PyQt6-WebEngine-Qt6==6.7.3
|
||||
PyQt6-WebEngineSubwheel-Qt6==6.7.3
|
||||
PyQt6_sip==13.10.2
|
||||
PyQt6-WebEngine-Qt6==6.7.2
|
||||
PyQt6-WebEngineSubwheel-Qt6==6.7.2
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.8.1
|
||||
PyQt6-Qt6==6.8.2
|
||||
PyQt6-WebEngine==6.8.0
|
||||
PyQt6-WebEngine-Qt6==6.8.2
|
||||
PyQt6_sip==13.10.2
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
PyQt6 >= 6.8, < 6.9
|
||||
PyQt6-Qt6 >= 6.8, < 6.9
|
||||
PyQt6-WebEngine >= 6.8, < 6.9
|
||||
PyQt6-WebEngine-Qt6 >= 6.8, < 6.9
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.9.1
|
||||
PyQt6-Qt6==6.9.2
|
||||
PyQt6-WebEngine==6.9.0
|
||||
PyQt6-WebEngine-Qt6==6.9.2
|
||||
PyQt6_sip==13.10.2
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
PyQt6 >= 6.9, < 6.10
|
||||
PyQt6-Qt6 >= 6.9, < 6.10
|
||||
PyQt6-WebEngine >= 6.9, < 6.10
|
||||
PyQt6-WebEngine-Qt6 >= 6.9, < 6.10
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.10.1
|
||||
PyQt6-Qt6==6.10.1
|
||||
PyQt6-WebEngine==6.10.0
|
||||
PyQt6-WebEngine-Qt6==6.10.1
|
||||
PyQt6_sip==13.10.2
|
||||
--extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
PyQt6==6.7.0
|
||||
PyQt6-Qt6==6.7.2
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.7.0
|
||||
PyQt6-WebEngine-Qt6==6.7.2
|
||||
PyQt6-WebEngineSubwheel-Qt6==6.7.2
|
||||
|
|
|
|||
|
|
@ -2,7 +2,3 @@ PyQt6
|
|||
PyQt6-Qt6
|
||||
PyQt6-WebEngine
|
||||
PyQt6-WebEngine-Qt6
|
||||
|
||||
# WORKAROUND for https://www.riverbankcomputing.com/pipermail/pyqt/2025-October/046347.html
|
||||
#@ add: --extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
--extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
PyQt6==6.10.1
|
||||
PyQt6-Qt6==6.10.1
|
||||
PyQt6-WebEngine==6.10.0
|
||||
PyQt6-WebEngine-Qt6==6.10.1
|
||||
PyQt6_sip==13.10.2
|
||||
--extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
PyQt6==6.7.0
|
||||
PyQt6-Qt6==6.7.2
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-WebEngine==6.7.0
|
||||
PyQt6-WebEngine-Qt6==6.7.2
|
||||
PyQt6-WebEngineSubwheel-Qt6==6.7.2
|
||||
|
|
|
|||
|
|
@ -2,7 +2,3 @@ PyQt6
|
|||
PyQt6-Qt6
|
||||
PyQt6-WebEngine
|
||||
PyQt6-WebEngine-Qt6
|
||||
|
||||
# WORKAROUND for https://www.riverbankcomputing.com/pipermail/pyqt/2025-October/046347.html
|
||||
#@ add: --extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
--extra-index-url https://www.riverbankcomputing.com/pypi/simple/
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
build==1.3.0
|
||||
certifi==2025.11.12
|
||||
charset-normalizer==3.4.4
|
||||
check-manifest==0.51
|
||||
docutils==0.22.3
|
||||
idna==3.11
|
||||
importlib_metadata==8.7.0
|
||||
packaging==25.0
|
||||
Pygments==2.19.2
|
||||
pyproject_hooks==1.2.0
|
||||
pyroma==5.0.1
|
||||
requests==2.32.5
|
||||
tomli==2.3.0
|
||||
trove-classifiers==2025.12.1.14
|
||||
urllib3==2.6.2
|
||||
zipp==3.23.0
|
||||
build==1.2.1
|
||||
certifi==2024.6.2
|
||||
charset-normalizer==3.3.2
|
||||
docutils==0.20.1
|
||||
idna==3.7
|
||||
importlib_metadata==7.1.0
|
||||
packaging==24.0
|
||||
Pygments==2.18.0
|
||||
pyproject_hooks==1.1.0
|
||||
pyroma==4.2
|
||||
requests==2.32.3
|
||||
tomli==2.0.1
|
||||
trove-classifiers==2024.5.22
|
||||
urllib3==2.2.1
|
||||
zipp==3.19.1
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
pyroma
|
||||
check-manifest
|
||||
|
|
|
|||
|
|
@ -12,7 +12,12 @@ 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.*"
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
alabaster==0.7.16
|
||||
babel==2.17.0
|
||||
certifi==2025.11.12
|
||||
charset-normalizer==3.4.4
|
||||
docutils==0.21.2
|
||||
idna==3.11
|
||||
alabaster==0.7.13
|
||||
Babel==2.15.0
|
||||
certifi==2024.6.2
|
||||
charset-normalizer==3.3.2
|
||||
docutils==0.20.1
|
||||
idna==3.7
|
||||
imagesize==1.4.1
|
||||
importlib_metadata==8.7.0
|
||||
Jinja2==3.1.6
|
||||
MarkupSafe==3.0.3
|
||||
packaging==25.0
|
||||
Pygments==2.19.2
|
||||
requests==2.32.5
|
||||
snowballstemmer==3.0.1
|
||||
Sphinx==7.4.7
|
||||
sphinxcontrib-applehelp==2.0.0
|
||||
sphinxcontrib-devhelp==2.0.0
|
||||
sphinxcontrib-htmlhelp==2.1.0
|
||||
importlib_metadata==7.1.0
|
||||
Jinja2==3.1.4
|
||||
MarkupSafe==2.1.5
|
||||
packaging==24.0
|
||||
Pygments==2.18.0
|
||||
pytz==2024.1
|
||||
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
|
||||
sphinxcontrib-jsmath==1.0.1
|
||||
sphinxcontrib-qthelp==2.0.0
|
||||
sphinxcontrib-serializinghtml==2.0.0
|
||||
tomli==2.3.0
|
||||
urllib3==2.6.2
|
||||
zipp==3.23.0
|
||||
sphinxcontrib-qthelp==1.0.3
|
||||
sphinxcontrib-serializinghtml==1.1.5
|
||||
urllib3==2.2.1
|
||||
zipp==3.19.1
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@
|
|||
# bzr+lp:beautifulsoup
|
||||
beautifulsoup4
|
||||
git+https://github.com/cherrypy/cheroot.git
|
||||
coverage[toml] @ git+https://github.com/nedbat/coveragepy.git
|
||||
git+https://github.com/nedbat/coveragepy.git#egg=coverage[toml]
|
||||
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
|
||||
gherkin-official<31.0.0 # https://github.com/cucumber/gherkin/issues/373
|
||||
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
|
||||
|
|
@ -21,7 +20,6 @@ git+https://github.com/pygments/pygments.git
|
|||
git+https://github.com/pytest-dev/pytest-repeat.git
|
||||
git+https://github.com/pytest-dev/pytest-cov.git
|
||||
git+https://github.com/The-Compiler/pytest-xvfb.git
|
||||
git+https://github.com/python-pillow/Pillow.git
|
||||
git+https://github.com/pytest-dev/pytest-xdist.git
|
||||
git+https://github.com/john-kurkowski/tldextract
|
||||
|
||||
|
|
|
|||
|
|
@ -1,67 +1,56 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
attrs==25.4.0
|
||||
autocommand==2.2.2
|
||||
backports.tarfile==1.2.0
|
||||
beautifulsoup4==4.14.3
|
||||
blinker==1.9.0
|
||||
certifi==2025.11.12
|
||||
charset-normalizer==3.4.4
|
||||
cheroot==11.1.2
|
||||
click==8.1.8
|
||||
coverage==7.10.7
|
||||
exceptiongroup==1.3.1
|
||||
execnet==2.1.2
|
||||
filelock==3.19.1
|
||||
Flask==3.1.2
|
||||
gherkin-official==29.0.0
|
||||
hunter==3.9.0
|
||||
hypothesis==6.141.1
|
||||
idna==3.11
|
||||
importlib_metadata==8.7.0
|
||||
importlib_resources==6.5.2
|
||||
inflect==7.3.1
|
||||
iniconfig==2.1.0
|
||||
attrs==23.2.0
|
||||
beautifulsoup4==4.12.3
|
||||
blinker==1.8.2
|
||||
certifi==2024.6.2
|
||||
charset-normalizer==3.3.2
|
||||
cheroot==10.0.1
|
||||
click==8.1.7
|
||||
coverage==7.5.3
|
||||
exceptiongroup==1.2.1
|
||||
execnet==2.1.1
|
||||
filelock==3.14.0
|
||||
Flask==3.0.3
|
||||
hunter==3.7.0
|
||||
hypothesis==6.103.0
|
||||
idna==3.7
|
||||
importlib_metadata==7.1.0
|
||||
iniconfig==2.0.0
|
||||
itsdangerous==2.2.0
|
||||
jaraco.collections==5.1.0
|
||||
jaraco.context==6.0.1
|
||||
jaraco.functools==4.0.1
|
||||
jaraco.text==3.12.1
|
||||
# Jinja2==3.1.6
|
||||
Mako==1.3.10
|
||||
manhole==1.8.1
|
||||
# MarkupSafe==3.0.3
|
||||
more-itertools==10.8.0
|
||||
packaging==25.0
|
||||
parse==1.20.2
|
||||
parse_type==0.6.6
|
||||
pillow==11.3.0
|
||||
platformdirs==4.4.0
|
||||
pluggy==1.6.0
|
||||
# Jinja2==3.1.4
|
||||
Mako==1.3.5
|
||||
manhole==1.8.0
|
||||
# MarkupSafe==2.1.5
|
||||
more-itertools==10.2.0
|
||||
packaging==24.0
|
||||
parse==1.20.1
|
||||
parse-type==0.6.2
|
||||
pluggy==1.5.0
|
||||
py-cpuinfo==9.0.0
|
||||
Pygments==2.19.2
|
||||
pytest==8.4.2
|
||||
pytest-bdd==8.1.0
|
||||
pytest-benchmark==5.2.3
|
||||
pytest-cov==7.0.0
|
||||
Pygments==2.18.0
|
||||
pytest==8.2.1
|
||||
pytest-bdd==7.1.2
|
||||
pytest-benchmark==4.0.0
|
||||
pytest-cov==5.0.0
|
||||
pytest-instafail==0.5.0
|
||||
pytest-mock==3.15.1
|
||||
pytest-qt==4.5.0
|
||||
pytest-repeat==0.9.4
|
||||
pytest-rerunfailures==16.0.1
|
||||
pytest-xdist==3.8.0
|
||||
pytest-xvfb==3.1.1
|
||||
pytest-mock==3.14.0
|
||||
pytest-qt==4.4.0
|
||||
pytest-repeat==0.9.3
|
||||
pytest-rerunfailures==14.0
|
||||
pytest-xdist==3.6.1
|
||||
pytest-xvfb==3.0.0
|
||||
PyVirtualDisplay==3.0
|
||||
requests==2.32.5
|
||||
requests-file==3.0.1
|
||||
six==1.17.0
|
||||
requests==2.32.3
|
||||
requests-file==2.1.0
|
||||
six==1.16.0
|
||||
sortedcontainers==2.4.0
|
||||
soupsieve==2.8
|
||||
tldextract==5.3.0
|
||||
tomli==2.3.0
|
||||
typeguard==4.3.0
|
||||
typing_extensions==4.15.0
|
||||
urllib3==2.6.2
|
||||
vulture==2.14
|
||||
Werkzeug==3.1.4
|
||||
zipp==3.23.0
|
||||
soupsieve==2.5
|
||||
tldextract==5.1.2
|
||||
tomli==2.0.1
|
||||
typing_extensions==4.12.1
|
||||
urllib3==2.2.1
|
||||
vulture==2.11
|
||||
Werkzeug==3.0.3
|
||||
zipp==3.19.1
|
||||
|
|
|
|||
|
|
@ -25,21 +25,10 @@ pytest-cov
|
|||
# To avoid windows from popping up
|
||||
pytest-xvfb
|
||||
PyVirtualDisplay
|
||||
pillow
|
||||
# To run on multiple cores with -n
|
||||
pytest-xdist
|
||||
|
||||
# Needed to test misc/userscripts/qute-lastpass
|
||||
tldextract
|
||||
|
||||
# importlib_resources==6.4.0, jaraco.context and platformdirs are being
|
||||
# included in the lock file via setuptools' vendored dependencies and
|
||||
# conflicting with the more up to date one pulled down by other requirements
|
||||
# files.
|
||||
# Include them here even though we don't need them to make sure we at least
|
||||
# get an up to date version.
|
||||
importlib_resources
|
||||
jaraco.context
|
||||
platformdirs
|
||||
|
||||
#@ ignore: Jinja2, MarkupSafe, colorama
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
cachetools==6.2.3
|
||||
cachetools==5.3.3
|
||||
chardet==5.2.0
|
||||
colorama==0.4.6
|
||||
distlib==0.4.0
|
||||
filelock==3.19.1
|
||||
packaging==25.0
|
||||
pip==25.3
|
||||
platformdirs==4.4.0
|
||||
pluggy==1.6.0
|
||||
pyproject-api==1.9.1
|
||||
setuptools==80.9.0
|
||||
tomli==2.3.0
|
||||
tox==4.30.3 ; python_full_version!="3.14.0b1"
|
||||
typing_extensions==4.15.0
|
||||
virtualenv==20.35.4
|
||||
wheel==0.45.1
|
||||
tox @ git+https://github.com/tox-dev/tox ; python_full_version=="3.14.0b1"
|
||||
distlib==0.3.8
|
||||
filelock==3.14.0
|
||||
packaging==24.0
|
||||
pip==24.0
|
||||
platformdirs==4.2.2
|
||||
pluggy==1.5.0
|
||||
pyproject-api==1.6.1
|
||||
setuptools==70.0.0
|
||||
tomli==2.0.1
|
||||
tox==4.15.0
|
||||
virtualenv==20.26.2
|
||||
wheel==0.43.0
|
||||
|
|
|
|||
|
|
@ -1,5 +1,2 @@
|
|||
tox
|
||||
wheel
|
||||
|
||||
#@ markers: tox python_full_version!="3.14.0b1"
|
||||
#@ add: tox @ git+https://github.com/tox-dev/tox ; python_full_version=="3.14.0b1"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
tomli==2.3.0
|
||||
vulture==2.14
|
||||
tomli==2.0.1
|
||||
vulture==2.11
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
pathspec==0.12.1
|
||||
PyYAML==6.0.3
|
||||
yamllint==1.37.1
|
||||
PyYAML==6.0.1
|
||||
yamllint==1.35.1
|
||||
|
|
|
|||
|
|
@ -106,8 +106,6 @@ The following userscripts can be found on their own repositories.
|
|||
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
|
||||
- [qute-translate-popup](https://github.com/JohnBardoe/qute-translate-popup):
|
||||
selected text translation, with a qute popup!
|
||||
|
||||
[Zotero]: https://www.zotero.org/
|
||||
[Pocket]: https://getpocket.com/
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ no_entries_found() {
|
|||
# expected to write the username of that entry to the $username variable and
|
||||
# the corresponding password to $password
|
||||
|
||||
# shellcheck disable=SC2329
|
||||
# shellcheck disable=SC2317
|
||||
reset_backend() {
|
||||
init() { true ; }
|
||||
query_entries() { true ; }
|
||||
|
|
@ -199,8 +199,7 @@ choose_entry_zenity() {
|
|||
}
|
||||
|
||||
choose_entry_zenity_radio() {
|
||||
# shellcheck disable=SC2329
|
||||
zenity_helper() {
|
||||
zenity_helper() { # shellcheck disable=SC2317
|
||||
awk '{ print $0 ; print $0 }' \
|
||||
| zenity --list --radiolist \
|
||||
--title "qutebrowser password fill" \
|
||||
|
|
@ -280,7 +279,7 @@ pass_backend() {
|
|||
|
||||
# =======================================================
|
||||
# backend: secret
|
||||
# shellcheck disable=SC2329
|
||||
# shellcheck disable=SC2317
|
||||
secret_backend() {
|
||||
init() {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -96,8 +96,7 @@ def ask_password(password_prompt_invocation):
|
|||
raise Exception('Could not unlock vault')
|
||||
master_pass = process.stdout.strip()
|
||||
return subprocess.check_output(
|
||||
['bw', 'unlock', '--raw', '--passwordenv', 'BW_MASTERPASS'],
|
||||
env={**os.environ, 'BW_MASTERPASS': master_pass},
|
||||
['bw', 'unlock', '--raw', master_pass],
|
||||
text=True,
|
||||
).strip()
|
||||
|
||||
|
|
@ -133,7 +132,7 @@ def get_session_key(auto_lock, password_prompt_invocation):
|
|||
def pass_(domain, encoding, auto_lock, password_prompt_invocation):
|
||||
session_key = get_session_key(auto_lock, password_prompt_invocation)
|
||||
process = subprocess.run(
|
||||
['bw', 'list', 'items', '--nointeraction', '--session', session_key, '--url', domain],
|
||||
['bw', 'list', 'items', '--session', session_key, '--url', domain],
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
|
|
@ -142,10 +141,6 @@ def pass_(domain, encoding, auto_lock, password_prompt_invocation):
|
|||
msg = 'Bitwarden CLI returned for {:s} - {:s}'.format(domain, err)
|
||||
stderr(msg)
|
||||
|
||||
if "Vault is locked" in err:
|
||||
stderr("Bitwarden Vault got locked, trying again with clean session")
|
||||
return pass_(domain, encoding, 0, password_prompt_invocation)
|
||||
|
||||
if process.returncode:
|
||||
return '[]'
|
||||
|
||||
|
|
@ -157,7 +152,7 @@ def pass_(domain, encoding, auto_lock, password_prompt_invocation):
|
|||
def get_totp_code(selection_id, domain_name, encoding, auto_lock, password_prompt_invocation):
|
||||
session_key = get_session_key(auto_lock, password_prompt_invocation)
|
||||
process = subprocess.run(
|
||||
['bw', 'get', 'totp', '--nointeraction', '--session', session_key, selection_id],
|
||||
['bw', 'get', 'totp', '--session', session_key, selection_id],
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
|
|
@ -167,10 +162,6 @@ def get_totp_code(selection_id, domain_name, encoding, auto_lock, password_promp
|
|||
msg = 'Bitwarden CLI returned for {:s} - {:s}'.format(domain_name, err)
|
||||
stderr(msg)
|
||||
|
||||
if "Vault is locked" in err:
|
||||
stderr("Bitwarden Vault got locked, trying again with clean session")
|
||||
return get_totp_code(selection_id, domain_name, encoding, 0, password_prompt_invocation)
|
||||
|
||||
if process.returncode:
|
||||
return '[]'
|
||||
|
||||
|
|
@ -204,20 +195,12 @@ def main(arguments):
|
|||
# the registered domain name and finally: the IPv4 address if that's what
|
||||
# the URL represents
|
||||
candidates = []
|
||||
for target in filter(
|
||||
None,
|
||||
[
|
||||
extract_result.fqdn,
|
||||
(
|
||||
extract_result.top_domain_under_public_suffix
|
||||
if hasattr(extract_result, "top_domain_under_public_suffix")
|
||||
else extract_result.registered_domain
|
||||
),
|
||||
extract_result.subdomain + "." + extract_result.domain,
|
||||
extract_result.domain,
|
||||
extract_result.ipv4,
|
||||
],
|
||||
):
|
||||
for target in filter(None, [
|
||||
extract_result.fqdn,
|
||||
extract_result.registered_domain,
|
||||
extract_result.subdomain + '.' + extract_result.domain,
|
||||
extract_result.domain,
|
||||
extract_result.ipv4]):
|
||||
target_candidates = json.loads(
|
||||
pass_(
|
||||
target,
|
||||
|
|
|
|||
|
|
@ -117,20 +117,7 @@ def main(arguments):
|
|||
# the URL represents
|
||||
candidates = []
|
||||
seen_id = set()
|
||||
for target in filter(
|
||||
None,
|
||||
[
|
||||
extract_result.fqdn,
|
||||
(
|
||||
extract_result.top_domain_under_public_suffix
|
||||
if hasattr(extract_result, "top_domain_under_public_suffix")
|
||||
else extract_result.registered_domain
|
||||
),
|
||||
extract_result.subdomain + extract_result.domain,
|
||||
extract_result.domain,
|
||||
extract_result.ipv4,
|
||||
],
|
||||
):
|
||||
for target in filter(None, [extract_result.fqdn, extract_result.registered_domain, extract_result.subdomain + extract_result.domain, extract_result.domain, extract_result.ipv4]):
|
||||
target_candidates, err = pass_(target, arguments.io_encoding)
|
||||
if err:
|
||||
stderr("LastPass CLI returned for {:s} - {:s}".format(target, err))
|
||||
|
|
|
|||
|
|
@ -40,13 +40,11 @@ import argparse
|
|||
import enum
|
||||
import fnmatch
|
||||
import functools
|
||||
import idna
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import unicodedata
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import tldextract
|
||||
|
|
@ -118,23 +116,6 @@ def qute_command(command):
|
|||
fifo.write(command + '\n')
|
||||
fifo.flush()
|
||||
|
||||
# Encode candidate string parts as Internationalized Domain Name, doing
|
||||
# Unicode normalization before. This allows to properly match (non-ASCII)
|
||||
# pass entries with the corresponding domain names.
|
||||
def idna_encode(name):
|
||||
# Do Unicode normalization first, we use form NFKC because:
|
||||
# 1. Use the compatibility normalization because these sequences have "the same meaning in some contexts"
|
||||
# 2. idna.encode() below requires the Unicode strings to be in normalization form C
|
||||
# See https://en.wikipedia.org/wiki/Unicode_equivalence#Normal_forms
|
||||
unicode_normalized = unicodedata.normalize("NFKC", name)
|
||||
# Empty strings can not be encoded, they appear for example as empty
|
||||
# parts in split_path. If something like this happens, we just fall back
|
||||
# to the unicode representation (which may already be ASCII then).
|
||||
try:
|
||||
idna_encoded = idna.encode(unicode_normalized)
|
||||
except idna.IDNAError:
|
||||
idna_encoded = unicode_normalized
|
||||
return idna_encoded
|
||||
|
||||
def find_pass_candidates(domain, unfiltered=False):
|
||||
candidates = []
|
||||
|
|
@ -149,7 +130,6 @@ def find_pass_candidates(domain, unfiltered=False):
|
|||
if unfiltered or domain in password:
|
||||
candidates.append(password)
|
||||
else:
|
||||
idna_domain = idna_encode(domain)
|
||||
for path, directories, file_names in os.walk(arguments.password_store, followlinks=True):
|
||||
secrets = fnmatch.filter(file_names, '*.gpg')
|
||||
if not secrets:
|
||||
|
|
@ -158,14 +138,11 @@ def find_pass_candidates(domain, unfiltered=False):
|
|||
# Strip password store path prefix to get the relative pass path
|
||||
pass_path = path[len(arguments.password_store):]
|
||||
split_path = pass_path.split(os.path.sep)
|
||||
idna_split_path = [idna_encode(part) for part in split_path]
|
||||
for secret in secrets:
|
||||
secret_base = os.path.splitext(secret)[0]
|
||||
idna_secret_base = idna_encode(secret_base)
|
||||
if not unfiltered and idna_domain not in (idna_split_path + [idna_secret_base]):
|
||||
if not unfiltered and domain not in (split_path + [secret_base]):
|
||||
continue
|
||||
|
||||
# Append the unencoded Unicode path/name since this is how pass uses them
|
||||
candidates.append(os.path.join(pass_path, secret_base))
|
||||
return candidates
|
||||
|
||||
|
|
@ -243,20 +220,7 @@ def main(arguments):
|
|||
|
||||
netloc = urlparse(arguments.url).netloc
|
||||
|
||||
for target in filter(
|
||||
None,
|
||||
[
|
||||
extract_result.fqdn,
|
||||
(
|
||||
extract_result.top_domain_under_public_suffix
|
||||
if hasattr(extract_result, "top_domain_under_public_suffix")
|
||||
else extract_result.registered_domain
|
||||
),
|
||||
extract_result.ipv4,
|
||||
private_domain,
|
||||
netloc,
|
||||
],
|
||||
):
|
||||
for target in filter(None, [extract_result.fqdn, extract_result.registered_domain, extract_result.ipv4, private_domain, netloc]):
|
||||
attempted_targets.append(target)
|
||||
target_candidates = find_pass_candidates(target, unfiltered=arguments.unfiltered)
|
||||
if not target_candidates:
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ create_menu() {
|
|||
done < "$QUTE_CONFIG_DIR"/bookmarks/urls
|
||||
|
||||
# Finally history
|
||||
printf -- '%s\n' "$(sqlite3 -separator ' ' "$QUTE_DATA_DIR/history.sqlite" 'select title, url from CompletionHistory ORDER BY last_atime DESC')"
|
||||
printf -- '%s\n' "$(sqlite3 -separator ' ' "$QUTE_DATA_DIR/history.sqlite" 'select title, url from CompletionHistory')"
|
||||
}
|
||||
|
||||
get_selection() {
|
||||
|
|
|
|||
|
|
@ -9,16 +9,18 @@
|
|||
# :spawn --userscript ripbang amazon maps
|
||||
#
|
||||
|
||||
import os, requests, sys
|
||||
import os, re, requests, sys
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
for argument in sys.argv[1:]:
|
||||
bang = '!' + argument
|
||||
r = requests.get('https://html.duckduckgo.com/html/',
|
||||
allow_redirects=False,
|
||||
r = requests.get('https://duckduckgo.com/',
|
||||
params={'q': bang + ' SEARCHTEXT'},
|
||||
headers={'user-agent': 'qutebrowser ripbang'})
|
||||
|
||||
searchengine = r.headers['location']
|
||||
searchengine = re.search("url=([^']+)", r.text).group(1)
|
||||
searchengine = urlparse(searchengine).query
|
||||
searchengine = parse_qs(searchengine)['uddg'][0]
|
||||
searchengine = searchengine.replace('SEARCHTEXT', '{}')
|
||||
|
||||
if os.getenv('QUTE_FIFO'):
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.check-manifest]
|
||||
ignore = [
|
||||
"qutebrowser/git-commit-id",
|
||||
"qutebrowser/html/doc",
|
||||
"qutebrowser/html/doc/*",
|
||||
"qutebrowser/html/doc/img/cheatsheet-*.png",
|
||||
"*/__pycache__",
|
||||
]
|
||||
31
pytest.ini
31
pytest.ini
|
|
@ -1,5 +1,4 @@
|
|||
[pytest]
|
||||
pythonpath = .
|
||||
log_level = NOTSET
|
||||
addopts = --strict-markers --strict-config --instafail --benchmark-columns=Min,Max,Median
|
||||
testpaths = tests
|
||||
|
|
@ -20,7 +19,6 @@ markers =
|
|||
not_frozen: Tests which can't be run if sys.frozen is True.
|
||||
not_flatpak: Tests which can't be run if running with Flatpak.
|
||||
no_xvfb: Tests which can't be run with Xvfb.
|
||||
no_offscreen: Tests which can't be run with the offscreen platform plugin.
|
||||
frozen: Tests which can only be run if sys.frozen is True.
|
||||
integration: Tests which test a bigger portion of code
|
||||
end2end: End to end tests which run qutebrowser as subprocess
|
||||
|
|
@ -43,8 +41,6 @@ markers =
|
|||
qt6_only: Tests which should only run with Qt 6
|
||||
qt5_xfail: Tests which fail with Qt 5
|
||||
qt6_xfail: Tests which fail with Qt 6
|
||||
qt69_ci_flaky: Tests which are flaky with Qt 6.9+ on CI
|
||||
qt69_ci_skip: Tests which should be skipped with Qt 6.9+ on CI
|
||||
qt_log_level_fail = WARNING
|
||||
qt_log_ignore =
|
||||
# GitHub Actions
|
||||
|
|
@ -76,33 +72,10 @@ qt_log_ignore =
|
|||
^[^ ]*qtwebengine_dictionaries'$
|
||||
# Qt 5 on Archlinux
|
||||
^QSslSocket: cannot resolve .*
|
||||
# Seems to happen after we try to complete immediately after clearing a
|
||||
# model, for example, when no completion function is available for the
|
||||
# current text pattern.
|
||||
QItemSelectionModel: Selecting when no model has been set will result in a no-op.
|
||||
^QSaveFile::commit: File \(.*[/\\]test_failing_flush0[/\\]foo\) is not open$
|
||||
^The following paths were searched for Qt WebEngine dictionaries:.*
|
||||
# Qt 6.9 with Xvfb
|
||||
^Backend texture is not a Vulkan texture\.$
|
||||
^Compositor returned null texture$
|
||||
# With offscreen platform plugin
|
||||
^This plugin does not support (raise\(\)|propagateSizeHints\(\)|createPlatformVulkanInstance|grabbing the keyboard)$
|
||||
^QRhiGles2: Failed to create (temporary )?context$
|
||||
^QVulkanInstance: Failed to initialize Vulkan$
|
||||
^Unable to detect GPU vendor\.$
|
||||
# Qt 5 on CI with WebKit
|
||||
^qglx_findConfig: Failed to finding matching FBConfig for QSurfaceFormat\(version 2\.0, options QFlags<QSurfaceFormat::FormatOption>\(\), depthBufferSize -1, redBufferSize 1, greenBufferSize 1, blueBufferSize 1, alphaBufferSize -1, stencilBufferSize -1, samples -1, swapBehavior QSurfaceFormat::SingleBuffer, swapInterval 1, colorSpace QSurfaceFormat::DefaultColorSpace, profile QSurfaceFormat::NoProfile\)$
|
||||
# Qt 6.8+ debug build
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/8069#issuecomment-2017644465
|
||||
^QObject::connect: Connecting from COMPAT signal \(QWebEnginePage::featurePermissionRequest(ed|Canceled)\(QUrl,QWebEnginePage::Feature\)\)
|
||||
xfail_strict = true
|
||||
filterwarnings =
|
||||
error
|
||||
default:Test process .* failed to terminate!:UserWarning
|
||||
# https://github.com/cucumber/gherkin/commit/2f4830093149eae7ff7bd82f683b3d3bb7320d39
|
||||
# https://github.com/pytest-dev/pytest-bdd/issues/752
|
||||
ignore:'maxsplit' is passed as positional argument:DeprecationWarning:gherkin.gherkin_line
|
||||
# https://github.com/ionelmc/pytest-benchmark/issues/283
|
||||
ignore:FileType is deprecated\. Simply open files after parsing arguments\.:PendingDeprecationWarning:pytest_benchmark.plugin
|
||||
# Python 3.12: https://github.com/ionelmc/pytest-benchmark/issues/240 (fixed but not released)
|
||||
ignore:(datetime\.)?datetime\.utcnow\(\) is deprecated and scheduled for removal in a future version\. Use timezone-aware objects to represent datetimes in UTC. (datetime\.)?datetime\.now\(datetime\.UTC\)\.:DeprecationWarning:pytest_benchmark\.utils
|
||||
faulthandler_timeout = 90
|
||||
xvfb_colordepth = 24
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ _year = datetime.date.today().year
|
|||
|
||||
__author__ = "Florian Bruhin"
|
||||
__copyright__ = "Copyright 2013-{} Florian Bruhin (The Compiler)".format(_year)
|
||||
__license__ = "GPL-3.0-or-later"
|
||||
__license__ = "GPL"
|
||||
__maintainer__ = __author__
|
||||
__email__ = "mail@qutebrowser.org"
|
||||
__version__ = "3.6.3"
|
||||
__version__ = "3.2.1"
|
||||
__version_info__ = tuple(int(part) for part in __version__.split('.'))
|
||||
__description__ = "A keyboard-driven, vim-like browser based on Python and Qt."
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ Possible values:
|
|||
|
||||
|
||||
import inspect
|
||||
from typing import Any, Protocol, Optional, cast
|
||||
from collections.abc import Iterable, Callable
|
||||
from typing import Any, Callable, Iterable, Protocol, Optional, Dict, cast
|
||||
|
||||
from qutebrowser.utils import qtutils
|
||||
from qutebrowser.commands import command, cmdexc
|
||||
|
|
@ -102,7 +101,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:
|
||||
...
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@
|
|||
"""Hooks for extensions."""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
from collections.abc import Callable
|
||||
from typing import Callable, Any
|
||||
|
||||
|
||||
from qutebrowser.extensions import loader
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ import tempfile
|
|||
import pathlib
|
||||
import datetime
|
||||
import argparse
|
||||
from typing import Optional
|
||||
from collections.abc import Iterable
|
||||
from typing import Iterable, Optional, List, Tuple
|
||||
|
||||
from qutebrowser.qt import machinery
|
||||
from qutebrowser.qt.widgets import QApplication, QWidget
|
||||
|
|
@ -331,7 +330,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,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import pathlib
|
|||
import itertools
|
||||
import functools
|
||||
import dataclasses
|
||||
from typing import (cast, TYPE_CHECKING, Any, Optional, Union)
|
||||
from collections.abc import Iterable, Sequence, Callable
|
||||
from typing import (cast, TYPE_CHECKING, Any, Callable, Iterable, List, Optional,
|
||||
Sequence, Set, Type, Union, Tuple)
|
||||
|
||||
from qutebrowser.qt import machinery
|
||||
from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt,
|
||||
|
|
@ -29,7 +29,7 @@ if TYPE_CHECKING:
|
|||
from qutebrowser.keyinput import modeman
|
||||
from qutebrowser.config import config, websettings
|
||||
from qutebrowser.utils import (utils, objreg, usertypes, log, qtutils,
|
||||
urlutils, message, jinja)
|
||||
urlutils, message, jinja, version)
|
||||
from qutebrowser.misc import miscwidgets, objects, sessions
|
||||
from qutebrowser.browser import eventfilter, inspector
|
||||
from qutebrowser.qt import sip
|
||||
|
|
@ -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
|
||||
|
|
@ -1177,6 +1177,37 @@ class AbstractTab(QWidget):
|
|||
navigation.url.errorString()))
|
||||
navigation.accepted = False
|
||||
|
||||
# WORKAROUND for QtWebEngine >= 6.2 not allowing form requests from
|
||||
# qute:// to outside domains.
|
||||
needs_load_workarounds = (
|
||||
objects.backend == usertypes.Backend.QtWebEngine and
|
||||
version.qtwebengine_versions().webengine >= utils.VersionNumber(6, 2)
|
||||
)
|
||||
if (
|
||||
needs_load_workarounds and
|
||||
self.url() == QUrl("qute://start/") and
|
||||
navigation.navigation_type == navigation.Type.form_submitted and
|
||||
navigation.url.matches(
|
||||
QUrl(config.val.url.searchengines['DEFAULT']),
|
||||
urlutils.FormatOption.REMOVE_QUERY)
|
||||
):
|
||||
log.webview.debug(
|
||||
"Working around qute://start loading issue for "
|
||||
f"{navigation.url.toDisplayString()}")
|
||||
navigation.accepted = False
|
||||
self.load_url(navigation.url)
|
||||
|
||||
if (
|
||||
needs_load_workarounds and
|
||||
self.url() == QUrl("qute://bookmarks/") and
|
||||
navigation.navigation_type == navigation.Type.back_forward
|
||||
):
|
||||
log.webview.debug(
|
||||
"Working around qute://bookmarks loading issue for "
|
||||
f"{navigation.url.toDisplayString()}")
|
||||
navigation.accepted = False
|
||||
self.load_url(navigation.url)
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _on_load_finished(self, ok: bool) -> None:
|
||||
assert self._widget is not None
|
||||
|
|
|
|||
|
|
@ -2,15 +2,12 @@
|
|||
#
|
||||
# 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, Union, Optional
|
||||
from collections.abc import Callable
|
||||
from typing import cast, Callable, Dict, Union, Optional
|
||||
|
||||
from qutebrowser.qt.widgets import QApplication, QTabBar
|
||||
from qutebrowser.qt.core import Qt, QUrl, QEvent, QUrlQuery
|
||||
|
|
@ -71,10 +68,7 @@ class CommandDispatcher:
|
|||
|
||||
def _current_index(self):
|
||||
"""Convenience method to get the current widget index."""
|
||||
current_index = self._tabbed_browser.widget.currentIndex()
|
||||
if current_index == -1:
|
||||
raise cmdutils.CommandError("No WebView available yet!")
|
||||
return current_index
|
||||
return self._tabbed_browser.widget.currentIndex()
|
||||
|
||||
def _current_url(self):
|
||||
"""Convenience method to get the current url."""
|
||||
|
|
@ -642,7 +636,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,
|
||||
|
|
@ -704,6 +698,28 @@ class CommandDispatcher:
|
|||
"Numeric argument is too large for internal int "
|
||||
"representation.")
|
||||
|
||||
def _yank_url(self, what):
|
||||
"""Helper method for yank() to get the URL to copy."""
|
||||
assert what in ['url', 'pretty-url'], what
|
||||
|
||||
if what == 'pretty-url':
|
||||
flags = urlutils.FormatOption.DECODE_RESERVED
|
||||
else:
|
||||
flags = urlutils.FormatOption.ENCODED
|
||||
flags |= urlutils.FormatOption.REMOVE_PASSWORD
|
||||
|
||||
url = QUrl(self._current_url())
|
||||
url_query = QUrlQuery()
|
||||
url_query_str = url.query()
|
||||
if '&' not in url_query_str and ';' in url_query_str:
|
||||
url_query.setQueryDelimiters('=', ';')
|
||||
url_query.setQuery(url_query_str)
|
||||
for key in dict(url_query.queryItems()):
|
||||
if key in config.val.url.yank_ignored_parameters:
|
||||
url_query.removeQueryItem(key)
|
||||
url.setQuery(url_query)
|
||||
return url.toString(flags)
|
||||
|
||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||
@cmdutils.argument('what', choices=['selection', 'url', 'pretty-url',
|
||||
'title', 'domain', 'inline'])
|
||||
|
|
@ -738,9 +754,7 @@ class CommandDispatcher:
|
|||
self._current_url().host(),
|
||||
':' + str(port) if port > -1 else '')
|
||||
elif what in ['url', 'pretty-url']:
|
||||
url = self._current_url()
|
||||
pretty = what == 'pretty-url'
|
||||
s = urlutils.get_url_yank_text(url, pretty=pretty)
|
||||
s = self._yank_url(what)
|
||||
what = 'URL' # For printing
|
||||
elif what == 'selection':
|
||||
def _selection_callback(s):
|
||||
|
|
@ -868,6 +882,10 @@ class CommandDispatcher:
|
|||
Args:
|
||||
count: How many tabs to switch back.
|
||||
"""
|
||||
if self._count() == 0:
|
||||
# Running :tab-prev after last tab was closed
|
||||
# See https://github.com/qutebrowser/qutebrowser/issues/1448
|
||||
return
|
||||
newidx = self._current_index() - count
|
||||
if newidx >= 0:
|
||||
self._set_current_index(newidx)
|
||||
|
|
@ -884,6 +902,10 @@ class CommandDispatcher:
|
|||
Args:
|
||||
count: How many tabs to switch forward.
|
||||
"""
|
||||
if self._count() == 0:
|
||||
# Running :tab-next after last tab was closed
|
||||
# See https://github.com/qutebrowser/qutebrowser/issues/1448
|
||||
return
|
||||
newidx = self._current_index() + count
|
||||
if newidx < self._count():
|
||||
self._set_current_index(newidx)
|
||||
|
|
@ -1134,7 +1156,8 @@ class CommandDispatcher:
|
|||
else:
|
||||
cmd = os.path.expanduser(cmd)
|
||||
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
|
||||
output_messages=output_messages)
|
||||
output_messages=output_messages,
|
||||
parent=self._tabbed_browser)
|
||||
if detach:
|
||||
ok = proc.start_detached(cmd, args)
|
||||
if not ok:
|
||||
|
|
@ -1163,7 +1186,7 @@ class CommandDispatcher:
|
|||
if count is not None:
|
||||
env['QUTE_COUNT'] = str(count)
|
||||
|
||||
idx = self._tabbed_browser.widget.currentIndex()
|
||||
idx = self._current_index()
|
||||
if idx != -1:
|
||||
env['QUTE_TAB_INDEX'] = str(idx + 1)
|
||||
env['QUTE_TITLE'] = self._tabbed_browser.widget.page_title(idx)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ import functools
|
|||
import pathlib
|
||||
import tempfile
|
||||
import enum
|
||||
from typing import Any, IO, Optional, Union
|
||||
from collections.abc import MutableSequence
|
||||
from typing import Any, Dict, IO, List, MutableSequence, Optional, Union
|
||||
|
||||
from qutebrowser.qt.core import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
|
||||
QTimer, QAbstractListModel, QUrl)
|
||||
|
|
@ -188,22 +187,15 @@ def transform_path(path):
|
|||
"""
|
||||
if not utils.is_windows:
|
||||
return path
|
||||
|
||||
path = utils.expand_windows_drive(path)
|
||||
# Drive dependent working directories are not supported, e.g.
|
||||
# E:filename is invalid
|
||||
if re.search(r'^[A-Z]:[^\\]', path, re.IGNORECASE):
|
||||
return None
|
||||
|
||||
# Paths like COM1, ...
|
||||
# See https://github.com/qutebrowser/qutebrowser/issues/82
|
||||
if sys.version_info[:2] >= (3, 13):
|
||||
if os.path.isreserved(path): # pylint: disable=no-member
|
||||
return None
|
||||
else:
|
||||
if pathlib.Path(path).is_reserved(): # pylint: disable=else-if-used
|
||||
return None
|
||||
|
||||
if pathlib.Path(path).is_reserved():
|
||||
return None
|
||||
return path
|
||||
|
||||
|
||||
|
|
@ -455,7 +447,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
|
||||
|
|
@ -907,7 +899,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)
|
||||
|
|
@ -1272,7 +1264,7 @@ class DownloadModel(QAbstractListModel):
|
|||
else:
|
||||
return ""
|
||||
|
||||
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> Any:
|
||||
def data(self, index, role):
|
||||
"""Download data from DownloadManager."""
|
||||
if not index.isValid():
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
"""The ListView to display downloads in."""
|
||||
|
||||
import functools
|
||||
from typing import Union
|
||||
from collections.abc import MutableSequence, Callable
|
||||
from typing import Callable, MutableSequence, Tuple, Union
|
||||
|
||||
from qutebrowser.qt.core import pyqtSlot, QSize, Qt
|
||||
from qutebrowser.qt.widgets import QListView, QSizePolicy, QMenu, QStyleFactory
|
||||
|
|
@ -18,8 +17,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]],
|
||||
]
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@
|
|||
|
||||
from qutebrowser.qt import machinery
|
||||
from qutebrowser.qt.core import QObject, QEvent, Qt, QTimer
|
||||
from qutebrowser.qt.gui import QKeyEvent
|
||||
from qutebrowser.qt.widgets import QWidget
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import log, message, usertypes, qtutils, version, utils
|
||||
from qutebrowser.keyinput import modeman, keyutils
|
||||
from qutebrowser.utils import log, message, usertypes, qtutils
|
||||
from qutebrowser.keyinput import modeman
|
||||
|
||||
|
||||
class ChildEventFilter(QObject):
|
||||
|
|
@ -38,8 +37,8 @@ class ChildEventFilter(QObject):
|
|||
if event.type() == QEvent.Type.ChildAdded:
|
||||
child = event.child()
|
||||
if not isinstance(child, QWidget):
|
||||
# Can e.g. happen when dragging text, or accessibility tree
|
||||
# nodes since Qt 6.9
|
||||
# Can e.g. happen when dragging text
|
||||
log.misc.debug(f"Ignoring new child {qtutils.qobj_repr(child)}")
|
||||
return False
|
||||
|
||||
log.misc.debug(
|
||||
|
|
@ -55,30 +54,21 @@ class ChildEventFilter(QObject):
|
|||
# - This is a child event filter on a tab (self._widget is not None)
|
||||
# - We find an old existing child which is a QQuickWidget and is
|
||||
# currently focused.
|
||||
# - We're using an affected QtWebEngine version
|
||||
# - We're using QtWebEngine >= 6.4 (older versions are not affected)
|
||||
children = [
|
||||
c for c in self._widget.findChildren(
|
||||
QWidget, "", Qt.FindChildOption.FindDirectChildrenOnly)
|
||||
if c is not child and
|
||||
c.hasFocus() and
|
||||
c.metaObject() is not None and
|
||||
c.metaObject().className() == "QQuickWidget" # Qt 6.4+
|
||||
c.metaObject().className() == "QQuickWidget"
|
||||
]
|
||||
if children and version.qtwebengine_versions().webengine < utils.VersionNumber(6, 6, 3):
|
||||
if children:
|
||||
log.misc.debug("Focusing new child")
|
||||
child.setFocus()
|
||||
|
||||
child.installEventFilter(self._filter)
|
||||
elif event.type() == QEvent.Type.ChildRemoved:
|
||||
if isinstance(event, QKeyEvent):
|
||||
# WORKAROUND for unknown (Py)Qt bug
|
||||
info = keyutils.KeyInfo.from_event(event)
|
||||
log.misc.warning(
|
||||
f"ChildEventFilter: ignoring key event {info} "
|
||||
f"on {qtutils.qobj_repr(obj)}"
|
||||
)
|
||||
return False
|
||||
|
||||
child = event.child()
|
||||
log.misc.debug(
|
||||
f"{qtutils.qobj_repr(obj)}: removed child {qtutils.qobj_repr(child)}")
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import functools
|
|||
import glob
|
||||
import textwrap
|
||||
import dataclasses
|
||||
from typing import cast, Optional
|
||||
from collections.abc import Sequence
|
||||
from typing import cast, List, Sequence, Tuple, Optional
|
||||
|
||||
from qutebrowser.qt.core import pyqtSignal, QObject, QUrl
|
||||
|
||||
|
|
@ -208,9 +207,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
|
||||
|
|
@ -218,8 +217,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.
|
||||
|
|
@ -295,10 +294,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.
|
||||
|
|
|
|||
|
|
@ -12,15 +12,8 @@ import html
|
|||
import enum
|
||||
import dataclasses
|
||||
from string import ascii_lowercase
|
||||
from typing import (TYPE_CHECKING, Optional)
|
||||
from collections.abc import (
|
||||
Iterable,
|
||||
Iterator,
|
||||
Mapping,
|
||||
MutableSequence,
|
||||
Sequence,
|
||||
Callable,
|
||||
)
|
||||
from typing import (TYPE_CHECKING, Callable, Dict, Iterable, Iterator, List, Mapping,
|
||||
MutableSequence, Optional, Sequence, Set)
|
||||
|
||||
from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, Qt, QUrl
|
||||
from qutebrowser.qt.widgets import QLabel
|
||||
|
|
@ -182,11 +175,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
|
||||
|
|
@ -244,7 +237,11 @@ class HintActions:
|
|||
sel = (context.target == Target.yank_primary and
|
||||
utils.supports_selection())
|
||||
|
||||
urlstr = urlutils.get_url_yank_text(url, pretty=False)
|
||||
flags = urlutils.FormatOption.ENCODED | urlutils.FormatOption.REMOVE_PASSWORD
|
||||
if url.scheme() == 'mailto':
|
||||
flags |= urlutils.FormatOption.REMOVE_SCHEME
|
||||
urlstr = url.toString(flags)
|
||||
|
||||
new_content = urlstr
|
||||
|
||||
# only second and consecutive yanks are to append to the clipboard
|
||||
|
|
@ -1040,7 +1037,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:
|
||||
|
|
@ -1150,7 +1147,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)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import os
|
|||
import time
|
||||
import contextlib
|
||||
import pathlib
|
||||
from typing import cast, Optional
|
||||
from collections.abc import Mapping, MutableSequence
|
||||
from typing import cast, Mapping, MutableSequence, Optional
|
||||
|
||||
from qutebrowser.qt import machinery
|
||||
from qutebrowser.qt.core import pyqtSlot, QUrl, QObject, pyqtSignal
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import re
|
||||
import posixpath
|
||||
from typing import Optional
|
||||
from typing import Optional, Set
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ class PACFetcher(QObject):
|
|||
pac_prefix = "pac+"
|
||||
|
||||
assert url.scheme().startswith(pac_prefix)
|
||||
url.setScheme(url.scheme().removeprefix(pac_prefix))
|
||||
url.setScheme(url.scheme()[len(pac_prefix):])
|
||||
|
||||
self._pac_url = url
|
||||
with qtlog.disable_qt_msghandler():
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
from typing import Optional
|
||||
|
||||
from qutebrowser.qt.core import QUrl, pyqtSlot
|
||||
from qutebrowser.qt.network import QNetworkProxy, QNetworkProxyFactory, QNetworkProxyQuery
|
||||
from qutebrowser.qt.network import QNetworkProxy, QNetworkProxyFactory
|
||||
|
||||
from qutebrowser.config import config, configtypes
|
||||
from qutebrowser.utils import message, usertypes, urlutils, utils, qtutils
|
||||
|
|
@ -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):
|
||||
"""Get the QNetworkProxies for a query.
|
||||
|
||||
Args:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from qutebrowser.qt.core import QUrl, QUrlQuery
|
|||
|
||||
from qutebrowser.utils import resources, javascript, jinja, standarddir, log, urlutils
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.misc import objects
|
||||
|
||||
|
||||
_SYSTEM_PATHS = [
|
||||
|
|
@ -70,8 +69,19 @@ def generate_pdfjs_page(filename, url):
|
|||
return html
|
||||
|
||||
|
||||
def _get_polyfills() -> str:
|
||||
return resources.read_file("javascript/pdfjs_polyfills.js")
|
||||
def _generate_polyfills():
|
||||
return """
|
||||
if (typeof Promise.withResolvers === 'undefined') {
|
||||
Promise.withResolvers = function () {
|
||||
let resolve, reject
|
||||
const promise = new Promise((res, rej) => {
|
||||
resolve = res
|
||||
reject = rej
|
||||
})
|
||||
return { promise, resolve, reject }
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def _generate_pdfjs_script(filename):
|
||||
|
|
@ -111,7 +121,7 @@ def _generate_pdfjs_script(filename):
|
|||
});
|
||||
}
|
||||
});
|
||||
""").render(url=js_url, polyfills=_get_polyfills())
|
||||
""").render(url=js_url, polyfills=_generate_polyfills())
|
||||
|
||||
|
||||
def get_pdfjs_res_and_path(path):
|
||||
|
|
@ -128,12 +138,7 @@ def get_pdfjs_res_and_path(path):
|
|||
content = None
|
||||
file_path = None
|
||||
|
||||
if 'no-system-pdfjs' in objects.debug_flags:
|
||||
system_paths = []
|
||||
else:
|
||||
system_paths = _SYSTEM_PATHS[:]
|
||||
|
||||
system_paths += [
|
||||
system_paths = _SYSTEM_PATHS + [
|
||||
# fallback
|
||||
os.path.join(standarddir.data(), 'pdfjs'),
|
||||
# hardcoded fallback for --temp-basedir
|
||||
|
|
@ -163,7 +168,7 @@ def get_pdfjs_res_and_path(path):
|
|||
if path == "build/pdf.worker.mjs":
|
||||
content = b"\n".join(
|
||||
[
|
||||
_get_polyfills().encode("ascii"),
|
||||
_generate_polyfills().encode("ascii"),
|
||||
content,
|
||||
]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import os.path
|
|||
import shutil
|
||||
import functools
|
||||
import dataclasses
|
||||
from typing import IO, Optional
|
||||
from typing import Dict, 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
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ import textwrap
|
|||
import urllib
|
||||
import collections
|
||||
import secrets
|
||||
from typing import TypeVar, Optional, Union
|
||||
from collections.abc import Sequence, Callable
|
||||
from typing import TypeVar, Callable, Dict, List, Optional, Union, Sequence, Tuple
|
||||
|
||||
from qutebrowser.qt.core import QUrlQuery, QUrl
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ pyeval_output = ":pyeval was never called"
|
|||
csrf_token: Optional[str] = None
|
||||
|
||||
|
||||
_HANDLERS: dict[str, "_HandlerCallable"] = {}
|
||||
_HANDLERS: Dict[str, "_HandlerCallable"] = {}
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
|
|
@ -78,7 +77,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)
|
||||
|
||||
|
|
@ -106,7 +105,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:
|
||||
|
|
@ -123,24 +122,25 @@ def data_for_url(url: QUrl) -> tuple[str, bytes]:
|
|||
|
||||
path = url.path()
|
||||
host = url.host()
|
||||
query = url.query()
|
||||
# A url like "qute:foo" is split as "scheme:path", not "scheme:host".
|
||||
log.misc.debug("url: {}, path: {}, host {}".format(
|
||||
url.toDisplayString(), path, host))
|
||||
if not path or not host:
|
||||
new_url = QUrl()
|
||||
new_url.setScheme('qute')
|
||||
# When path is absent, e.g. qute://help (with no trailing slash)
|
||||
if host:
|
||||
new_url.setHost(host)
|
||||
# When host is absent, e.g. qute:help
|
||||
else:
|
||||
new_url.setHost(path)
|
||||
|
||||
if not host:
|
||||
# Redirect qute:help -> qute://help/
|
||||
new_url = QUrl(url)
|
||||
new_url.setHost(path)
|
||||
new_url.setPath('/')
|
||||
if not new_url.host(): # Valid path but not valid host
|
||||
raise UrlInvalidError(f"Invalid host (from path): {path!r}")
|
||||
raise Redirect(new_url)
|
||||
|
||||
if not path:
|
||||
# Redirect qute://help -> qute://help/
|
||||
new_url = QUrl(url)
|
||||
new_url.setPath('/')
|
||||
raise Redirect(new_url)
|
||||
if query:
|
||||
new_url.setQuery(query)
|
||||
if new_url.host(): # path was a valid host
|
||||
raise Redirect(new_url)
|
||||
|
||||
try:
|
||||
handler = _HANDLERS[host]
|
||||
|
|
@ -180,7 +180,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 +201,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:
|
||||
|
|
|
|||
|
|
@ -10,12 +10,11 @@ import html
|
|||
import enum
|
||||
import netrc
|
||||
import tempfile
|
||||
from typing import Optional
|
||||
from collections.abc import Mapping, Iterable, Iterator, Callable
|
||||
from typing import Callable, Mapping, List, Optional, Iterable, Iterator
|
||||
|
||||
from qutebrowser.qt.core import QUrl, pyqtBoundSignal
|
||||
|
||||
from qutebrowser.config import config, configtypes
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import (usertypes, message, log, objreg, jinja, utils,
|
||||
qtutils, version, urlutils)
|
||||
from qutebrowser.mainwindow import mainwindow
|
||||
|
|
@ -26,15 +25,8 @@ class CallSuper(Exception):
|
|||
"""Raised when the caller should call the superclass instead."""
|
||||
|
||||
|
||||
def custom_headers(
|
||||
url: QUrl, *, fallback_accept_language: bool = True
|
||||
) -> list[tuple[bytes, bytes]]:
|
||||
"""Get the combined custom headers.
|
||||
|
||||
Arguments:
|
||||
fallback_accept_language: Whether to include the global (rather than
|
||||
per-domain override) accept language header as well.
|
||||
"""
|
||||
def custom_headers(url):
|
||||
"""Get the combined custom headers."""
|
||||
headers = {}
|
||||
|
||||
dnt_config = config.instance.get('content.headers.do_not_track', url=url)
|
||||
|
|
@ -48,17 +40,9 @@ def custom_headers(
|
|||
encoded_value = b"" if value is None else value.encode('ascii')
|
||||
headers[encoded_header] = encoded_value
|
||||
|
||||
# On QtWebEngine, we have fallback_accept_language set to False here for XHR
|
||||
# requests, so that we don't end up overriding headers that are set via the XHR API.
|
||||
#
|
||||
# The global Accept-Language header is set via
|
||||
# QWebEngineProfile::setHttpAcceptLanguage already anyways, so we only need
|
||||
# to take care of URL pattern overrides here.
|
||||
#
|
||||
# note: Once we drop QtWebKit, we could hardcode fallback_accept_language to False.
|
||||
accept_language = config.instance.get('content.headers.accept_language',
|
||||
url=url, fallback=fallback_accept_language)
|
||||
if accept_language is not None and not isinstance(accept_language, usertypes.Unset):
|
||||
url=url)
|
||||
if accept_language is not None:
|
||||
headers[b'Accept-Language'] = accept_language.encode('ascii')
|
||||
|
||||
return sorted(headers.items())
|
||||
|
|
@ -319,7 +303,6 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on,
|
|||
None otherwise.
|
||||
"""
|
||||
config_val = config.instance.get(option, url=url)
|
||||
opt = config.instance.get_opt(option)
|
||||
if config_val == 'ask':
|
||||
if url.isValid():
|
||||
urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded)
|
||||
|
|
@ -345,21 +328,12 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on,
|
|||
cancel_action=no_action, abort_on=abort_on,
|
||||
title='Permission request', text=text, url=urlstr,
|
||||
option=option)
|
||||
|
||||
if isinstance(opt.typ, configtypes.AsBool):
|
||||
config_val = opt.typ.to_bool(config_val)
|
||||
|
||||
if config_val is True:
|
||||
elif config_val:
|
||||
yes_action()
|
||||
return None
|
||||
elif config_val is False:
|
||||
else:
|
||||
no_action()
|
||||
return None
|
||||
else:
|
||||
raise AssertionError(
|
||||
f"Unsupported value for permission prompt setting ({option}), expected boolean or "
|
||||
f"'ask', got: {config_val} ({type(config_val)})"
|
||||
)
|
||||
|
||||
|
||||
def get_tab(win_id, target):
|
||||
|
|
@ -471,7 +445,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:
|
||||
|
|
@ -511,10 +485,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:
|
||||
|
|
@ -548,7 +522,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.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import os.path
|
|||
import html
|
||||
import functools
|
||||
import collections
|
||||
from collections.abc import MutableMapping
|
||||
from typing import MutableMapping
|
||||
|
||||
from qutebrowser.qt.core import pyqtSignal, QUrl, QObject
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
"""Generic web element related code."""
|
||||
|
||||
from typing import Optional, TYPE_CHECKING, Union
|
||||
from collections.abc import Iterator
|
||||
from typing import Iterator, Optional, Set, TYPE_CHECKING, Union, Dict
|
||||
import collections.abc
|
||||
|
||||
from qutebrowser.qt import machinery
|
||||
|
|
@ -23,9 +22,9 @@ if TYPE_CHECKING:
|
|||
JsValueType = Union[int, float, str, None]
|
||||
|
||||
if machinery.IS_QT6:
|
||||
KeyboardModifierType = Qt.KeyboardModifier
|
||||
KeybordModifierType = Qt.KeyboardModifier
|
||||
else:
|
||||
KeyboardModifierType = Union[Qt.KeyboardModifiers, Qt.KeyboardModifier]
|
||||
KeybordModifierType = Union[Qt.KeyboardModifiers, Qt.KeyboardModifier]
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
|
|
@ -94,7 +93,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
|
||||
|
||||
|
|
@ -337,7 +336,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, KeybordModifierType] = {
|
||||
usertypes.ClickTarget.normal: Qt.KeyboardModifier.NoModifier,
|
||||
usertypes.ClickTarget.window: Qt.KeyboardModifier.AltModifier | Qt.KeyboardModifier.ShiftModifier,
|
||||
usertypes.ClickTarget.tab: Qt.KeyboardModifier.ControlModifier,
|
||||
|
|
|
|||
|
|
@ -125,8 +125,8 @@ import copy
|
|||
import enum
|
||||
import dataclasses
|
||||
import collections
|
||||
from typing import (Any, Optional, Union)
|
||||
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
|
||||
from typing import (Any, Iterator, Mapping, MutableMapping, Optional, Set, Tuple, Union,
|
||||
Sequence, List)
|
||||
|
||||
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.removeprefix(blink_settings_flag).split(','):
|
||||
for pair in flag[len(blink_settings_flag):].split(','):
|
||||
key, val = pair.split('=', maxsplit=1)
|
||||
result[_BLINK_SETTINGS].append((key, val))
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor):
|
|||
}
|
||||
new_types = {
|
||||
"WebSocket": interceptors.ResourceType.websocket, # added in Qt 6.4
|
||||
"Json": interceptors.ResourceType.json, # added in Qt 6.8
|
||||
}
|
||||
for qt_name, qb_value in new_types.items():
|
||||
qt_value = getattr(
|
||||
|
|
@ -188,9 +187,7 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor):
|
|||
if request.is_blocked:
|
||||
info.block(True)
|
||||
|
||||
for header, value in shared.custom_headers(
|
||||
url=url, fallback_accept_language=not is_xhr
|
||||
):
|
||||
for header, value in shared.custom_headers(url=url):
|
||||
if header.lower() == b'accept' and is_xhr:
|
||||
# https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader
|
||||
# says: "If no Accept header has been set using this, an Accept header
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ import dataclasses
|
|||
import itertools
|
||||
import functools
|
||||
import subprocess
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
from collections.abc import Iterator
|
||||
from typing import Any, List, Dict, Optional, Iterator, Type, TYPE_CHECKING
|
||||
|
||||
from qutebrowser.qt import machinery
|
||||
from qutebrowser.qt.core import (Qt, QObject, QVariant, QMetaType, QByteArray, pyqtSlot,
|
||||
|
|
@ -196,7 +195,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)
|
||||
|
|
@ -233,8 +232,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,
|
||||
|
|
@ -286,10 +285,7 @@ class NotificationBridgePresenter(QObject):
|
|||
|
||||
if replaces_id is None:
|
||||
if notification_id in self._active_notifications:
|
||||
message.error(f"Got duplicate notification id {notification_id} "
|
||||
f"from {self._adapter.NAME}")
|
||||
self._drop_adapter()
|
||||
return
|
||||
raise Error(f"Got duplicate id {notification_id}")
|
||||
|
||||
qt_notification.show()
|
||||
self._active_notifications[notification_id] = qt_notification
|
||||
|
|
@ -669,7 +665,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,
|
||||
|
|
@ -955,10 +951,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,
|
||||
|
|
@ -988,7 +984,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."""
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue