ci: install Python via astral-sh/setup-uv to skip slow downloads#1351
Closed
bdraco wants to merge 4 commits into
Closed
ci: install Python via astral-sh/setup-uv to skip slow downloads#1351bdraco wants to merge 4 commits into
bdraco wants to merge 4 commits into
Conversation
The macOS and Windows hosted runners do not keep pre-release or free-threaded CPython variants in the tool-cache, so `actions/setup-python` falls back to downloading them from the `python-versions` repo on each run. For `3.14t` that adds tens of seconds to jobs whose pytest run is shorter than the install step. `astral-sh/setup-uv` fetches python-build-standalone from a CDN and creates a seeded venv, which completes in a few seconds for the same matrix entries. `activate-environment: true` keeps `python`/`pip` on PATH so the rest of the pipeline (`py-actions/py-dependency-install`, inline `pip install` calls, and the standalone `Compute runtime Python version` step) is unchanged. The `allow-prereleases` input has no equivalent on setup-uv because uv treats prereleases as first-class.
The floating `v8` major tag does not exist; setup-uv switched to immutable releases at v8.0.0 and only publishes per-version tags from then on. Use the exact `v8.1.0` tag (same style as the existing `sigstore/gh-action-sigstore-python@v3.3.0` pin).
When `actions/setup-python` was the interpreter source, the `Get pip cache dir` + `Cache PyPI` pair sped up the pip HTTP cache across runs. With `astral-sh/setup-uv` and `activate-environment: true` the venv is created without `--seed`, so pip is missing and the wrapper's `pip cache dir` probe crashes the job. Rather than seed pip back in just to keep the wrapper working, go uv-native: * Drop the `Get pip cache dir` + `Cache PyPI` pair (and the `actions/cache@v5` invocation) from the test-matrix job. * Set `enable-cache: true` on both `setup-uv` invocations so uv's own wheel cache is persisted across runs. * Replace `py-actions/py-dependency-install@v4` with a one-line `uv pip install -r requirements/pytest.txt`. * Collapse the `pip --dry-run --report=-` + `jq` wheel-discovery trick and the follow-up `pip install <url>` into a single `uv pip install --find-links=./dist --no-index --no-deps --force-reinstall --only-binary=:all: multidict`. uv resolves the matching wheel for the active interpreter directly, so the intermediate JSON parse is unnecessary. * Split the conditional `Self-install` step into two clearer steps gated on `build_type`; the source-build branch keeps the `MULTIDICT_NO_EXTENSIONS` / `MULTIDICT_DEBUG_BUILD` env pair, the wheel branch does not need either. * Swap the inline `python -Im pip install build` in the build-pure-python-dists job for `uv pip install build` so the whole pipeline uses one cache. Net: -65 lines, no more pip dependency in the venv, and every install benefits from uv's resolver and cache.
`actions/setup-python@v6` accepts the `3.x` shorthand to mean
"latest 3.x release", but `astral-sh/setup-uv` passes the value
straight through to `uv venv --python <ver>`, and uv has no such
shorthand. The build-pure-python-dists job is the only consumer
of `${{ env.PYTHON_LATEST }}` in this workflow and was failing
with:
error: No interpreter found for executable name `3.x` in
managed installations or search path
Pin `PYTHON_LATEST` to `3.13`, matching the concrete-pin style
already in use by `reusable-linters.yml` (`PYTHON_LATEST: 3.12`)
and yarl's analogous job (`PYTHON_LATEST: 3.12`). Bump to 3.13
specifically because the test matrix already exercises 3.13 as
a stable target.
Member
Author
|
Closing in favor of a fresh PR with a clean single-commit history; the iterative back-and-forth on this branch (initial swap, v8.1.0 pin, pip-cache drop, PYTHON_LATEST fix) is noise. Reopening as a single coherent commit. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What do these changes do?
Port aio-libs/yarl#1704 to multidict. Three logical steps, mirrored
1:1 in the commit history:
actions/setup-python@v6forastral-sh/setup-uv@v8inthe two CI jobs that install a Python interpreter
(
build-pure-python-distsand the matrixtest).activate-environment: truekeepspython/pipon PATH sothe rest of the pipeline is unchanged. The
allow-prereleasesinput has no equivalent on setup-uv because uv treats prereleases
as first-class.
v8.1.0tag. The floatingv8major tagdoes not exist; setup-uv switched to immutable releases at v8.0.0
and only publishes per-version tags from then on.
py-actions/py-dependency-installand install via
uv pipinstead.setup-uvdoes not seedpip into the venv, so the existing
pip cache dirprobe wouldcrash the job; rather than seed pip back in just to keep the
wrapper working, switch to
enable-cache: true(which persistsuv's own wheel cache across runs) and
uv pip install -r requirements/pytest.txt. Thepip --dry-run --report=- | jqwheel-discovery trick collapses into a single
uv pip install --find-links=./distcall; uv picks the right wheel for theactive interpreter directly.
Net: 58 fewer lines in the workflow and one tool (uv) doing both
the interpreter install and the dependency install with one cache.
Are there changes in behavior for the user?
No. This only affects CI runner provisioning. End-user-visible
behavior of
multidictis unaffected.Unlike yarl, multidict computes its runtime Python version in a
separate
Compute runtime Python versionstep rather thanreading
steps.python-install.outputs.python-versionoff thesetup action, so no Codecov flag shape changes here.
Is it a substantial burden for the maintainers to support this?
No.
astral-sh/setup-uvis widely used across aio-libs and thebroader Python ecosystem;
activate-environment: trueplusuv pip installreproduce the behavior the existing pipelinealready relies on.
Related issue number
N/A; ports aio-libs/yarl#1704 across to
multidict, whose matrix has the same
3.14tentry on macOS andWindows.
Checklist
CONTRIBUTORS.txtCHANGES/folder (1351.contrib.rst)Agent run details (optional, for reviewers)
Drafted with Claude Code (Opus 4.7); reviewed by @bdraco.
Direct port of aio-libs/yarl#1704 (merged). Commits mirror the
yarl PR's structure so the diff is easy to compare side-by-side:
ci: install Python via astral-sh/setup-uv to skip slow downloadsd10eecbci: pin astral-sh/setup-uv to the exact v8.1.0 tag07327e0ci: drop pip cache wrapper, install via uv pipd4ab3be(yarl's intermediate
Symlink CHANGES/1704.contrib.rst -> 1703.contrib.rstcommit does not apply here -- multidict has no separate tracking issue,
so the news fragment is named after the PR directly.)
This is a CI-only change; it cannot be exercised against the local
test suite. The full proof is the post-merge CI run on this PR
showing the matrix completing on all three OSes, which the
operator will check before flipping the PR out of draft.
Local verification:
make doc-spellingpasses for the new fragment (the fivemisspellings reported are pre-existing entries in
CHANGES.rst;the new
1351.contrib.rstis scanned bysphinxcontrib-towncrierand clean).pre-commitran on each commit: YAML lint, workflowvalidation, and the changelog/news-fragment role check all pass.