From ec28ad8db3306493aaa0282b8152e8f22cf08d00 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Thu, 5 Nov 2026 23:07:37 +0000 Subject: [PATCH 1/5] Install uv with mise in CI Replace astral-sh/setup-uv with jdx/mise-action. CI now runs the uv version in mise.lock, which is the version that local development uses. The release workflow disables the mise cache, as it did for the setup-uv cache (zizmor cache-poisoning). Dependabot does not update mise.lock. To update uv, run `mise upgrade uv` and commit mise.lock. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 7 +++--- .github/workflows/test.yml | 13 +++++++++--- mise.lock | 40 +++++++++++++++++++++++++++++++++++ mise.toml | 1 + 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de545d6..7c773d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,11 +22,12 @@ jobs: submodules: true persist-credentials: false - - name: Install the latest version of uv - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + - name: Install uv + uses: jdx/mise-action@82a612c5ab8bcda7cc5db6b7e81a8e7584c3dc6e # v5.2.3 with: + install_args: uv # Disable caching in the release workflow (zizmor cache-poisoning). - enable-cache: false + cache: false - name: Build run: uv build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79eaf8d..aa2136a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,10 +22,17 @@ jobs: with: submodules: true persist-credentials: false - - name: Install the latest version of uv - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + - name: Install uv + uses: jdx/mise-action@82a612c5ab8bcda7cc5db6b7e81a8e7584c3dc6e # v5.2.3 + with: + install_args: uv - name: Install tox - run: uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv --with tox-gh + shell: bash + run: | + uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv --with tox-gh + # mise-action, unlike setup-uv, does not add the uv tool bin + # directory to PATH. Windows runners need it. + uv tool dir --bin >> "$GITHUB_PATH" - name: Install Python if: matrix.env != '3.13' run: uv python install --python-preference only-managed ${{ matrix.env }} diff --git a/mise.lock b/mise.lock index 09ffa7e..c1f5a44 100644 --- a/mise.lock +++ b/mise.lock @@ -33,3 +33,43 @@ url_api = "https://api.github.com/repos/lycheeverse/lychee/releases/assets/40995 checksum = "sha256:32975d1493ee1a975d6bb41e4fb56fe419cb442ded628bb772ba2e614acfacad" url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.24.2/lychee-x86_64-pc-windows-msvc.zip" url_api = "https://api.github.com/repos/lycheeverse/lychee/releases/assets/409959491" + +[[tools.uv]] +version = "0.13.7" +backend = "aqua:astral-sh/uv" + +[tools.uv."platforms.linux-arm64"] +checksum = "sha256:71279f8d3c67241e807b9d8db872d1bf541579fb9f08b7d1eb1682196d1e57dc" +url = "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-aarch64-unknown-linux-gnu.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/704009469" +provenance = "github-attestations" + +[tools.uv."platforms.linux-arm64-musl"] +checksum = "sha256:2d3ec076a0c4c0e8250bb6418c44080828b544f1a3be0b6e46adf9fb6923de45" +url = "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-aarch64-unknown-linux-musl.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/704009487" +provenance = "github-attestations" + +[tools.uv."platforms.linux-x64"] +checksum = "sha256:c5221ff41b7892bfc223543883600125f6a47fe845093e0f5bdff4f359196d83" +url = "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-x86_64-unknown-linux-gnu.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/704009823" +provenance = "github-attestations" + +[tools.uv."platforms.linux-x64-musl"] +checksum = "sha256:287491da03f2a785c70fa75b13e1f849918c2f2b5415fe84876b8214eeb792f9" +url = "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-x86_64-unknown-linux-musl.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/704009859" +provenance = "github-attestations" + +[tools.uv."platforms.macos-arm64"] +checksum = "sha256:81b811b57e4624df7ed3aac148e0359100d9962f3d9dce00aec533dc2e086731" +url = "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-aarch64-apple-darwin.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/704009442" +provenance = "github-attestations" + +[tools.uv."platforms.windows-x64"] +checksum = "sha256:0cdc5b38fe5a8168ed6a25814f5ba43c21d313dd3187314fccb37b7cec46e021" +url = "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-x86_64-pc-windows-msvc.zip" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/704009796" +provenance = "github-attestations" diff --git a/mise.toml b/mise.toml index fff9190..bf617c3 100644 --- a/mise.toml +++ b/mise.toml @@ -3,6 +3,7 @@ lockfile = true [tools] lychee = "latest" +uv = "latest" [tasks.check-links] description = "Check links with lychee" From 44b49987e3c7960ce6b8c3dc3780377bf729a983 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 6 Nov 2026 19:00:55 +0000 Subject: [PATCH 2/5] Make tox use the uv on PATH tox-uv depends on the uv package from PyPI, and tox then uses that bundled uv. In CI, this was the newest uv on PyPI, not the uv in mise.lock. Locally, it was the uv in uv.lock. tox-uv-bare does not bundle uv. It uses the uv on PATH, which is the mise-installed uv in CI. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 2 +- pyproject.toml | 2 +- uv.lock | 42 ++------------------------------------ 3 files changed, 4 insertions(+), 42 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aa2136a..1c660ab 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: - name: Install tox shell: bash run: | - uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv --with tox-gh + uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv-bare --with tox-gh # mise-action, unlike setup-uv, does not add the uv tool bin # directory to PATH. Windows runners need it. uv tool dir --bin >> "$GITHUB_PATH" diff --git a/pyproject.toml b/pyproject.toml index 71ebd2f..427ccb5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ classifiers = [ dev = [ "pytest>=8.3.5", "pytest-httpserver>=1.0.10", - "tox-uv>=1.29.0", + "tox-uv-bare>=1.32.0", ] lint = [ "mypy>=1.15.0", diff --git a/uv.lock b/uv.lock index d9f814f..aeb6fab 100644 --- a/uv.lock +++ b/uv.lock @@ -847,7 +847,7 @@ dependencies = [ dev = [ { name = "pytest" }, { name = "pytest-httpserver" }, - { name = "tox-uv" }, + { name = "tox-uv-bare" }, ] lint = [ { name = "mypy" }, @@ -868,7 +868,7 @@ requires-dist = [ dev = [ { name = "pytest", specifier = ">=8.3.5" }, { name = "pytest-httpserver", specifier = ">=1.0.10" }, - { name = "tox-uv", specifier = ">=1.29.0" }, + { name = "tox-uv-bare", specifier = ">=1.32.0" }, ] lint = [ { name = "mypy", specifier = ">=1.15.0" }, @@ -1368,18 +1368,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/03/02e2a03f3756cfb66e7e1bac41b06953f12cec75ddb961d56695d4d43dc4/tox-4.53.0-py3-none-any.whl", hash = "sha256:cc4e716d18c4889aa179d785175c438fa60c35deef20ce689ec288d8fb656096", size = 212164, upload-time = "2026-04-14T13:44:11.997Z" }, ] -[[package]] -name = "tox-uv" -version = "1.36.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tox-uv-bare" }, - { name = "uv" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/ef/06e0f151d1ebb544bcf27bf8a6914bdc7d9434689278c669efb3c73a8ed5/tox_uv-1.36.1-py3-none-any.whl", hash = "sha256:6996cb49d0b6b838ae015b76611770595cb6f658a27e2a9661766148194c18bd", size = 6567, upload-time = "2026-10-01T23:51:58.511Z" }, -] - [[package]] name = "tox-uv-bare" version = "1.36.1" @@ -1412,32 +1400,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" }, ] -[[package]] -name = "uv" -version = "0.13.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/55/609455d21e87430c11fe734abfced50a3bdf177b2f49d41fbb19c199cbc3/uv-0.13.4.tar.gz", hash = "sha256:b0bff5b9a5061f7a35b1d0c1a94c19af134222c48eb7aadc42f85a038be1b248", size = 7482486, upload-time = "2026-10-20T15:12:06.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/bd/4349da5356b17a1c0e36c8552c809925f86f6292de9b1f599f01e8e8093d/uv-0.13.4-py3-none-linux_armv6l.whl", hash = "sha256:205a4f93e568fb24f45a2f3834f1c0a8f1adb5f396bf473c71030ed707dce048", size = 18272390, upload-time = "2026-10-20T15:11:02.468Z" }, - { url = "https://files.pythonhosted.org/packages/21/f2/0cb77a1ae43959772f8f7873eb1f4061907fbb1694ce55c79b231f639b1d/uv-0.13.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b4bbacea78c9db136cd2ec3147cbfd9ed910b4db5e1877109bd74d0e73bb2eaf", size = 17384113, upload-time = "2026-10-20T15:11:07.172Z" }, - { url = "https://files.pythonhosted.org/packages/26/44/5a8733dd1b2e8d6f9cffd1ff6428a3e11dcc7e146a7657e32cfb8d9fb4a4/uv-0.13.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:95f4eb2b991b53b50ec2b18ab612fca8ba1e7a75a47af0331fb8bcd21da3eb03", size = 14433723, upload-time = "2026-10-20T15:11:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/f8/39/be14f051bf34a1822d634819890a2d0cba3b69101e633fb7b9f54d7b4020/uv-0.13.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:e90ab42825587821096cb0d071e387468da38cfa22818c91f9c0b3c0453048e8", size = 17816443, upload-time = "2026-10-20T15:11:13.674Z" }, - { url = "https://files.pythonhosted.org/packages/97/a0/5df0f8bc6367dd37b98432a7c462e2918554f6db2a71211574852b8f0727/uv-0.13.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:3a9dcb6762c3ba249d8c084315ba03839082af3ece3536cc4164ec735c351d68", size = 17828025, upload-time = "2026-10-20T15:11:16.806Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9c/2fed5357700b7c304b94214979e4efe680c3bc6e337a97eedaa372fe0947/uv-0.13.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ae6ff2b07892379dc767c9064c2b8bbfac88e767edac7ce28e1b0f15d86abb4", size = 17843737, upload-time = "2026-10-20T15:11:20.043Z" }, - { url = "https://files.pythonhosted.org/packages/4c/2e/ee026284f096236dc3e1abed0316f9edab65c0ea176ea0072c064e62478d/uv-0.13.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25cc14ff4fd8335d3be2cc493a621a003fdafcb0fb1c953c905daabe4def5ab8", size = 18576350, upload-time = "2026-10-20T15:11:24.035Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f1/67fbdb649c8c5d0cb38ea74829080479b77c8631cda5d77fc1b28f027ca7/uv-0.13.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77062b02856c74697f48328d8a6583ab07e6da0a993e86c2db46f3d1da27c637", size = 19831234, upload-time = "2026-10-20T15:11:27.627Z" }, - { url = "https://files.pythonhosted.org/packages/bd/00/7d49e3a1a3e98e5244fa38e0c964dc8de568bf3bb101257a63dc2602efed/uv-0.13.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb0e2028d9a8929884344afb7d91d0f65d9783f640d28aede89fca3602bedde9", size = 19702886, upload-time = "2026-10-20T15:11:31.128Z" }, - { url = "https://files.pythonhosted.org/packages/4b/a1/de02c0913726728eca56ee258875cbba9c7b0572c63f494fd9f55c7852e3/uv-0.13.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e4332791b4d55b6dde8695b7fa6079b26991519f44760887c5dfbd5ca4fe53", size = 17181168, upload-time = "2026-10-20T15:11:34.583Z" }, - { url = "https://files.pythonhosted.org/packages/a8/cd/f4a3c7377674366798c56aabd0f9a1f05687c3939f5ba857a3ea6093ff84/uv-0.13.4-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:7b3cdf868e5415631fe797b648c0d6945d38d388f23367bdd0b6332e80a1fcb0", size = 16502020, upload-time = "2026-10-20T15:11:37.88Z" }, - { url = "https://files.pythonhosted.org/packages/f9/f4/ce79657c5a0f51b602db9a663529baafff03b9fe8cc41e09ad3f7246b88a/uv-0.13.4-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:4e6b08578c920b86910897f36bb6da7229c8e7e0187976570e2a538cb28b777e", size = 18000980, upload-time = "2026-10-20T15:11:41.59Z" }, - { url = "https://files.pythonhosted.org/packages/21/e6/7d77022d5661f8e01578bc5423bf02af408220e7e7ac5ee15eb94742c7cb/uv-0.13.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:d86a5dec8ab30c70519c71ca5085c8aaf28664836cbc600951cedaa3fc678cbf", size = 18179083, upload-time = "2026-10-20T15:11:45.191Z" }, - { url = "https://files.pythonhosted.org/packages/f4/40/1bf0324800d38009774ba087a6fbffddc76a3e5bf42c081b9298b1236fb5/uv-0.13.4-py3-none-musllinux_1_1_i686.whl", hash = "sha256:5d89d1028c2e22977d9215cbb79cfe12559cb0c8a507a12e2f3a7e47930cf1bf", size = 18010389, upload-time = "2026-10-20T15:11:48.963Z" }, - { url = "https://files.pythonhosted.org/packages/1e/ec/f352ca2cc3b4b6191bb4ec8cdf4bc190eed0ba8bda4c33b7fd66c5d33cec/uv-0.13.4-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:52b5c753a7c2d5f8323a70bb4c93118988356331d0758afa6446c81f974e7196", size = 19004998, upload-time = "2026-10-20T15:11:52.628Z" }, - { url = "https://files.pythonhosted.org/packages/9e/4f/fc05ff4292edfe785b47874ec86d3d83ca2bf735cff8a9d2170ffb66ad83/uv-0.13.4-py3-none-win32.whl", hash = "sha256:d333f01852b817ba05612de31474739da1af7e5463d119b30a9c4331eba1f408", size = 16190502, upload-time = "2026-10-20T15:11:56.657Z" }, - { url = "https://files.pythonhosted.org/packages/2f/b9/b526eab6c72eacc705a58378f6850fde046b28c86fed01bd42da61367c6b/uv-0.13.4-py3-none-win_amd64.whl", hash = "sha256:b2ff80397273fff0e02c20eacae6882834c811827d6fc08f658db156fe754386", size = 15331833, upload-time = "2026-10-20T15:11:59.733Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/4d5fa89d3d10ff6a84e547ef6e02c45b2f2d50e66682da778acf60db63f1/uv-0.13.4-py3-none-win_arm64.whl", hash = "sha256:deffa5a4afdb48f3e44fb26e80377d256b330ddcad0373daff4b54f6162b43a4", size = 15690151, upload-time = "2026-10-20T15:12:02.74Z" }, -] - [[package]] name = "virtualenv" version = "21.14.13" From 848e2bbaf2ed2cd864df500df7518fc584c3c634 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 6 Nov 2026 19:01:28 +0000 Subject: [PATCH 3/5] Run tox with uvx in CI uvx runs tox without installing it as a uv tool. The workflow no longer needs to add the uv tool bin directory to PATH or force bash on Windows. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1c660ab..0d4f62c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,17 +26,10 @@ jobs: uses: jdx/mise-action@82a612c5ab8bcda7cc5db6b7e81a8e7584c3dc6e # v5.2.3 with: install_args: uv - - name: Install tox - shell: bash - run: | - uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv-bare --with tox-gh - # mise-action, unlike setup-uv, does not add the uv tool bin - # directory to PATH. Windows runners need it. - uv tool dir --bin >> "$GITHUB_PATH" - name: Install Python if: matrix.env != '3.13' run: uv python install --python-preference only-managed ${{ matrix.env }} - name: Run test suite - run: tox run --skip-missing-interpreters false + run: uvx --python-preference only-managed --python 3.13 --with tox-uv-bare --with tox-gh tox run --skip-missing-interpreters false env: TOX_GH_MAJOR_MINOR: ${{ matrix.env }} From f31fab18af5366b9223a811da024fac8dc8d7854 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 6 Nov 2026 19:01:34 +0000 Subject: [PATCH 4/5] Name the mise step "Install uv with mise" The step installs mise, and mise.toml sets the uv version. The new name tells a reader where to change the uv version. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c773d5..13ba2d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: submodules: true persist-credentials: false - - name: Install uv + - name: Install uv with mise uses: jdx/mise-action@82a612c5ab8bcda7cc5db6b7e81a8e7584c3dc6e # v5.2.3 with: install_args: uv diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d4f62c..7808bf5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: with: submodules: true persist-credentials: false - - name: Install uv + - name: Install uv with mise uses: jdx/mise-action@82a612c5ab8bcda7cc5db6b7e81a8e7584c3dc6e # v5.2.3 with: install_args: uv From dbf3abdf967bd96b8a80e368263375ef6f5a0eaf Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 6 Nov 2026 19:01:43 +0000 Subject: [PATCH 5/5] Document installing uv with mise CI installs the uv version in mise.lock. The setup instructions now use the same version. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 6954b8c..2419f4a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -397,8 +397,8 @@ Adding required parameters breaks existing code. ### Setup ```bash -# Install uv if not already installed -curl -LsSf https://astral.sh/uv/install.sh | sh +# Install the uv version in mise.lock, which CI also uses +mise install uv # Install all dependencies including dev and lint groups uv sync --all-groups