diff --git a/.github/workflows/add-new-language.yml b/.github/workflows/add-new-language.yml index 9133d9c2225..897b39f4711 100644 --- a/.github/workflows/add-new-language.yml +++ b/.github/workflows/add-new-language.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: beta fetch-depth: 1 @@ -44,13 +44,6 @@ jobs: crowdinProjectID: ${{ vars.CROWDIN_PROJECT_ID }} crowdinAuthToken: ${{ secrets.CROWDIN_AUTH_TOKEN }} - - name: Install pre-commit - run: | - python -m pip install --upgrade pip - pip install pre-commit - pre-commit install - - # Job will fail if pre-commit checks fail - name: Commit language files only id: commit shell: bash @@ -61,6 +54,10 @@ jobs: git add source/locale/${{ matrix.newLanguage }} git add user_docs/${{ matrix.newLanguage }} + # Lint the staged translation files. If a hook fails or rewrites a file, + # this step fails, so the job stops here and no pull request is opened. + uv run prek run + # Check if there are any changes to commit if git diff --staged --quiet; then echo "No changes to commit" diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml new file mode 100644 index 00000000000..8149f60bd32 --- /dev/null +++ b/.github/workflows/autofix.yml @@ -0,0 +1,87 @@ +# A part of NonVisual Desktop Access (NVDA) +# Copyright (C) 2026 NV Access Limited, Leonard de Ruijter +# This file may be used under the terms of the GNU General Public License, version 2 or later, as modified by the NVDA license. +# For full terms and any additional permissions, see the NVDA license file: https://github.com/nvaccess/nvda/blob/master/copying.txt + +name: Autofix or fail + +on: + push: + # Never auto-fix the protected branches; PRs to them use pull_request below. + branches-ignore: + - master + - beta + - rc + pull_request: + branches: + - master + - beta + - rc + - 'try-**' + workflow_dispatch: +permissions: + contents: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + autofix: + name: Auto-fix and lint gate + # On the base repo the pull_request run is the gate; skip its push run on non-Fork pushes to + # avoid a duplicate. Fork pushes still run for autofix. + if: github.event_name != 'push' || github.repository != 'nvaccess/nvda' + runs-on: windows-2025-vs2026 + steps: + - name: Checkout repository + uses: actions/checkout@v7 + with: + submodules: true + - name: Set up python + uses: actions/setup-python@v6 + with: + # Keep in sync with defaultPythonVersion in testAndPublish.yml. + python-version: '3.13.13' + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v7 + with: + activate-environment: "false" + # Autofix role: run the fixer hooks (the "autofix" group) and push the fixes. + - name: Apply prek auto-fixes + if: github.event_name == 'push' + shell: bash + env: + REF_NAME: ${{ github.ref_name }} + run: | + # Fixers exit non-zero when they change files. Some fixers' output feeds + # another fixer, so a single pass may not reach a stable tree. + # Re-run on the fixed tree until prek exits clean or we hit the cap. + for attempt in 1 2 3; do + if uvx prek run --group autofix --all-files; then + break + fi + done + if ! git diff --quiet; then + git config user.name "github-actions" + git config user.email "github-actions@github.com" + git add -A + git commit -m "Auto-fix: apply prek fixes" + # Push via an explicit refspec so this works even if checkout left us + # in a detached HEAD state. + git push origin HEAD:"$REF_NAME" + fi + # Gate role: the merge-required blocking check (non-zero exit fails the job). + # The 6 skipped hooks are the heavy/env-bound ones with dedicated jobs in + # testAndPublish.yml. + - name: Lint gate + uses: j178/prek-action@v2 + with: + extra-args: >- + --all-files + --skip checkPo + --skip scons-source + --skip checkPot + --skip unitTest + --skip licenseCheck + --skip pyright diff --git a/.github/workflows/prekAutoUpdate.yml b/.github/workflows/prekAutoUpdate.yml new file mode 100644 index 00000000000..be0901bac53 --- /dev/null +++ b/.github/workflows/prekAutoUpdate.yml @@ -0,0 +1,51 @@ +# A part of NonVisual Desktop Access (NVDA) +# Copyright (C) 2026 NV Access Limited, Leonard de Ruijter +# This file may be used under the terms of the GNU General Public License, version 2 or later, as modified by the NVDA license. +# For full terms and any additional permissions, see the NVDA license file: https://github.com/nvaccess/nvda/blob/master/copying.txt + +name: Prek auto-update + +on: + schedule: + # Monthly, at midnight on the first day of the month. + - cron: '0 0 1 * *' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + prekAutoUpdate: + name: Prek auto-update + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v7 + # Install prek as a standalone binary + - name: Install prek + run: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/j178/prek/releases/latest/download/prek-installer.sh | sh + # --cooldown-days skips releases younger than 3 days, avoiding pinning to + # a freshly published (and potentially yanked/broken) hook revision. + - name: Run prek auto-update + run: prek auto-update --cooldown-days 3 + - name: Create pull request + shell: bash + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + if git diff --quiet; then + echo "No hook updates available." + exit 0 + fi + git config --local user.name "github-actions" + git config --local user.email "github-actions@github.com" + git checkout -b prek-autoupdate + git commit -am "Prek auto-update" + # Force push so a re-run replaces a stale auto-update branch. + git push --force --set-upstream origin prek-autoupdate + # Reuse the existing PR if one is already open from a previous run. + gh pr create --base master --head prek-autoupdate \ + --title "Prek auto-update" \ + --body "Automated update of prek hook revisions." \ + || echo "A pull request for prek-autoupdate already exists." diff --git a/.github/workflows/testAndPublish.yml b/.github/workflows/testAndPublish.yml index 4094f0c94bf..10051a9807c 100644 --- a/.github/workflows/testAndPublish.yml +++ b/.github/workflows/testAndPublish.yml @@ -191,14 +191,14 @@ jobs: architecture: ${{ env.defaultArch }} - name: Install the latest version of uv uses: astral-sh/setup-uv@v7 - - name: Run pre-commit + - name: Run prek run: | # Ensure uv environment is up to date. - # If the uv environment is outdated, running pre-commit will trigger uv to generate a uv.lock file, - # which causes checkPo to fail without clear errors because pre-commit fails when files are changed during its run. - uv run pre-commit run uv-lock --all-files - # Run pre-commit on the translations - uv run pre-commit run checkPo --all-files + # If the uv environment is outdated, running prek will trigger uv to generate a uv.lock file, + # which causes checkPo to fail without clear errors because prek fails when files are changed during its run. + uv run prek run uv-lock --all-files + # Run prek on the translations + uv run prek run checkPo --all-files - name: Add job summary if: ${{ failure() }} shell: bash diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 19a482f33ea..4a36b372f73 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,8 @@ ci: # which CI blocks. # Pyright does not seem to work in pre-commit CI skip: [checkPo, scons-source, checkPot, unitTest, licenseCheck, pyright] - autoupdate_schedule: monthly + autofix_prs: false + autoupdate_schedule: quarterly autoupdate_commit_msg: "Pre-commit auto-update" autofix_commit_msg: "Pre-commit auto-fix" submodules: true @@ -55,13 +56,16 @@ repos: - id: debug-statements # Removes trailing whitespace. - id: trailing-whitespace + groups: [autofix] types_or: [python, c, c++, batch, markdown, toml, yaml, powershell] # Ensures all files end in 1 (and only 1) newline. - id: end-of-file-fixer + groups: [autofix] types_or: [python, c, c++, batch, markdown, toml, yaml, powershell] # Removes the UTF-8 BOM from files that have it. # See https://github.com/nvaccess/nvda/blob/master/projectDocs/dev/codingStandards.md#encoding - id: fix-byte-order-marker + groups: [autofix] types_or: [python, c, c++, batch, markdown, toml, yaml, powershell] # Validates TOML files. - id: check-toml @@ -105,6 +109,7 @@ repos: # if a trailing comma is added. # This adds a trailing comma to args/iterable items in case it was missed. - id: add-trailing-comma + groups: [autofix] - repo: https://github.com/astral-sh/ruff-pre-commit # Matches Ruff version in pyproject. @@ -112,15 +117,18 @@ repos: hooks: - id: ruff name: lint with ruff + groups: [autofix] args: [ --fix ] - id: ruff-format name: format with ruff + groups: [autofix] - repo: https://github.com/astral-sh/uv-pre-commit rev: 0.11.7 hooks: - id: uv-lock name: Verify uv lock file + groups: [autofix] # Override python interpreter from .python-versions as that is too strict for pre-commit.ci args: ["-p3.13"] @@ -129,6 +137,7 @@ repos: hooks: - id: markdownlint-cli2 name: Lint markdown files + groups: [autofix] args: ["--fix"] - repo: local diff --git a/projectDocs/dev/contributing.md b/projectDocs/dev/contributing.md index 08931594f6c..f7a8c53ddd2 100644 --- a/projectDocs/dev/contributing.md +++ b/projectDocs/dev/contributing.md @@ -94,9 +94,11 @@ Refer to ["Proposing Major Changes"](./proposingMajorChanges.md) before opening * Consider if the PR should be made against `beta` or `rc` in the case of addressing bugs introduced in the current release cycle. 1. CI/CD testing: * Every time a PR has a commit pushed to it, CI/CD checks will be run - * [pre-commit.ci](https://pre-commit.ci/) will apply linting fixes. - * re-run pre-commit on a pull request by commenting `pre-commit.ci run`. - * prevent pre-commit from pushing by putting `[skip ci]`, `[ci skip]`, `[skip pre-commit.ci]`, or `[pre-commit.ci skip]` in the commit message. + * GitHub Actions runs a lint check on every PR, which fails until any lint issues are fixed. + * To have lint fixes applied and pushed automatically, enable GitHub Actions on your fork so the autofix workflow runs on your branch pushes. + * When the autofix workflow pushes a fix commit, your PR's checks do re-run, but since that commit is authored by the GitHub Actions bot the run is held for maintainer approval (it shows as "action required" / "approve and run"). + To get the checks running without waiting for approval, push any follow-up commit yourself. + * Otherwise, fix the reported lint issues manually. * GitHub Actions will build a copy of NVDA when changes are pushed to your PR. A build artifact will be created for a successful build to allow for testing the PR. * GitHub Actions will run system tests and other tests. diff --git a/projectDocs/testing/automated.md b/projectDocs/testing/automated.md index cc470c3510d..815a118db8b 100644 --- a/projectDocs/testing/automated.md +++ b/projectDocs/testing/automated.md @@ -3,30 +3,43 @@ If you make a change to the NVDA code, you should run NVDA's automated tests. These tests help to ensure that code changes do not unintentionally break functionality that was previously working. -## Pre-commit hooks +## Git hooks (prek) -[Pre-commit hooks](https://pre-commit.com/) can be used to automatically run linting, translatable string checks and unit tests on files staged for commit. +Git hooks can be used to automatically run linting, translatable string checks and unit tests on files staged for commit. This will automatically apply lint fixes where possible, and will cancel the commit on lint issues and other test failures. +NVDA uses [prek](https://prek.j178.dev/), a faster, drop-in compatible alternative to [pre-commit](https://pre-commit.com/). -From a shell, [set up pre-commit scripts](https://pre-commit.com/#pre-commit-install) for your NVDA python environment: +There are two ways to run prek, and the examples below use both: -`uv run pre-commit install` +* Via the project's uv environment, prefixing commands with `uv run` (e.g. `uv run prek install`). + This needs no separate installation. +* Via a global install, calling `prek` directly (e.g. `prek install`). + Install it once with `uv tool install prek`. -Alternatively, set up pre-commit scripts globally: +From a shell, [set up the Git hooks](https://prek.j178.dev/reference/cli/#prek-install) for your NVDA python environment: -1. `pip install pre-commit` -1. `pre-commit install --allow-missing-config` +`uv run prek install` -To skip pre-commit hooks from triggering, use the `--no-verify` CLI option. +Alternatively, if you installed prek globally, set up the Git hooks with: + +`prek install --allow-missing-config` + +To skip the hooks from triggering, use the `--no-verify` CLI option. Example: `git commit -m "message" --no-verify`. -### Manually running pre-commit hooks +### Switching from pre-commit + +If you previously ran `pre-commit install`, an old `pre-commit` Git hook is still installed. +Run `uv run prek install -f` once to overwrite it with the prek hook. + +### Manually running hooks -You can run pre-commit hooks manually with [`pre commit run`](https://pre-commit.com/#pre-commit-run). +You can run the hooks manually with [`prek run`](https://prek.j178.dev/reference/cli/#prek-run). +The examples below use the project's uv environment (`uv run prek run …`); if you installed prek globally, drop the `uv run` prefix and call `prek run …` directly. * You can filter files with `--files` and `--all-files` * You can also compare two revisions: -`uv run pre-commit run --from-ref origin/master --to-ref HEAD` +`uv run prek run --from-ref origin/master --to-ref HEAD` ## Translatable string checks diff --git a/pyproject.toml b/pyproject.toml index 23a264a04f5..83eb65a3533 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -331,7 +331,7 @@ dev = [ ] lint = [ "ruff==0.15.9", - "pre-commit==4.2.0", + "prek==0.4.4", "pyright[nodejs]==1.1.407", ] license-check = [ diff --git a/readme.md b/readme.md index defd75e247d..e44cc0ee6d5 100644 --- a/readme.md +++ b/readme.md @@ -35,5 +35,4 @@ This includes information on reporting issues, triaging issues, testing, transla * Alpha build status: [![view latest alpha builds](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml/badge.svg?branch=master)](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml?query=branch%3Amaster+event%3Apush) * Beta build status: [![view latest beta builds](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml/badge.svg?branch=beta)](https://github.com/nvaccess/nvda/actions/workflows/testAndPublish.yml?query=branch%3Abeta+event%3Apush) -* Pre-commit status (master): [![view pre-commit checks on master](https://results.pre-commit.ci/badge/github/nvaccess/nvda/master.svg)](https://results.pre-commit.ci/latest/github/nvaccess/nvda/master) * CodeQL security analysis status (master): [![view CodeQL security analysis checks on master](https://github.com/nvaccess/nvda/actions/workflows/codeql.yml/badge.svg)](https://github.com/nvaccess/nvda/actions/workflows/codeql.yml) diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 247a9bbc806..aca58f172a2 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -48,6 +48,10 @@ Please refer to [the developer guide](https://download.nvaccess.org/documentation/developerGuide.html#API) for information on NVDA's API deprecation and removal process. +* The local Git hook runner has been switched from [pre-commit](https://pre-commit.com/) to [prek](https://prek.j178.dev/), a faster, drop-in compatible alternative. (#20305, @LeonarddeR) + * The [pre-commit.ci](https://pre-commit.ci/) integration will be dropped entirely;. + Linting and autofixing now run via GitHub Actions, using an autofix-or-fail workflow plus an automatic `prek auto-update` workflow. + * Developers who previously ran `pre-commit install` should run `uv run prek install -f` once to replace the installed Git hook. * `config.configSections.registerSection` and `config.configSections.unregisterSection` methods can be used to register and unregister configuration sections. (#7467, @nvdaes) * In the `installTasks` module, add-on developers can add a spec for each configuration section to be registered. * The `config.configSections.registerSection` method can be used in the `onInstall` function. diff --git a/uv.lock b/uv.lock index d1ae63dd9da..e636e47cf1a 100644 --- a/uv.lock +++ b/uv.lock @@ -124,15 +124,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, ] -[[package]] -name = "cfgv" -version = "3.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, -] - [[package]] name = "charset-normalizer" version = "3.4.7" @@ -221,15 +212,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/5e/4f5fe4b89fde1dc3ed0eb51bd4ce4c0bca406246673d370ea2ad0c58d747/detect_secrets-1.5.0-py3-none-any.whl", hash = "sha256:e24e7b9b5a35048c313e983f76c4bd09dad89f045ff059e354f9943bf45aa060", size = 120341, upload-time = "2024-05-06T17:46:16.628Z" }, ] -[[package]] -name = "distlib" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/8d/873e9252ea2c0e0c857884e0a2899ec43ade132345df1925ef24cbe64f18/distlib-0.4.2.tar.gz", hash = "sha256:baeb401c90f27acd15c4861ae0847d1e731c27ac3dbf4210643ba61fa1e813db", size = 614914, upload-time = "2026-06-08T16:24:15.439Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/aa891c893821d4d127292ed66c6940d1d715894bd5a0ce048056bc641773/distlib-0.4.2-py2.py3-none-any.whl", hash = "sha256:ca4cb11e5d746b5ec13c199cbf19ae27a241f89702b54e153a74332955446067", size = 470510, upload-time = "2026-06-08T16:24:13.208Z" }, -] - [[package]] name = "docutils" version = "0.21.2" @@ -258,15 +240,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/2b/fd360e1b65ba44179424aa0a8c227c17d7df384f20bb8d38a5cbe23e3ba2/fhconfparser-2024.1-py3-none-any.whl", hash = "sha256:f6048cb646e69a3422a581bc0102150c2b79fe7ff26b82233e5ef52f72820e3e", size = 9221, upload-time = "2024-01-24T21:48:54.81Z" }, ] -[[package]] -name = "filelock" -version = "3.29.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/f5/3557bf28e0f1943e4849154c821533706e6dea010f96fb6aa0b6949037d1/filelock-3.29.3.tar.gz", hash = "sha256:7fc1b3f39cf172fd8203812043c57b8a65aef9969f38b6704f628b881f761a84", size = 61956, upload-time = "2026-06-10T17:37:11.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/8f/b61d427c4f49a8bdadc93f4e7e74df8a6df6f77ee6e26bf0df53d3925363/filelock-3.29.3-py3-none-any.whl", hash = "sha256:e58333029cc9b925f39aad59b1d8f0a1ad836af4e60d7217f4a4dba87461261d", size = 42324, upload-time = "2026-06-10T17:37:10.37Z" }, -] - [[package]] name = "fuzzysearch" version = "0.8.1" @@ -276,15 +249,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/e9/b4/d92b429ba4bfe5461faa358f84092eceb5ea8985cd2e448daf38bba17737/fuzzysearch-0.8.1.tar.gz", hash = "sha256:e5f50962c6b1c3dfc6c8cdfd5e2604838c95cb10118e4cab518e5292e9e0b1c6", size = 39510, upload-time = "2025-11-11T08:47:10.321Z" } -[[package]] -name = "identify" -version = "2.6.19" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, -] - [[package]] name = "idna" version = "3.18" @@ -600,7 +564,7 @@ license-check = [ { name = "licensecheck", marker = "sys_platform == 'win32'" }, ] lint = [ - { name = "pre-commit", marker = "sys_platform == 'win32'" }, + { name = "prek", marker = "sys_platform == 'win32'" }, { name = "pyright", extra = ["nodejs"], marker = "sys_platform == 'win32'" }, { name = "ruff", marker = "sys_platform == 'win32'" }, ] @@ -659,7 +623,7 @@ dev-docs = [ ] license-check = [{ name = "licensecheck", specifier = "==2025.1" }] lint = [ - { name = "pre-commit", specifier = "==4.2.0" }, + { name = "prek", specifier = "==0.4.4" }, { name = "pyright", extras = ["nodejs"], specifier = "==1.1.407" }, { name = "ruff", specifier = "==0.15.9" }, ] @@ -758,19 +722,14 @@ wheels = [ ] [[package]] -name = "pre-commit" -version = "4.2.0" +name = "prek" +version = "0.4.4" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cfgv", marker = "sys_platform == 'win32'" }, - { name = "identify", marker = "sys_platform == 'win32'" }, - { name = "nodeenv", marker = "sys_platform == 'win32'" }, - { name = "pyyaml", marker = "sys_platform == 'win32'" }, - { name = "virtualenv", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/13/3d71b3adbf385f7dc7fb6e16d6e25421fd8398b45d8f8410a328bf22bd3f/prek-0.4.4.tar.gz", hash = "sha256:4ec5771153d158a0e4473933b7fd9b51e1b1f57f2df50aeb7560ea6812226dc5", size = 470641, upload-time = "2026-06-04T07:26:07.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/a4ddbf38034afe67cfa97c4bd81c86429ada098e7c323218d9f9fd061566/prek-0.4.4-py3-none-win32.whl", hash = "sha256:143154b329c05b2f9fa3230e604d02d9c4297dd43f96135a8ba166772e8ecd60", size = 5240317, upload-time = "2026-06-04T07:26:08.726Z" }, + { url = "https://files.pythonhosted.org/packages/bc/8c/fe97b5b095187bb2f93bbe406bccf108c879e5e4c83f165809b0d16ce0fb/prek-0.4.4-py3-none-win_amd64.whl", hash = "sha256:c38c5140ae2ea55ebb02e6ca590a416664ea1af287cdd21f54daeec53a81015a", size = 5626104, upload-time = "2026-06-04T07:26:14.81Z" }, + { url = "https://files.pythonhosted.org/packages/25/63/3586226d536796e65f8e725b531d6104e55caaa18659bdcb512661629586/prek-0.4.4-py3-none-win_arm64.whl", hash = "sha256:3efa28fb37b9ddbafb7759da8d497f0d36cf02a05816e15d6541f5669d5d2114", size = 5470399, upload-time = "2026-06-04T07:26:13.231Z" }, ] [[package]] @@ -931,19 +890,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0", size = 90585, upload-time = "2020-11-23T03:59:13.41Z" }, ] -[[package]] -name = "python-discovery" -version = "1.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "filelock", marker = "sys_platform == 'win32'" }, - { name = "platformdirs", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/1a/cbbaf13b730abb0a16b964d984e19f2fe520c21a4dc664051359a3f5a9e7/python_discovery-1.4.2.tar.gz", hash = "sha256:8f3746c4b4968d22afbb97d36e1a0e5b66e6c0f297290f2e95f05b9b8bf18690", size = 70277, upload-time = "2026-06-11T16:10:42.383Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/82/a70006589557f267f15bd384c0642ad49f0d97b690c3a05b166b9dcbad3b/python_discovery-1.4.2-py3-none-any.whl", hash = "sha256:475803f53b7b2ed6e490e27373f9d8340f7d2eebf9acdaf645d7d714c97bb500", size = 33886, upload-time = "2026-06-11T16:10:41.192Z" }, -] - [[package]] name = "pytweening" version = "1.2.0" @@ -1305,21 +1251,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1b/bb/e6bfdea92ed270f3445a5a3c17599d041b3f2dbc5026c09e02830a03bbaf/uv-0.11.7-py3-none-win_arm64.whl", hash = "sha256:6158b7e39464f1aa1e040daa0186cae4749a78b5cd80ac769f32ca711b8976b1", size = 23941816, upload-time = "2026-04-15T21:43:06.732Z" }, ] -[[package]] -name = "virtualenv" -version = "21.4.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib", marker = "sys_platform == 'win32'" }, - { name = "filelock", marker = "sys_platform == 'win32'" }, - { name = "platformdirs", marker = "sys_platform == 'win32'" }, - { name = "python-discovery", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4b/50/7564c805bb8966d9771caaba8a143fa5e57c848ce4e7fdf2d55a1feb2ead/virtualenv-21.4.3.tar.gz", hash = "sha256:938ff0fd3f4e0f0d3a025f67a3d2f25e3c3aabbcd5857ea6170619138d72d141", size = 7644454, upload-time = "2026-06-11T16:47:04.843Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/8d/84b0d07c6b5f685f85ddf6c87a59d3a8a895a3dfd89e759666fabe951b94/virtualenv-21.4.3-py3-none-any.whl", hash = "sha256:75f4127d4067397c64f38579ce918fec6bf9ca2cd4f48685e82952cc3c035840", size = 7625544, upload-time = "2026-06-11T16:47:01.78Z" }, -] - [[package]] name = "win32-setctime" version = "1.2.0"