diff options
author | Florian Bruhin <me@the-compiler.org> | 2023-11-22 09:17:43 +0100 |
---|---|---|
committer | Florian Bruhin <me@the-compiler.org> | 2023-11-22 09:17:43 +0100 |
commit | ab198177bdd492cdb926651dfbc30256f01fc6af (patch) | |
tree | a9649263c7338133dbc2e52e8c2aef6ab828056f | |
parent | 7b6cda95fb70a177bfaf7c4cee89e82cf485d938 (diff) | |
parent | 723a5db8f2986197e8179b4cc2143da2410b0a66 (diff) | |
download | qutebrowser-ab198177bdd492cdb926651dfbc30256f01fc6af.tar.gz qutebrowser-ab198177bdd492cdb926651dfbc30256f01fc6af.zip |
Merge branch 'main' into pakjoy
40 files changed, 329 insertions, 206 deletions
diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 8b83ca8bf..051e07b87 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.0.1 +current_version = 3.0.2 commit = True message = Release v{new_version} tag = True diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d7963ea7..c2babf437 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3.10' - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: '16.x' if: "matrix.testenv == 'eslint'" @@ -157,28 +157,28 @@ jobs: - testenv: py310-pyqt65 os: ubuntu-22.04 python: "3.10" - ### PyQt 6.5 (Python 3.11) - - testenv: py311-pyqt65 + ### PyQt 6.6 (Python 3.11) + - testenv: py311-pyqt66 os: ubuntu-22.04 python: "3.11" - ### PyQt 6.5 (Python 3.12) - - testenv: py312-pyqt65 + ### PyQt 6.6 (Python 3.12) + - testenv: py312-pyqt66 os: ubuntu-22.04 - python: "3.12-dev" - ### macOS Big Sur: PyQt 5.15 (Python 3.9 to match PyInstaller env) - - testenv: py39-pyqt515 + python: "3.12" + ### macOS Big Sur + - testenv: py311-pyqt66 os: macos-11 - python: "3.9" + python: "3.11" args: "tests/unit" # Only run unit tests on macOS ### macOS Monterey - - testenv: py39-pyqt515 + - testenv: py311-pyqt66 os: macos-12 - python: "3.9" + python: "3.11" args: "tests/unit" # Only run unit tests on macOS - ### Windows: PyQt 5.15 (Python 3.9 to match PyInstaller env) - - testenv: py39-pyqt515 + ### Windows + - testenv: py311-pyqt66 os: windows-2019 - python: "3.9" + python: "3.11" runs-on: "${{ matrix.os }}" steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 76332e8ba..433cd3c0b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -15,24 +15,19 @@ jobs: matrix: include: - os: macos-11 - branch: main toxenv: build-release-qt5 name: qt5-macos - os: windows-2019 - branch: main toxenv: build-release-qt5 name: qt5-windows - os: macos-11 args: --debug - branch: main toxenv: build-release-qt5 name: qt5-macos-debug - os: windows-2019 args: --debug - branch: main toxenv: build-release-qt5 name: qt5-windows-debug - - os: macos-11 toxenv: build-release name: macos @@ -52,7 +47,6 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: "${{ matrix.branch }}" persist-credentials: false - name: Set up Python uses: actions/setup-python@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 786f9742c..fd3bc5cd8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,7 +34,7 @@ jobs: contents: write # To push release commit/tag steps: - name: Find release branch - uses: actions/github-script@v6 + uses: actions/github-script@v7 id: find-branch with: script: | @@ -84,7 +84,7 @@ jobs: id: bump run: "tox -e update-version -- ${{ github.event.inputs.release_type }}" - name: Check milestone - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const milestones = await github.paginate(github.rest.issues.listMilestones, { @@ -178,7 +178,7 @@ jobs: contents: write # To change release steps: - name: Publish final release - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | await github.rest.repos.updateRelease({ diff --git a/README.asciidoc b/README.asciidoc index 2b6bdfdd6..364f8fa62 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -227,7 +227,7 @@ Active https://tridactyl.xyz/[Tridactyl], https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/[Vimium-FF] * Addons for Firefox and Chrome: - https://github.com/brookhong/Surfingkeys[Surfingkeys], + https://github.com/brookhong/Surfingkeys[Surfingkeys] (https://github.com/brookhong/Surfingkeys/issues/1796[somewhat sketchy]...), https://lydell.github.io/LinkHints/[Link Hints] (hinting only), https://github.com/ueokande/vimmatic[Vimmatic] diff --git a/doc/backers.asciidoc b/doc/backers.asciidoc index bdabb5f96..81ccc14ab 100644 --- a/doc/backers.asciidoc +++ b/doc/backers.asciidoc @@ -1,6 +1,14 @@ Crowdfunding backers ==================== +2019+ +----- + +Since late 2019, qutebrowser is taking recurring donations via +https://github.com/sponsors/The-Compiler/[GitHub Sponsors] and +https://liberapay.com/The-Compiler/[Liberapay]. You can find Sponsors/Patrons +who opted to be listed as public on the respective pages. **Thank you!** + 2017 ---- diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index db4014be5..a799deaab 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -16,7 +16,7 @@ breaking changes (such as renamed commands) can happen in minor releases. // `Security` to invite users to upgrade in case of vulnerabilities. [[v3.0.2]] -v3.0.2 (unreleased) +v3.0.2 (2023-10-19) ------------------- Fixed diff --git a/doc/contributing.asciidoc b/doc/contributing.asciidoc index 0be2655c5..144117677 100644 --- a/doc/contributing.asciidoc +++ b/doc/contributing.asciidoc @@ -575,35 +575,46 @@ Chrome URLs ~~~~~~~~~~~ With the QtWebEngine backend, qutebrowser supports several chrome:// urls which -can be useful for debugging: +can be useful for debugging. -- chrome://accessibility/ -- chrome://appcache-internals/ -- chrome://blob-internals/ -- chrome://conversion-internals/ (QtWebEngine 5.15.3+) -- chrome://crash/ (crashes the current renderer process!) +Info pages: + +- chrome://device-log/ (QtWebEngine >= 6.3) - chrome://gpu/ -- chrome://gpuclean/ (crashes the current renderer process!) -- chrome://gpucrash/ (crashes qutebrowser!) -- chrome://gpuhang/ (hangs qutebrowser!) +- chrome://sandbox/ (Linux only) + +Misc. / Debugging pages: + +- chrome://dino/ - chrome://histograms/ +- chrome://network-errors/ +- chrome://tracing/ (QtWebEngine >= 5.15.3) +- chrome://ukm/ (QtWebEngine >= 5.15.3) +- chrome://user-actions/ (QtWebEngine >= 5.15.3) +- chrome://webrtc-logs/ (QtWebEngine >= 5.15.3) + +Internals pages: + +- chrome://accessibility/ +- chrome://appcache-internals/ (QtWebEngine < 6.4) +- chrome://attribution-internals/ (QtWebEngine >= 6.4) +- chrome://blob-internals/ +- chrome://conversion-internals/ (QtWebEngine >= 5.15.3 and < 6.4) - chrome://indexeddb-internals/ -- chrome://kill/ (kills the current renderer process!) - chrome://media-internals/ -- chrome://net-internals/ (QtWebEngine 5.15.4+) -- chrome://network-errors/ -- chrome://ppapiflashcrash/ -- chrome://ppapiflashhang/ +- chrome://net-internals/ (QtWebEngine >= 5.15.4) - chrome://process-internals/ - chrome://quota-internals/ -- chrome://sandbox/ (Linux only) - chrome://serviceworker-internals/ -- chrome://taskscheduler-internals/ (removed in QtWebEngine 5.14) -- chrome://tracing/ (QtWebEngine 5.15.3+) -- chrome://ukm/ (QtWebEngine 5.15.3+) -- chrome://user-actions/ (QtWebEngine 5.15.3+) - chrome://webrtc-internals/ -- chrome://webrtc-logs/ (QtWebEngine 5.15.3+) + +Crash/hang pages: + +- chrome://crash/ (crashes the current renderer process!) +- chrome://gpuclean/ (crashes the current renderer process!) +- chrome://gpucrash/ (crashes qutebrowser!) +- chrome://gpuhang/ (hangs qutebrowser!) +- chrome://kill/ (kills the current renderer process!) QtWebEngine internals ~~~~~~~~~~~~~~~~~~~~~ diff --git a/misc/org.qutebrowser.qutebrowser.appdata.xml b/misc/org.qutebrowser.qutebrowser.appdata.xml index 6dabaa36b..477a8194c 100644 --- a/misc/org.qutebrowser.qutebrowser.appdata.xml +++ b/misc/org.qutebrowser.qutebrowser.appdata.xml @@ -44,6 +44,7 @@ </content_rating> <releases> <!-- Add new releases here --> +<release version="3.0.2" date="2023-10-19"/> <release version="3.0.1" date="2023-10-19"/> <release version="3.0.0" date="2023-08-18"/> <release version="2.5.4" date="2023-03-13"/> diff --git a/misc/qutebrowser.spec b/misc/qutebrowser.spec index ecb9da68e..652f69bfb 100644 --- a/misc/qutebrowser.spec +++ b/misc/qutebrowser.spec @@ -100,6 +100,11 @@ else: DEBUG = os.environ.get('PYINSTALLER_DEBUG', '').lower() in ['1', 'true'] +if DEBUG: + options = options = [('v', None, 'OPTION')] +else: + options = [] + a = Analysis(['../qutebrowser/__main__.py'], @@ -117,6 +122,7 @@ pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, + options, exclude_binaries=True, name='qutebrowser', icon=icon, diff --git a/misc/requirements/requirements-dev.txt b/misc/requirements/requirements-dev.txt index 65adceac5..df7c7b847 100644 --- a/misc/requirements/requirements-dev.txt +++ b/misc/requirements/requirements-dev.txt @@ -2,19 +2,19 @@ build==1.0.3 bump2version==1.0.1 -certifi==2023.7.22 +certifi==2023.11.17 cffi==1.16.0 -charset-normalizer==3.3.0 -cryptography==41.0.4 +charset-normalizer==3.3.2 +cryptography==41.0.5 docutils==0.20.1 github3.py==4.0.1 hunter==3.6.1 idna==3.4 importlib-metadata==6.8.0 -importlib-resources==6.1.0 +importlib-resources==6.1.1 jaraco.classes==3.3.0 jeepney==0.8.0 -keyring==24.2.0 +keyring==24.3.0 manhole==1.8.0 markdown-it-py==3.0.0 mdurl==0.1.2 @@ -24,7 +24,7 @@ packaging==23.2 pkginfo==1.9.6 ply==3.11 pycparser==2.21 -Pygments==2.16.1 +Pygments==2.17.1 PyJWT==2.8.0 Pympler==1.0.1 pyproject_hooks==1.0.0 @@ -34,7 +34,7 @@ readme-renderer==42.0 requests==2.31.0 requests-toolbelt==1.0.0 rfc3986==2.0.0 -rich==13.6.0 +rich==13.7.0 SecretStorage==3.3.3 sip==6.7.12 six==1.16.0 @@ -42,5 +42,5 @@ tomli==2.0.1 twine==4.0.2 typing_extensions==4.8.0 uritemplate==4.1.1 -# urllib3==2.0.6 +# urllib3==2.1.0 zipp==3.17.0 diff --git a/misc/requirements/requirements-flake8.txt b/misc/requirements/requirements-flake8.txt index 95a9cb382..6995f7ac5 100644 --- a/misc/requirements/requirements-flake8.txt +++ b/misc/requirements/requirements-flake8.txt @@ -3,10 +3,10 @@ attrs==23.1.0 flake8==6.1.0 flake8-bugbear==23.9.16 -flake8-builtins==2.1.0 +flake8-builtins==2.2.0 flake8-comprehensions==3.14.0 flake8-debugger==4.1.2 -flake8-deprecated==2.1.0 +flake8-deprecated==2.2.1 flake8-docstrings==1.7.0 flake8-future-import==0.4.7 flake8-plugin-utils==1.3.3 diff --git a/misc/requirements/requirements-mypy.txt b/misc/requirements/requirements-mypy.txt index 418611aae..f1d5c8bdf 100644 --- a/misc/requirements/requirements-mypy.txt +++ b/misc/requirements/requirements-mypy.txt @@ -1,21 +1,21 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py chardet==5.2.0 -diff_cover==8.0.0 -importlib-resources==6.1.0 +diff_cover==8.0.1 +importlib-resources==6.1.1 Jinja2==3.1.2 lxml==4.9.3 MarkupSafe==2.1.3 -mypy==1.6.0 +mypy==1.7.0 mypy-extensions==1.0.0 pluggy==1.3.0 -Pygments==2.16.1 +Pygments==2.17.1 PyQt5-stubs==5.15.6.0 tomli==2.0.1 types-colorama==0.4.15.12 types-docutils==0.20.0.3 -types-Pygments==2.16.0.0 +types-Pygments==2.16.0.1 types-PyYAML==6.0.12.12 -types-setuptools==68.2.0.0 +types-setuptools==68.2.0.1 typing_extensions==4.8.0 zipp==3.17.0 diff --git a/misc/requirements/requirements-pyinstaller.txt b/misc/requirements/requirements-pyinstaller.txt index 84f35ea61..d1a2c18c9 100644 --- a/misc/requirements/requirements-pyinstaller.txt +++ b/misc/requirements/requirements-pyinstaller.txt @@ -1,5 +1,8 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py altgraph==0.17.4 -pyinstaller @ git+https://github.com/pyinstaller/pyinstaller.git@79f62ef29822169ae00cd4271390d0e3175476ad +importlib-metadata==6.8.0 +packaging==23.2 +pyinstaller==6.2.0 pyinstaller-hooks-contrib==2023.10 +zipp==3.17.0 diff --git a/misc/requirements/requirements-pyinstaller.txt-raw b/misc/requirements/requirements-pyinstaller.txt-raw index 7b4c8c84c..ef376ca83 100644 --- a/misc/requirements/requirements-pyinstaller.txt-raw +++ b/misc/requirements/requirements-pyinstaller.txt-raw @@ -1 +1 @@ -pyinstaller @ git+https://github.com/pyinstaller/pyinstaller.git@79f62ef29822169ae00cd4271390d0e3175476ad +pyinstaller diff --git a/misc/requirements/requirements-pylint.txt b/misc/requirements/requirements-pylint.txt index a3821428a..7d4dc69b7 100644 --- a/misc/requirements/requirements-pylint.txt +++ b/misc/requirements/requirements-pylint.txt @@ -1,26 +1,26 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py astroid==3.0.1 -certifi==2023.7.22 +certifi==2023.11.17 cffi==1.16.0 -charset-normalizer==3.3.0 -cryptography==41.0.4 +charset-normalizer==3.3.2 +cryptography==41.0.5 dill==0.3.7 github3.py==4.0.1 idna==3.4 isort==5.12.0 mccabe==0.7.0 pefile==2023.2.7 -platformdirs==3.11.0 +platformdirs==4.0.0 pycparser==2.21 PyJWT==2.8.0 -pylint==3.0.1 +pylint==3.0.2 python-dateutil==2.8.2 ./scripts/dev/pylint_checkers requests==2.31.0 six==1.16.0 tomli==2.0.1 -tomlkit==0.12.1 +tomlkit==0.12.3 typing_extensions==4.8.0 uritemplate==4.1.1 -# urllib3==2.0.6 +# urllib3==2.1.0 diff --git a/misc/requirements/requirements-pyqt-6.6.txt b/misc/requirements/requirements-pyqt-6.6.txt new file mode 100644 index 000000000..0a9c72e25 --- /dev/null +++ b/misc/requirements/requirements-pyqt-6.6.txt @@ -0,0 +1,7 @@ +# This file is automatically generated by scripts/dev/recompile_requirements.py + +PyQt6==6.6.0 +PyQt6-Qt6==6.6.0 +PyQt6-sip==13.6.0 +PyQt6-WebEngine==6.6.0 +PyQt6-WebEngine-Qt6==6.6.0 diff --git a/misc/requirements/requirements-pyqt-6.6.txt-raw b/misc/requirements/requirements-pyqt-6.6.txt-raw new file mode 100644 index 000000000..7cfe6d34c --- /dev/null +++ b/misc/requirements/requirements-pyqt-6.6.txt-raw @@ -0,0 +1,4 @@ +PyQt6 >= 6.6, < 6.7 +PyQt6-Qt6 >= 6.6, < 6.7 +PyQt6-WebEngine >= 6.6, < 6.7 +PyQt6-WebEngine-Qt6 >= 6.6, < 6.7 diff --git a/misc/requirements/requirements-pyqt-6.txt b/misc/requirements/requirements-pyqt-6.txt index 5dca9ab74..0a9c72e25 100644 --- a/misc/requirements/requirements-pyqt-6.txt +++ b/misc/requirements/requirements-pyqt-6.txt @@ -1,7 +1,7 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py -PyQt6==6.5.3 -PyQt6-Qt6==6.5.3 +PyQt6==6.6.0 +PyQt6-Qt6==6.6.0 PyQt6-sip==13.6.0 -PyQt6-WebEngine==6.5.0 -PyQt6-WebEngine-Qt6==6.5.3 +PyQt6-WebEngine==6.6.0 +PyQt6-WebEngine-Qt6==6.6.0 diff --git a/misc/requirements/requirements-pyqt.txt b/misc/requirements/requirements-pyqt.txt index 5dca9ab74..0a9c72e25 100644 --- a/misc/requirements/requirements-pyqt.txt +++ b/misc/requirements/requirements-pyqt.txt @@ -1,7 +1,7 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py -PyQt6==6.5.3 -PyQt6-Qt6==6.5.3 +PyQt6==6.6.0 +PyQt6-Qt6==6.6.0 PyQt6-sip==13.6.0 -PyQt6-WebEngine==6.5.0 -PyQt6-WebEngine-Qt6==6.5.3 +PyQt6-WebEngine==6.6.0 +PyQt6-WebEngine-Qt6==6.6.0 diff --git a/misc/requirements/requirements-pyroma.txt b/misc/requirements/requirements-pyroma.txt index 72dc5545c..b80f5f63a 100644 --- a/misc/requirements/requirements-pyroma.txt +++ b/misc/requirements/requirements-pyroma.txt @@ -1,17 +1,17 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py build==1.0.3 -certifi==2023.7.22 -charset-normalizer==3.3.0 +certifi==2023.11.17 +charset-normalizer==3.3.2 docutils==0.20.1 idna==3.4 importlib-metadata==6.8.0 packaging==23.2 -Pygments==2.16.1 +Pygments==2.17.1 pyproject_hooks==1.0.0 pyroma==4.2 requests==2.31.0 tomli==2.0.1 -trove-classifiers==2023.9.19 -urllib3==2.0.6 +trove-classifiers==2023.11.14 +urllib3==2.1.0 zipp==3.17.0 diff --git a/misc/requirements/requirements-sphinx.txt b/misc/requirements/requirements-sphinx.txt index afc173af6..5de9398fb 100644 --- a/misc/requirements/requirements-sphinx.txt +++ b/misc/requirements/requirements-sphinx.txt @@ -1,9 +1,9 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py alabaster==0.7.13 -Babel==2.13.0 -certifi==2023.7.22 -charset-normalizer==3.3.0 +Babel==2.13.1 +certifi==2023.11.17 +charset-normalizer==3.3.2 docutils==0.20.1 idna==3.4 imagesize==1.4.1 @@ -11,7 +11,7 @@ importlib-metadata==6.8.0 Jinja2==3.1.2 MarkupSafe==2.1.3 packaging==23.2 -Pygments==2.16.1 +Pygments==2.17.1 pytz==2023.3.post1 requests==2.31.0 snowballstemmer==2.2.0 @@ -22,5 +22,5 @@ sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 -urllib3==2.0.6 +urllib3==2.1.0 zipp==3.17.0 diff --git a/misc/requirements/requirements-tests.txt b/misc/requirements/requirements-tests.txt index b772d87f8..86e13960a 100644 --- a/misc/requirements/requirements-tests.txt +++ b/misc/requirements/requirements-tests.txt @@ -2,25 +2,25 @@ attrs==23.1.0 beautifulsoup4==4.12.2 -blinker==1.6.3 -certifi==2023.7.22 -charset-normalizer==3.3.0 +blinker==1.7.0 +certifi==2023.11.17 +charset-normalizer==3.3.2 cheroot==10.0.0 click==8.1.7 coverage==7.3.2 exceptiongroup==1.1.3 execnet==2.0.2 -filelock==3.12.4 +filelock==3.13.1 Flask==3.0.0 hunter==3.6.1 -hypothesis==6.88.0 +hypothesis==6.90.0 idna==3.4 importlib-metadata==6.8.0 iniconfig==2.0.0 itsdangerous==2.1.2 -jaraco.functools==3.9.0 +jaraco.functools==4.0.0 # Jinja2==3.1.2 -Mako==1.2.4 +Mako==1.3.0 manhole==1.8.0 # MarkupSafe==2.1.3 more-itertools==10.1.0 @@ -29,17 +29,17 @@ parse==1.19.1 parse-type==0.6.2 pluggy==1.3.0 py-cpuinfo==9.0.0 -Pygments==2.16.1 -pytest==7.4.2 +Pygments==2.17.1 +pytest==7.4.3 pytest-bdd==7.0.0 pytest-benchmark==4.0.0 pytest-cov==4.1.0 pytest-instafail==0.5.0 -pytest-mock==3.11.1 +pytest-mock==3.12.0 pytest-qt==4.2.0 pytest-repeat==0.9.3 pytest-rerunfailures==12.0 -pytest-xdist==3.3.1 +pytest-xdist==3.4.0 pytest-xvfb==3.0.0 PyVirtualDisplay==3.0 requests==2.31.0 @@ -47,11 +47,11 @@ requests-file==1.5.1 six==1.16.0 sortedcontainers==2.4.0 soupsieve==2.5 -tldextract==5.0.0 +tldextract==5.1.1 toml==0.10.2 tomli==2.0.1 typing_extensions==4.8.0 -urllib3==2.0.6 +urllib3==2.1.0 vulture==2.10 -Werkzeug==3.0.0 +Werkzeug==3.0.1 zipp==3.17.0 diff --git a/misc/requirements/requirements-tox.txt b/misc/requirements/requirements-tox.txt index 4c719ce5b..0b1b5277d 100644 --- a/misc/requirements/requirements-tox.txt +++ b/misc/requirements/requirements-tox.txt @@ -1,17 +1,17 @@ # This file is automatically generated by scripts/dev/recompile_requirements.py -cachetools==5.3.1 +cachetools==5.3.2 chardet==5.2.0 colorama==0.4.6 distlib==0.3.7 -filelock==3.12.4 +filelock==3.13.1 packaging==23.2 -pip==23.3 +pip==23.3.1 platformdirs==3.11.0 pluggy==1.3.0 pyproject-api==1.6.1 setuptools==68.2.2 tomli==2.0.1 tox==4.11.3 -virtualenv==20.24.5 -wheel==0.41.2 +virtualenv==20.24.6 +wheel==0.41.3 diff --git a/misc/requirements/requirements-yamllint.txt b/misc/requirements/requirements-yamllint.txt index fd9ea256f..32589d26f 100644 --- a/misc/requirements/requirements-yamllint.txt +++ b/misc/requirements/requirements-yamllint.txt @@ -2,4 +2,4 @@ pathspec==0.11.2 PyYAML==6.0.1 -yamllint==1.32.0 +yamllint==1.33.0 diff --git a/qutebrowser/__init__.py b/qutebrowser/__init__.py index 6a1a21806..522545e12 100644 --- a/qutebrowser/__init__.py +++ b/qutebrowser/__init__.py @@ -11,7 +11,7 @@ __copyright__ = "Copyright 2014-2021 Florian Bruhin (The Compiler)" __license__ = "GPL" __maintainer__ = __author__ __email__ = "mail@qutebrowser.org" -__version__ = "3.0.1" +__version__ = "3.0.2" __version_info__ = tuple(int(part) for part in __version__.split('.')) __description__ = "A keyboard-driven, vim-like browser based on Python and Qt." diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 1312275dc..4d14c9cd7 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -"""Base class for a wrapper over QWebView/QWebEngineView.""" +"""Base class for a wrapper over WebView/WebEngineView.""" import enum import pathlib @@ -22,10 +22,9 @@ from qutebrowser.qt.network import QNetworkAccessManager if TYPE_CHECKING: from qutebrowser.qt.webkit import QWebHistory, QWebHistoryItem - from qutebrowser.qt.webkitwidgets import QWebPage, QWebView + from qutebrowser.qt.webkitwidgets import QWebPage from qutebrowser.qt.webenginecore import ( QWebEngineHistory, QWebEngineHistoryItem, QWebEnginePage) - from qutebrowser.qt.webenginewidgets import QWebEngineView from qutebrowser.keyinput import modeman from qutebrowser.config import config, websettings @@ -38,10 +37,12 @@ from qutebrowser.qt import sip if TYPE_CHECKING: from qutebrowser.browser import webelem from qutebrowser.browser.inspector import AbstractWebInspector + from qutebrowser.browser.webengine.webview import WebEngineView + from qutebrowser.browser.webkit.webview import WebView tab_id_gen = itertools.count(0) -_WidgetType = Union["QWebView", "QWebEngineView"] +_WidgetType = Union["WebView", "WebEngineView"] def create(win_id: int, @@ -964,7 +965,7 @@ class AbstractTabPrivate: class AbstractTab(QWidget): - """An adapter for QWebView/QWebEngineView representing a single tab.""" + """An adapter for WebView/WebEngineView representing a single tab.""" #: Signal emitted when a website requests to close this tab. window_close_requested = pyqtSignal() @@ -1058,7 +1059,7 @@ class AbstractTab(QWidget): self.before_load_started.connect(self._on_before_load_started) - def _set_widget(self, widget: Union["QWebView", "QWebEngineView"]) -> None: + def _set_widget(self, widget: _WidgetType) -> None: # pylint: disable=protected-access self._widget = widget # FIXME:v4 ignore needed for QtWebKit diff --git a/qutebrowser/browser/webengine/webengineinspector.py b/qutebrowser/browser/webengine/webengineinspector.py index 64ef24319..d37f41ba5 100644 --- a/qutebrowser/browser/webengine/webengineinspector.py +++ b/qutebrowser/browser/webengine/webengineinspector.py @@ -35,14 +35,19 @@ class WebEngineInspectorView(QWebEngineView): See WebEngineView.createWindow for details. """ - inspected_page = self.page().inspectedPage() + our_page = self.page() + assert our_page is not None + inspected_page = our_page.inspectedPage() + assert inspected_page is not None if machinery.IS_QT5: view = inspected_page.view() assert isinstance(view, QWebEngineView), view return view.createWindow(wintype) else: # Qt 6 newpage = inspected_page.createWindow(wintype) - return webview.WebEngineView.forPage(newpage) + ret = webview.WebEngineView.forPage(newpage) + assert ret is not None + return ret class WebEngineInspector(inspector.AbstractWebInspector): @@ -88,16 +93,17 @@ class WebEngineInspector(inspector.AbstractWebInspector): def inspect(self, page: QWebEnginePage) -> None: if not self._widget: view = WebEngineInspectorView() - inspector_page = QWebEnginePage( + new_page = QWebEnginePage( page.profile(), self ) - inspector_page.windowCloseRequested.connect(self._on_window_close_requested) - view.setPage(inspector_page) + new_page.windowCloseRequested.connect(self._on_window_close_requested) + view.setPage(new_page) self._settings = webenginesettings.WebEngineSettings(view.settings()) self._set_widget(view) inspector_page = self._widget.page() + assert inspector_page is not None assert inspector_page.profile() == page.profile() inspector_page.setInspectedPage(page) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index 168fb8280..e1aa7c52e 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -51,8 +51,12 @@ class _SettingsWrapper: For read operations, the default profile value is always used. """ + def _default_profile_settings(self): + assert default_profile is not None + return default_profile.settings() + def _settings(self): - yield default_profile.settings() + yield self._default_profile_settings() if private_profile: yield private_profile.settings() @@ -77,19 +81,19 @@ class _SettingsWrapper: settings.setUnknownUrlSchemePolicy(policy) def testAttribute(self, attribute): - return default_profile.settings().testAttribute(attribute) + return self._default_profile_settings().testAttribute(attribute) def fontSize(self, fonttype): - return default_profile.settings().fontSize(fonttype) + return self._default_profile_settings().fontSize(fonttype) def fontFamily(self, which): - return default_profile.settings().fontFamily(which) + return self._default_profile_settings().fontFamily(which) def defaultTextEncoding(self): - return default_profile.settings().defaultTextEncoding() + return self._default_profile_settings().defaultTextEncoding() def unknownUrlSchemePolicy(self): - return default_profile.settings().unknownUrlSchemePolicy() + return self._default_profile_settings().unknownUrlSchemePolicy() class WebEngineSettings(websettings.AbstractSettings): @@ -342,7 +346,10 @@ def _init_user_agent_str(ua): def init_user_agent(): - _init_user_agent_str(QWebEngineProfile.defaultProfile().httpUserAgent()) + """Make the default WebEngine user agent available via parsed_user_agent.""" + actual_default_profile = QWebEngineProfile.defaultProfile() + assert actual_default_profile is not None + _init_user_agent_str(actual_default_profile.httpUserAgent()) def _init_profile(profile: QWebEngineProfile) -> None: diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 9f1d04b63..1c712db5e 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -"""Wrapper over a QWebEngineView.""" +"""Wrapper over a WebEngineView.""" import math import struct @@ -15,7 +15,6 @@ from typing import cast, Union, Optional from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, Qt, QPoint, QPointF, QTimer, QUrl, QObject, QByteArray) from qutebrowser.qt.network import QAuthenticator -from qutebrowser.qt.webenginewidgets import QWebEngineView from qutebrowser.qt.webenginecore import QWebEnginePage, QWebEngineScript, QWebEngineHistory from qutebrowser.config import config @@ -1267,7 +1266,7 @@ class WebEngineTab(browsertab.AbstractTab): abort_questions = pyqtSignal() - _widget: QWebEngineView + _widget: webview.WebEngineView search: WebEngineSearch audio: WebEngineAudio printing: WebEnginePrinting diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py index 3c63c59e4..a6f2ae113 100644 --- a/qutebrowser/browser/webengine/webview.py +++ b/qutebrowser/browser/webengine/webview.py @@ -5,13 +5,16 @@ """The main browser widget for QtWebEngine.""" import mimetypes -from typing import List, Iterable +from typing import List, Iterable, Optional from qutebrowser.qt import machinery from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QUrl from qutebrowser.qt.gui import QPalette from qutebrowser.qt.webenginewidgets import QWebEngineView -from qutebrowser.qt.webenginecore import QWebEnginePage, QWebEngineCertificateError +from qutebrowser.qt.webenginecore import ( + QWebEnginePage, QWebEngineCertificateError, QWebEngineSettings, + QWebEngineHistory, +) from qutebrowser.browser import shared from qutebrowser.browser.webengine import webenginesettings, certificateerror @@ -129,6 +132,25 @@ class WebEngineView(QWebEngineView): return super().contextMenuEvent(ev) + def page(self) -> "WebEnginePage": + """Return the page for this view.""" + maybe_page = super().page() + assert maybe_page is not None + assert isinstance(maybe_page, WebEnginePage) + return maybe_page + + def settings(self) -> "QWebEngineSettings": + """Return the settings for this view.""" + maybe_settings = super().settings() + assert maybe_settings is not None + return maybe_settings + + def history(self) -> "QWebEngineHistory": + """Return the history for this view.""" + maybe_history = super().history() + assert maybe_history is not None + return maybe_history + def extra_suffixes_workaround(upstream_mimetypes): """Return any extra suffixes for mimetypes in upstream_mimetypes. @@ -294,22 +316,28 @@ class WebEnginePage(QWebEnginePage): def chooseFiles( self, mode: QWebEnginePage.FileSelectionMode, - old_files: Iterable[str], - accepted_mimetypes: Iterable[str], + old_files: Iterable[Optional[str]], + accepted_mimetypes: Iterable[Optional[str]], ) -> List[str]: """Override chooseFiles to (optionally) invoke custom file uploader.""" - extra_suffixes = extra_suffixes_workaround(accepted_mimetypes) + accepted_mimetypes_filtered = [m for m in accepted_mimetypes if m is not None] + old_files_filtered = [f for f in old_files if f is not None] + extra_suffixes = extra_suffixes_workaround(accepted_mimetypes_filtered) if extra_suffixes: log.webview.debug( "adding extra suffixes to filepicker: " - f"before={accepted_mimetypes} " + f"before={accepted_mimetypes_filtered} " f"added={extra_suffixes}", ) - accepted_mimetypes = list(accepted_mimetypes) + list(extra_suffixes) + accepted_mimetypes_filtered = list( + accepted_mimetypes_filtered + ) + list(extra_suffixes) handler = config.val.fileselect.handler if handler == "default": - return super().chooseFiles(mode, old_files, accepted_mimetypes) + return super().chooseFiles( + mode, old_files_filtered, accepted_mimetypes_filtered, + ) assert handler == "external", handler try: qb_mode = _QB_FILESELECTION_MODES[mode] @@ -317,6 +345,8 @@ class WebEnginePage(QWebEnginePage): log.webview.warning( f"Got file selection mode {mode}, but we don't support that!" ) - return super().chooseFiles(mode, old_files, accepted_mimetypes) + return super().chooseFiles( + mode, old_files_filtered, accepted_mimetypes_filtered, + ) return shared.choose_file(qb_mode=qb_mode) diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py index 7ccdabc88..b5b232c5a 100644 --- a/qutebrowser/extensions/loader.py +++ b/qutebrowser/extensions/loader.py @@ -6,12 +6,11 @@ import pkgutil import types -import sys import pathlib import importlib import argparse import dataclasses -from typing import Callable, Iterator, List, Optional, Set, Tuple +from typing import Callable, Iterator, List, Optional, Tuple from qutebrowser.qt.core import pyqtSlot @@ -80,14 +79,6 @@ def load_components(*, skip_hooks: bool = False) -> None: def walk_components() -> Iterator[ExtensionInfo]: """Yield ExtensionInfo objects for all modules.""" - if hasattr(sys, 'frozen'): - yield from _walk_pyinstaller() - else: - yield from _walk_normal() - - -def _walk_normal() -> Iterator[ExtensionInfo]: - """Walk extensions when not using PyInstaller.""" for _finder, name, ispkg in pkgutil.walk_packages( path=components.__path__, prefix=components.__name__ + '.', @@ -102,23 +93,6 @@ def _walk_normal() -> Iterator[ExtensionInfo]: yield ExtensionInfo(name=name) -def _walk_pyinstaller() -> Iterator[ExtensionInfo]: - """Walk extensions when using PyInstaller. - - See https://github.com/pyinstaller/pyinstaller/issues/1905 - - Inspired by: - https://github.com/webcomics/dosage/blob/master/dosagelib/loader.py - """ - toc: Set[str] = set() - for importer in pkgutil.iter_importers('qutebrowser'): - if hasattr(importer, 'toc'): - toc |= importer.toc - for name in toc: - if name.startswith(components.__name__ + '.'): - yield ExtensionInfo(name=name) - - def _get_init_context() -> InitContext: """Get an InitContext object.""" return InitContext(data_dir=pathlib.Path(standarddir.data()), diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 1f5da2dcd..363d5607a 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -18,8 +18,8 @@ import enum import pathlib import operator import contextlib -from typing import (Any, AnyStr, TYPE_CHECKING, BinaryIO, IO, Iterator, - Optional, Union, Tuple, Protocol, cast, TypeVar) +from typing import (Any, TYPE_CHECKING, BinaryIO, IO, Iterator, Literal, + Optional, Union, Tuple, Protocol, cast, overload, TypeVar) from qutebrowser.qt import machinery, sip from qutebrowser.qt.core import (qVersion, QEventLoop, QDataStream, QByteArray, @@ -89,8 +89,8 @@ def version_check(version: str, With `compiled=False` only the runtime Qt version (1) is checked. You can often run older PyQt versions against newer Qt versions, but you - won't be able to access any APIs that where only added in the newer Qt - version. So if you want to check if a new feature if supported, use the + won't be able to access any APIs that were only added in the newer Qt + version. So if you want to check if a new feature is supported, use the default behavior. If you just want to check the underlying Qt version, pass `compiled=False`. @@ -236,12 +236,32 @@ def deserialize_stream(stream: QDataStream, obj: _QtSerializableType) -> None: check_qdatastream(stream) +@overload +@contextlib.contextmanager +def savefile_open( + filename: str, + binary: Literal[False] = ..., + encoding: str = 'utf-8' +) -> Iterator[IO[str]]: + ... + + +@overload +@contextlib.contextmanager +def savefile_open( + filename: str, + binary: Literal[True] = ..., + encoding: str = 'utf-8' +) -> Iterator[IO[str]]: + ... + + @contextlib.contextmanager def savefile_open( filename: str, binary: bool = False, encoding: str = 'utf-8' -) -> Iterator[IO[AnyStr]]: +) -> Iterator[Union[IO[str], IO[bytes]]]: """Context manager to easily use a QSaveFile.""" f = QSaveFile(filename) cancelled = False @@ -253,7 +273,7 @@ def savefile_open( dev = cast(BinaryIO, PyQIODevice(f)) if binary: - new_f: IO[Any] = dev # FIXME:mypy Why doesn't AnyStr work? + new_f: Union[IO[str], IO[bytes]] = dev else: new_f = io.TextIOWrapper(dev, encoding=encoding) diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py index 75df73ffa..a139d01c5 100644 --- a/qutebrowser/utils/version.py +++ b/qutebrowser/utils/version.py @@ -686,7 +686,7 @@ class WebEngineVersions: return cls._CHROMIUM_VERSIONS.get(minor_version) @classmethod - def from_api(cls, qtwe_version: str, chromium_version: str) -> 'WebEngineVersions': + def from_api(cls, qtwe_version: str, chromium_version: Optional[str]) -> 'WebEngineVersions': """Get the versions based on the exact versions. This is called if we have proper APIs to get the versions easily @@ -796,8 +796,10 @@ def qtwebengine_versions(*, avoid_init: bool = False) -> WebEngineVersions: except ImportError: pass # Needs QtWebEngine 6.2+ with PyQtWebEngine 6.3.1+ else: + qtwe_version = qWebEngineVersion() + assert qtwe_version is not None return WebEngineVersions.from_api( - qtwe_version=qWebEngineVersion(), + qtwe_version=qtwe_version, chromium_version=qWebEngineChromiumVersion(), ) diff --git a/requirements.txt b/requirements.txt index dc07bf531..f1b9a4a2a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,10 +2,10 @@ adblock==0.6.0 colorama==0.4.6 -importlib-resources==6.1.0 ; python_version=="3.8.*" +importlib-resources==6.1.1 ; python_version=="3.8.*" Jinja2==3.1.2 MarkupSafe==2.1.3 -Pygments==2.16.1 +Pygments==2.17.1 PyYAML==6.0.1 zipp==3.17.0 # Unpinned due to recompile_requirements.py limitations diff --git a/scripts/dev/ci/problemmatchers.py b/scripts/dev/ci/problemmatchers.py index fa623dec7..3316c5597 100644 --- a/scripts/dev/ci/problemmatchers.py +++ b/scripts/dev/ci/problemmatchers.py @@ -160,13 +160,17 @@ MATCHERS = { "tests": [ { # pytest test summary output + # Examples (with ANSI color codes around FAILED|ERROR and the + # function name): + # FAILED tests/end2end/features/test_keyinput_bdd.py::test_fakekey_sending_special_key_to_the_website - end2end.fixtures.testprocess.WaitForTimeout: Timed out after 15000ms waiting for {'category': 'js', 'message': '[*] key press: 27'}. + # ERROR tests/end2end/test_insert_mode.py::test_insert_mode[100-textarea.html-qute-textarea-clipboard-qutebrowser] - Failed: Logged unexpected errors: "severity": "error", "pattern": [ { - "regexp": r'^=+ short test summary info =+$', + "regexp": r'^.*=== short test summary info ===.*$', }, { - "regexp": r"^((ERROR|FAILED) .*)", + "regexp": r"^[^ ]*((ERROR|FAILED)[^ ]* .*)$", "message": 1, "loop": True, } diff --git a/tests/end2end/fixtures/quteprocess.py b/tests/end2end/fixtures/quteprocess.py index a2f870e32..de9b490ca 100644 --- a/tests/end2end/fixtures/quteprocess.py +++ b/tests/end2end/fixtures/quteprocess.py @@ -390,7 +390,8 @@ class QuteProc(testprocess.Process): '--json-logging', '--loglevel', 'vdebug', '--backend', backend, '--debug-flag', 'no-sql-history', '--debug-flag', 'werror', '--debug-flag', - 'test-notification-service'] + 'test-notification-service', + '--qt-flag', 'disable-features=PaintHoldingCrossOrigin'] if self.request.config.webengine and testutils.disable_seccomp_bpf_sandbox(): args += testutils.DISABLE_SECCOMP_BPF_ARGS diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py index af81781f6..72e08af96 100644 --- a/tests/end2end/test_invocations.py +++ b/tests/end2end/test_invocations.py @@ -15,6 +15,7 @@ import re import json import platform from contextlib import nullcontext as does_not_raise +from unittest.mock import ANY import pytest from qutebrowser.qt.core import QProcess, QPoint @@ -885,27 +886,78 @@ def test_sandboxing( bpf_text = "Seccomp-BPF sandbox" yama_text = "Ptrace Protection with Yama LSM" - header, *lines, empty, result = text.split("\n") - assert not empty + if not utils.is_windows: + header, *lines, empty, result = text.split("\n") + assert not empty - expected_status = { - "Layer 1 Sandbox": "Namespace" if has_namespaces else "None", + expected_status = { + "Layer 1 Sandbox": "Namespace" if has_namespaces else "None", - "PID namespaces": "Yes" if has_namespaces else "No", - "Network namespaces": "Yes" if has_namespaces else "No", + "PID namespaces": "Yes" if has_namespaces else "No", + "Network namespaces": "Yes" if has_namespaces else "No", - bpf_text: "Yes" if has_seccomp else "No", - f"{bpf_text} supports TSYNC": "Yes" if has_seccomp else "No", + bpf_text: "Yes" if has_seccomp else "No", + f"{bpf_text} supports TSYNC": "Yes" if has_seccomp else "No", - f"{yama_text} (Broker)": "Yes" if has_yama else "No", - f"{yama_text} (Non-broker)": "Yes" if has_yama_non_broker else "No", - } - - assert header == "Sandbox Status" - assert result == expected_result + f"{yama_text} (Broker)": "Yes" if has_yama else "No", + f"{yama_text} (Non-broker)": "Yes" if has_yama_non_broker else "No", + } - status = dict(line.split("\t") for line in lines) - assert status == expected_status + assert header == "Sandbox Status" + assert result == expected_result + + status = dict(line.split("\t") for line in lines) + assert status == expected_status + + else: # utils.is_windows + # The sandbox page on Windows if different that Linux and macOS. It's + # a lot more complex. There is a table up top with lots of columns and + # a row per tab and helper process then a json object per row down + # below with even more detail (which we ignore). + # https://www.chromium.org/Home/chromium-security/articles/chrome-sandbox-diagnostics-for-windows/ + + # We're not getting full coverage of the table and there doesn't seem + # to be a simple summary like for linux. The "Sandbox" and "Lockdown" + # column are probably the key ones. + # We are looking at all the rows in the table for the sake of + # completeness, but I expect there will always be just one row with a + # renderer process in it for this test. If other helper processes pop + # up we might want to exclude them. + lines = text.split("\n") + assert lines.pop(0) == "Sandbox Status" + header = lines.pop(0).split("\t") + rows = [] + current_line = lines.pop(0) + while current_line.strip(): + if lines[0].startswith("\t"): + # Continuation line. Not sure how to 100% identify them + # but new rows should start with a process ID. + current_line += lines.pop(0) + continue + + columns = current_line.split("\t") + assert len(header) == len(columns) + rows.append(dict(zip(header, columns))) + current_line = lines.pop(0) + + assert rows + + # I'm using has_namespaces as a proxy for "should be sandboxed" here, + # which is a bit lazy but its either that or match on the text + # "sandboxing" arg. The seccomp-bpf arg does nothing on windows, so + # we only have the off and on states. + for row in rows: + assert row == { + "Process": ANY, + "Type": "Renderer", + "Name": "", + "Sandbox": "Renderer" if has_namespaces else "Not Sandboxed", + "Lockdown": "Lockdown" if has_namespaces else "", + "Integrity": ANY if has_namespaces else "", + "Mitigations": ANY if has_namespaces else "", + "Component Filter": ANY if has_namespaces else "", + "Lowbox/AppContainer": "", + } @pytest.mark.not_frozen diff --git a/tests/unit/extensions/test_loader.py b/tests/unit/extensions/test_loader.py index fd15130ba..a2a99f305 100644 --- a/tests/unit/extensions/test_loader.py +++ b/tests/unit/extensions/test_loader.py @@ -20,16 +20,10 @@ def test_on_walk_error(): def test_walk_normal(): - names = [info.name for info in loader._walk_normal()] + names = [info.name for info in loader.walk_components()] assert 'qutebrowser.components.scrollcommands' in names -def test_walk_pyinstaller(): - # We can't test whether we get something back without being frozen by - # PyInstaller, but at least we can test that we don't crash. - list(loader._walk_pyinstaller()) - - def test_load_component(monkeypatch): monkeypatch.setattr(objects, 'commands', {}) @@ -51,8 +51,9 @@ deps = pyqt63: -r{toxinidir}/misc/requirements/requirements-pyqt-6.3.txt pyqt64: -r{toxinidir}/misc/requirements/requirements-pyqt-6.4.txt pyqt65: -r{toxinidir}/misc/requirements/requirements-pyqt-6.5.txt + pyqt66: -r{toxinidir}/misc/requirements/requirements-pyqt-6.6.txt commands = - !pyqt-!pyqt515-!pyqt5152-!pyqt62-!pyqt63-!pyqt64-!pyqt65: {envpython} scripts/link_pyqt.py --tox {envdir} + !pyqt-!pyqt515-!pyqt5152-!pyqt62-!pyqt63-!pyqt64-!pyqt65-!pyqt66: {envpython} scripts/link_pyqt.py --tox {envdir} {envpython} -bb -m pytest {posargs:tests} cov: {envpython} scripts/dev/check_coverage.py {posargs} @@ -191,7 +192,6 @@ passenv = APPDATA HOME PYINSTALLER_DEBUG - PYINSTALLER_COMPILE_BOOTLOADER setenv = qt5: PYINSTALLER_QT5=true deps = @@ -281,7 +281,6 @@ passenv = * # Override default PyQt6 from [testenv] setenv = qt5: QUTE_QT_WRAPPER=PyQt5 - PYINSTALLER_COMPILE_BOOTLOADER=true usedevelop = true deps = -r{toxinidir}/requirements.txt |