Selective uv sync: Install only needed packages on PEX builds#23504
Open
lowvoltage wants to merge 2 commits into
Open
Selective uv sync: Install only needed packages on PEX builds#23504lowvoltage wants to merge 2 commits into
lowvoltage wants to merge 2 commits into
Conversation
lowvoltage
marked this pull request as ready for review
July 7, 2026 13:57
Contributor
|
Thanks for the contribution. We've just branched for 2.33.x, so merging this pull request now will come out in 2.34.x, please move the release notes updates to docs/notes/2.34.x.md if that's appropriate. |
lowvoltage
force-pushed
the
dk-uv-selective-sync
branch
from
July 8, 2026 18:57
50c51d4 to
9d03889
Compare
Contributor
Author
Updated |
When building a PEX from a uv lockfile, the uv resolver previously downloaded the entire lockfile contents (via `uv sync --frozen --all-extras`), even when the PEX only needed a small subset of packages. For large resolves containing ML dependencies like torch/CUDA, this caused multi-GB downloads and could exhaust disk space. This change adds selective sync support using uv's dependency groups and `--only-group` flag: - `generate_pyproject_toml()` now emits a `[dependency-groups]` section with one group per top-level requirement, named after the canonicalized package name (PEP 503). Since this function is shared by both lockfile generation and sync, the groups are automatically baked into the lockfile. - `VenvFromUvLockfileRequest` gains a `subset_req_strings` field. When populated, `create_venv_repository_from_uv_lockfile()` uses `--only-group <name>` + `--inexact` instead of `--all-extras`, installing only the requested packages and their transitive dependencies. - `build_pex()` in pex.py passes the target's `req_strings` through to enable selective sync for per-target PEX builds. Backward compatibility: - Lockfiles generated before this change (without dependency group metadata) are detected by checking for `[package.dev-dependencies]` in the lockfile. When absent, the code falls back to full sync with a warning to regenerate. - The `EntireLockfile` path (tools, `run_against_entire_lockfile`) is unchanged and continues to use `--all-extras`. - A lockfile content hash is included in the venv path when using `--inexact` to prevent stale packages from old lockfile versions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
lowvoltage
force-pushed
the
dk-uv-selective-sync
branch
from
July 9, 2026 10:59
9d03889 to
98c5840
Compare
Contributor
Author
|
bump ^^? |
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.
Problem
When building a PEX from a uv lockfile, the uv resolver downloads the entire lockfile contents via
uv sync --frozen --all-extras, even when the PEX only needs a small subset of packages. For large monorepo resolves containing ML dependencies liketorchwith CUDA extensions, this causes:This is a regression compared to the Pex resolver, which natively subsets the lockfile via its
--lockflag.Slack ref: https://pantsbuild.slack.com/archives/C0D7TNJHL/p1779314212347949
Solution
Use uv's dependency groups and
--only-groupflag to selectively install only the packages needed for each PEX build.How it works
generate_pyproject_toml()now emits a[dependency-groups]section with one group per top-level requirement, named after the canonicalized package name (PEP 503). Since this function is shared by both lockfile generation and sync, the groups are automatically baked into the lockfile at generation time.VenvFromUvLockfileRequestgains asubset_req_stringsfield. When populated,create_venv_repository_from_uv_lockfile()uses--only-group <name>+--inexactinstead of--all-extras, installing only the requested packages and their transitive dependencies.build_pex()passes the target'sreq_stringsthrough to enable selective sync for per-target PEX builds.Key design decisions
uv sync --frozen --only-grouprequires groups to exist in the lock metadata. An ephemeral-group approach (adding groups only at sync time) would fail with--frozen.--inexactflag prevents removal of previously-installed packages, allowing the shared venv to accumulate packages across different PEX builds.--inexactto prevent stale packages from old lockfile versions.Backward Compatibility
[package.dev-dependencies]in the lockfile content. When absent, the code falls back to full sync (--all-extras) with a warning to regenerate.EntireLockfilepath (tools,run_against_entire_lockfile) is unchanged and continues to use--all-extras.Changes
uv.pygenerate_pyproject_toml, selective sync logic with--only-group+--inexact, lockfile-has-groups detection, graceful fallbackpex.pyreq_stringstoVenvFromUvLockfileRequest.subset_req_stringspex_test.pyTesting
test_generate_pyproject_toml_includes_dependency_groups— verifies group generationtest_generate_pyproject_toml_canonicalizes_group_names— verifies PEP 503 canonicalizationtest_generate_pyproject_toml_accumulates_duplicate_groups— verifies collision handlingtest_build_pex_subset_from_uv_lockfile— end-to-end: generates lockfile with multiple packages, builds PEX requesting only one, verifies it workstest_build_pex_from_uv_lockfile— existing test continues to pass (full sync path)