Skip to content

feat(uv): support WORKSPACE builds in the lock() macro - #4360

Merged
aignas merged 3 commits into
bazel-contrib:mainfrom
rickeylev:support_uv_lock_workspace
Oct 27, 2026
Merged

aignas merged 3 commits into
bazel-contrib:mainfrom
rickeylev:support_uv_lock_workspace

Conversation

@rickeylev

@rickeylev rickeylev commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

This makes the uv lock() rule work in workspace mode. Since we'll
be supporting Bazel 8 for another year, and I'd really like to get
rid of the remaining requirements.txt and compile_pip_requirements
calls, I figured we should just implement workspace support for it.

This is a fairly low-effort conversion of the bzlmod APIs to
workspace mode. Fundamentally, the bzlmod API works by obtaining
one or more manifests, then using the manifest information to
define repos with the uv binaries. Then the names of all those
repos are fed into the toolchain hub where the toolchain()
registrations are.

The workspace API more-or-less exposes that same API.

The uv_toolchain_manifest() function is the equivalent of the
first half of the bzlmod phase. All it does is download the
manifests so they can be read by subsequent workspace macros
and repos. Like the bzlmod API, a manifest per uv version can
be registered.

The uv_register_toolchains() function is the equivalent of the
second half of the bzlmod phase. It takes what's in the manifest
and defines repos pointing to a particular URL. Like the bzlmod
API, it accepts args to customize processing. This function also
keeps track of all the created toolchain implementations and
creates the toolchain hub with all the toolchain() registrations.

The args to the functions mirror the bzlmod API, which is basically
a list of key-values. Hence the uv_register_toolchains.configure
arg accepts a list of dicts, where the keys are the same as the
attributes of the uv.configure tag class. This makes for a
somewhat awkward API, but it matches the bzlmod API and makes it
easier to integrate into the underlying code.

Tested on Bazel 7.x and 8.x in WORKSPACE mode, and on Bazel 7.x, 8.x
and 9.x in bzlmod mode (Bazel 9 no longer evaluates WORKSPACE).

Work towards #1975

The `lock()` macro marked all of its targets incompatible unless bzlmod
was enabled, because the only way to download `uv` and register a
`uv_toolchain` was the `uv` module extension.

To support WORKSPACE, add the extension's API to
`@rules_python//python/uv:repositories.bzl` in two steps because only a
repository rule can download the release manifests and WORKSPACE cannot
look at a repository the same statement creates. The
`uv_toolchains_manifest` repository rule fetches the manifests of the
requested versions and writes their archive URLs and checksums,
unfiltered, to `dist_manifest.bzl`; the `uv_register_toolchains()`
macro loaded from there takes the `uv.configure()` fields as a
`configure` list of dicts, creates the download repositories for the
configured platforms that have an archive, defines one toolchain hub
for all versions and registers it. Without a manifest, the same macro
accepts explicit URLs. Users combine it with their own toolchains by
registering them before or after that call.

The extension's configuration and toolchain definition logic, and the
manifest parsing, move into modules shared by both so they cannot
drift. As a side effect, `netrc` and `auth_patterns` given to
`uv.default()` now apply to configured versions; the extension stored
but never used them.

With toolchains available, the bzlmod gates in `lock()` and its template
filegroups are removed. The root WORKSPACE registers `uv` so the
existing `tests/uv` suite runs in WORKSPACE mode, and a WORKSPACE
variant of the `uv_lock` bazel-in-bazel test reuses the existing Python
test cases via a new `bzlmod` mode switch in the integration test
runner. The `bzlmod_lockfile` test lockfile is refreshed because the
`uv` extension's transitive digest changed.

Tested on Bazel 7.x and 8.x in WORKSPACE mode, and on Bazel 7.x, 8.x
and 9.x in bzlmod mode (Bazel 9 no longer evaluates WORKSPACE).

Work towards bazel-contrib#1975
@rickeylev
rickeylev force-pushed the support_uv_lock_workspace branch from 106250b to 17193d6 Compare October 27, 2026 03:26
The `uv_register_toolchains` docstring repeated the `uv.configure` rules
and included multi-step WORKSPACE examples that belong in the user
guide, and the new `.bzl` module docstrings still carried `EXPERIMENTAL`
notices removed upstream.

Move the custom-toolchain and no-manifest examples into `docs/pypi/lock.md`,
trim `uv_register_toolchains`'s docstring to link to the guide and
`uv.configure`, and remove the leftover `EXPERIMENTAL` notices.
Every value in `DIST_MANIFESTS` is a dict, list, or string, so JSON
output is already valid Starlark syntax and `_render_manifests` is
unnecessary.

Replace `_render_manifests` in `uv_toolchains_manifest.bzl` with
`json.encode_indent(manifests, indent = "    ")` and drop the unused
`//python/private:text_util` dependency.
@rickeylev
rickeylev marked this pull request as ready for review October 27, 2026 04:58
@rickeylev
rickeylev requested a review from aignas as a code owner October 27, 2026 04:58
@aignas
aignas added this pull request to the merge queue Oct 27, 2026
Merged via the queue into bazel-contrib:main with commit 44eb677 Oct 27, 2026
13 checks passed
rickeylev added a commit that referenced this pull request Oct 27, 2026
…rules (#4364)

Capture review feedback from #4360 in the workspace agent rules so
future Starlark and WORKSPACE implementations follow the same patterns:

- Direct repository rules to serialize JSON-compatible data constants in
  generated `.bzl` files with `json.encode_indent()` instead of custom
  `render.*` helpers.
- Keep `.bzl` API docstrings brief and place multi-scenario examples and
  setup guides in narrative `docs/` pages linked via `{ref}` or `{obj}`.
- Require `WORKSPACE` macros to match Bzlmod extension defaults, tag
  schemas, and single-hub multi-version structure, splitting manifest
  downloads into a manifest repo rule and a bound registration macro.
@rickeylev
rickeylev deleted the support_uv_lock_workspace branch October 27, 2026 06:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants