From 3c16eefe245229ff2de5a414e0e9f03675b36aa3 Mon Sep 17 00:00:00 2001 From: Logan Pulley Date: Mon, 20 Jul 2026 09:49:21 -0500 Subject: [PATCH 1/3] fix(pypi): don't expose source-less uv.lock packages Add news fragment for the uv.lock virtual/root package exposure fix. --- news/3934.fixed.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 news/3934.fixed.md diff --git a/news/3934.fixed.md b/news/3934.fixed.md new file mode 100644 index 0000000000..a30f475770 --- /dev/null +++ b/news/3934.fixed.md @@ -0,0 +1,7 @@ +(pypi) `pip.parse(uv_lock = ...)` no longer exposes uv workspace/root members +that resolve to no wheel or sdist (e.g. `source = { virtual = "." }` or editable +installs). Previously these source-less packages were added to the hub's +`all_requirements` / `all_whl_requirements` with an alias to a subpackage that +does not exist, breaking analysis for anything enumerating the full set such as +`modules_mapping(wheels = all_whl_requirements)` +([#3934](https://github.com/bazel-contrib/rules_python/issues/3934)). From d2808a6d59840aa91605d395416a4cde7fc28fbd Mon Sep 17 00:00:00 2001 From: Logan Pulley Date: Mon, 20 Jul 2026 09:51:32 -0500 Subject: [PATCH 2/3] fix(pypi): don't expose source-less uv.lock packages `pip.parse(uv_lock = ...)` exposed every package in the lock, including uv workspace/root members with `source = { virtual = "." }` (and editable installs). These resolve to no wheel/sdist (srcs = []) but were still marked is_exposed, so the hub added them to all_requirements / all_whl_requirements and created an alias to a subpackage that does not exist. Anything enumerating the full set then failed analysis, e.g. modules_mapping(wheels = all_whl_requirements). Gate is_exposed on whether the package resolved to any sources, mirroring the requirements path which already gates is_exposed. Fixes #3934 --- python/private/pypi/parse_requirements.bzl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/private/pypi/parse_requirements.bzl b/python/private/pypi/parse_requirements.bzl index be3ad9a5e5..648ec9e65c 100644 --- a/python/private/pypi/parse_requirements.bzl +++ b/python/private/pypi/parse_requirements.bzl @@ -292,7 +292,14 @@ def _parse_uv_lock_json(uv_lock, all_platforms, logger, extra_pip_args = None, p versions = sorted(info["versions"].keys()) item = struct( name = norm_name, - is_exposed = True, + # Only expose packages that resolved to at least one source. uv + # workspace/root members (e.g. `source = { virtual = "." }` or + # editable installs) resolve to no wheel/sdist, so exposing them + # would add a dangling entry to the hub's `all_requirements` / + # `all_whl_requirements` and create an alias to a subpackage that + # doesn't exist. This mirrors the requirements path, which also + # gates `is_exposed`. + is_exposed = bool(info["resolved_srcs"]), is_multiple_versions = len(versions) > 1, index_url = info["index_url"], srcs = info["resolved_srcs"], From 4a877ac6faaae0bfd9d5ce7f2204bde49be354ea Mon Sep 17 00:00:00 2001 From: Logan Pulley Date: Mon, 20 Jul 2026 09:54:54 -0500 Subject: [PATCH 3/3] fix(pypi): flip uv.lock virtual/root package test expectations Update _test_uv_lock_primary_source_includes_virtual and the root-pkg case in _test_uv_lock_requires_dist_extras to expect is_exposed = False now that source-less uv.lock packages are no longer exposed. --- tests/pypi/parse_requirements/parse_requirements_tests.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pypi/parse_requirements/parse_requirements_tests.bzl b/tests/pypi/parse_requirements/parse_requirements_tests.bzl index 576a31ae5d..57b3ea5d3e 100644 --- a/tests/pypi/parse_requirements/parse_requirements_tests.bzl +++ b/tests/pypi/parse_requirements/parse_requirements_tests.bzl @@ -1193,7 +1193,7 @@ def _test_uv_lock_primary_source_includes_virtual(env): struct( name = "virtual_pkg", index_url = "", - is_exposed = True, + is_exposed = False, is_multiple_versions = False, srcs = [], ), @@ -1620,7 +1620,7 @@ def _test_uv_lock_requires_dist_extras(env): struct( name = "root_pkg", index_url = "", - is_exposed = True, + is_exposed = False, is_multiple_versions = False, srcs = [], ),