Skip to content

Instantly share code, notes, and snippets.

@arrdem
Last active January 30, 2026 19:06
Show Gist options
  • Select an option

  • Save arrdem/975bf71f0d4833df346d603eaaa9a766 to your computer and use it in GitHub Desktop.

Select an option

Save arrdem/975bf71f0d4833df346d603eaaa9a766 to your computer and use it in GitHub Desktop.

The uv v0.2 extension & its architecture.

Bazel's "modules" system as of Bazel 6+ divides the world into "modules", each one of which can invoke "extensions" to request side-effects and configuration above and beyond the "normal" Bazel build graph. pip.parse() and the new uv.project() machinery are extensions.

Extensions' view of the world is a global one. They see all the requested configurations from all modules "at once", so they can do things like global reuse of generated targets.

The new uv extension's world is one of projects, being a (pyproject.toml, uv.lock) pair. This allows us to do [dependency-groups] which don't exist in the uv.lock alone, and compute extra activation modes.

Notionally the reworked architecture is simple and follows the same pattern as the original version. Translate every wheel in any uv.lock into a whl_file__* repo, ...Translate every sdist in any uv.lock into a sdist_file__* repo, containing the fileFor every versioned package in each lock with a sdist, create a sdist_build__{lock}__{pkg}__{ver} repo, which consumes the sdist artifact and builds it to a whl fileFor every versioned package in each lock create a whl_install__{lock}__{pkg}__{ver} repo, which will install either a prebuilt wheel if one matches the target configuration or the source-built wheel

We have a way to get versioned, isolated installs of each package. That's all straightforwards and as it was initially. Just had to work in deterministic IDs for lockfiles and package versions.

The really tricky bit is encoding the dependency graph such that Bazel can use it to choose the right versioned installs, while producing the desired behavior. We need to: "Break" cycles via statically connected component conversionEvaluate marker expressions within the build graphActivate extras

We normalize the [package] table of a UV lockfile into a graph that looks like

struct Id(lock_id: str, requirement: str, version: str, extra: str = "__base__")
struct Marker(str)

graph = {Id: {Id: {Marker: 1}}}

We normalize a requirement foo to be foo[__base__], and we treat a requirement foo[bar] as depending on foo[__base__].

Statically connected components can be computed from this graph. Then for each SCC we can determine the dependencies which leave the scc and their markers. We can also collect markers applied to dependency edges within the scc.

Starting from the [dependency-groups] table, we can then do a closure analysis to determine what set of extras for each package is reached in each group configuration.

We also try to decide for each [dependency-groups] what the nominal requirement -> version mapping is.

For each "hub" that users registered projects into, we generate a hub repo containing the merge of mappings from requirements to configurations containing those requirements to versioned nominal choices for those requirements.

We also have to generate a mapping from versioned nominal requirements to the extras conversion, so that we translate foo[] -> foo[bar] if the bar extra is reachable within a given configuration. These groups depend on our "fully qualified" (lock_id, pkg, ver, extra) coordinate targets.

For each lockfile, we generate a repo containing the (lock_id, pkg, ver, extra) "surface" targets. These are aliases pointing to group targets implementing the SCC containing that package and extra.

SCC targets themselves are a bundle of condition targets, which allow for each dependency edge (from the scc to a package which may be a member, from the scc to a package which may be a dep of a member) to be evaluated for markers. There may be a bug here around SCCs involving different versions of a member package depending on the active dependency group config.

Finally these SCC targets point either to other SCCs for external deps or to the whl_install__{lock}__{pkg}__{ver} for each of its direct components.

There's a bug here where because the hub not the lockfile is converting requirements to requirements+extras, a dep within the lockfile will observe the exact deps whereas the user-facing target may have additional extras activated.

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