Skip to content

Install Python via astral-sh/setup-uv to skip 40-58s downloads#1704

Merged
bdraco merged 4 commits into
masterfrom
ci/uv-setup-python
May 18, 2026
Merged

Install Python via astral-sh/setup-uv to skip 40-58s downloads#1704
bdraco merged 4 commits into
masterfrom
ci/uv-setup-python

Conversation

@bdraco

@bdraco bdraco commented May 18, 2026

Copy link
Copy Markdown
Member

What do these changes do?

Swap actions/setup-python@v6 for astral-sh/setup-uv@v8 in the
two CI jobs that install a Python interpreter: the
build-pure-python-dists step and the matrix test step.
activate-environment: true keeps python/pip on PATH so the
rest of the pipeline (re-actors/cache-python-deps,
py-actions/py-dependency-install, inline pip install calls)
is unchanged.

Are there changes in behavior for the user?

No. This only affects CI runner provisioning. End-user-visible
behavior of yarl is unaffected.

The Codecov flag derived from
steps.python-install.outputs.python-version now reports the
matrix spec (3.14t) rather than the resolved patch
(3.14.5t); coarser, but easier to group across patch releases.

Is it a substantial burden for the maintainer to support this?

No. astral-sh/setup-uv is widely used across aio-libs and the
broader Python ecosystem; activate-environment: true reproduces
the behavior the existing pipeline already relies on, so the swap
is local to the action invocation.

Related issue number

Closes #1703.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist — N/A (CI configuration)
  • Documentation reflects the changes — N/A (no user-visible change)
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt
  • Add a new news fragment into the CHANGES/ folder (1703.contrib.rst)
Agent run details (optional, for reviewers)

Drafted with Claude Code (Opus 4.7); reviewed by @bdraco.

Motivation pulled from PR #1682 run
https://github.com/aio-libs/yarl/actions/runs/26049305898, where
Setup Python 3.14t took 40s on macos-latest and 58s on
windows-latest for a test step that ran in 9-18s. Per-job
breakdown (setup vs. tests, all in seconds):

Job Setup Python Tests
3.14t, macos-latest 40 9
3.14t, windows-latest 58 18
3.14t, ubuntu-latest 10 17
3.10, macos-latest 27 11
everything else 0-1 7-21

Linux has the slow variants in hostedtoolcache; macOS/Windows
do not. astral-sh/setup-uv fetches python-build-standalone from
a CDN, which is consistently a few seconds across all three OSes.

Local verification: ran uv python install 3.14t,
uv venv --python 3.14t --seed, activated, and confirmed
python -Im pip install build works exactly as before. That is
the same sequence setup-uv runs with
activate-environment: true.

The macOS and Windows hosted runners don't 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 took 40s on
macOS and 58s on Windows, dominating jobs whose pytest run is only
9-18s.

`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 (`re-actors/cache-python-deps`,
`py-actions/py-dependency-install`, the inline `pip install` steps)
is unchanged.

The `allow-prereleases` input has no equivalent on setup-uv because
uv treats prereleases as first-class. The codecov flag derived from
`steps.python-install.outputs.python-version` now reports the matrix
spec (`3.14t`) rather than the resolved patch (`3.14.5t`); coarser
but easier to group across patch releases.

Closes #1703.
@psf-chronographer psf-chronographer Bot added the bot:chronographer:provided There is a change note present in this PR label May 18, 2026
Symlink CHANGES/1704.contrib.rst -> 1703.contrib.rst so towncrier
picks up both the issue and the PR cross-reference.
@coveralls

coveralls commented May 18, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 26050613112

Coverage remained the same at 98.724%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 6132
Covered Lines: 6053
Line Coverage: 98.71%
Relevant Branches: 61
Covered Branches: 61
Branch Coverage: 100.0%
Branches in Coverage %: Yes
Coverage Strength: 0.99 hits per line

💛 - Coveralls

bdraco added 2 commits May 18, 2026 10:50
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
companion `re-actors/cache-python-deps` action 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 cache wrapper's
`python -Im pip cache dir` probe crashes the job.

Rather than seed pip back in just to keep the wrapper working,
go uv-native:

* Drop the `Calculate cache key` + `Set up pip cache` pair from
  both the build-sdist and test-matrix jobs.
* Set `enable-cache: true` on the two `setup-uv` invocations so
  uv's own wheel cache ($UV_CACHE_DIR) is persisted across runs.
* Replace `py-actions/py-dependency-install` with a one-line
  `uv pip install -r requirements/test.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: yarl`. uv resolves the
  matching wheel for the active interpreter directly, so the
  intermediate JSON parse is unnecessary.
* Swap the remaining inline `pip install build` and
  `pip install expandvars` calls for `uv pip install` so the
  whole pipeline uses one cache.

Net: -53 lines, no more pip dependency in the venv, and every
install benefits from uv's resolver and cache.

Verified locally: `uv venv --python 3.12` (unseeded) +
`uv pip install -r requirements/test.txt` succeeds against the
real requirements file (resolves through to `pygments==2.20.0`,
`pytest==9.0.3`, etc.) without needing pip in the venv.
@bdraco

bdraco commented May 18, 2026

Copy link
Copy Markdown
Member Author

@aiolibsbot review

@bdraco bdraco changed the title ci: install Python via astral-sh/setup-uv to skip 40-58s downloads Install Python via astral-sh/setup-uv to skip 40-58s downloads May 18, 2026
@codspeed-hq

codspeed-hq Bot commented May 18, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 97 untouched benchmarks


Comparing ci/uv-setup-python (d4ab3be) with master (121cf0d)

Open in CodSpeed

@aiolibsbot

Copy link
Copy Markdown
Contributor

PR Review — ci: install Python via astral-sh/setup-uv to skip 40-58s downloads

Clean CI swap, well motivated by the runtime numbers in the PR body. The replacement is local to the two action invocations: astral-sh/setup-uv with activate-environment: true keeps python/pip on PATH so the downstream py-actions/py-dependency-install, pep_517_backend invocation, and inline pip calls keep working, and the loss of re-actors/cache-python-deps is offset by setup-uv's enable-cache: true. The two-step "determine pre-compiled wheel" + "Self-install" dance is correctly simplified to a single uv pip install --find-links=./dist --no-index --no-deps --force-reinstall --only-binary=:all: because dependencies are already installed by the preceding uv pip install -r requirements/test.txt. The Codecov flag becoming 3.14t instead of 3.14.5t is called out in the body, so reviewers won't be surprised. The news fragment is correctly named for the issue (1703.contrib.rst) with a symlinked 1704.contrib.rst so both numbers resolve in towncrier, matching the convention in AGENTS.md. Only minor notes are an action-pin style nit and confirming the 3.14t matrix leg resolves without allow-prereleases; neither is blocking.


🟢 Suggestions

1. Version pin style inconsistent with the rest of the workflow (`.github/workflows/ci-cd.yml`, L80)

The rest of this file pins third-party actions to a major version (actions/checkout@v6, actions/setup-python@v6, re-actors/cache-python-deps@release/v1), but the two new lines pin astral-sh/setup-uv@v8.1.0 to a specific patch. That's not wrong — pinning a patch is more conservative — but it does mean this action won't pick up the same kind of "latest within major" bumps the other actions do, and a future contributor who notices the inconsistency may flip it back without thinking. Pick one style and apply it both at line 80 and line 268; @v8 matches the rest of the file, @v8.1.0 is fine if you want it locked. Not a blocker.

uses: astral-sh/setup-uv@v8.1.0
2. `allow-prereleases: true` dropped — confirm 3.14t still resolves (`.github/workflows/ci-cd.yml`, L268-270)

The old actions/setup-python step set allow-prereleases: true so prerelease specs like 3.14t (the free-threaded build) would resolve against the hosted toolcache's pre-release listings. astral-sh/setup-uv doesn't have an equivalent flag because uv pulls from python-build-standalone and treats prereleases the same as releases, so this should be fine — but it's the one behavioural delta that's silent in the diff. Worth confirming in the matrix that the 3.14t leg actually picks up a free-threaded interpreter on all three OS targets before you flip out of draft. The CI run linked in the PR body is the proof point; if those legs are green, this comment is closeable.

uses: astral-sh/setup-uv@v8.1.0
      with:
        python-version: ${{ matrix.pyver }}

Checklist

  • No hardcoded secrets
  • Input validation at boundaries
  • Resource cleanup / no leaks
  • News fragment present and named correctly
  • PR follows aio-libs template
  • No regressions in caching behaviour
  • Action version pinning consistent — suggestion #1
  • Prerelease Python handling preserved — suggestion #2

Summary

Clean CI swap, well motivated by the runtime numbers in the PR body. The replacement is local to the two action invocations: astral-sh/setup-uv with activate-environment: true keeps python/pip on PATH so the downstream py-actions/py-dependency-install, pep_517_backend invocation, and inline pip calls keep working, and the loss of re-actors/cache-python-deps is offset by setup-uv's enable-cache: true. The two-step "determine pre-compiled wheel" + "Self-install" dance is correctly simplified to a single uv pip install --find-links=./dist --no-index --no-deps --force-reinstall --only-binary=:all: because dependencies are already installed by the preceding uv pip install -r requirements/test.txt. The Codecov flag becoming 3.14t instead of 3.14.5t is called out in the body, so reviewers won't be surprised. The news fragment is correctly named for the issue (1703.contrib.rst) with a symlinked 1704.contrib.rst so both numbers resolve in towncrier, matching the convention in AGENTS.md. Only minor notes are an action-pin style nit and confirming the 3.14t matrix leg resolves without allow-prereleases; neither is blocking.


Automated review by Kōand10eecb
6dfed11
07327e0
d4ab3be

@webknjaz webknjaz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's uv already, I imagine it might be able to produce dists w/o pypa/build, eh?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided There is a change note present in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch to uv for python setup to reduce CI time

4 participants