Skip to content

feat(pypi): support importing uv.lock file#3785

Open
aignas wants to merge 63 commits into
bazel-contrib:mainfrom
aignas:aignas.feat.uv-lock
Open

feat(pypi): support importing uv.lock file#3785
aignas wants to merge 63 commits into
bazel-contrib:mainfrom
aignas:aignas.feat.uv-lock

Conversation

@aignas

@aignas aignas commented May 16, 2026

Copy link
Copy Markdown
Collaborator

Part of this is vibe coded, but I thought that the approach might have been rigorous
enough to submit a PR.

The strategy was:

  • First add a way for us to create a uv.lock file from the lock rule.
  • Then add a uv.lock file to JSON converter.
  • Then add a way to read the uv.lock file together with the requirements file
    and verify things are OK.
  • Reuse most of the code.

Extra things that we could do:

  • Full test suite for various uv.lock scenarios and ensure parity with
    requirements.txt files.
  • Call the PyPI index to understand if the packages are yanked or not - lock
    file does not have that information.
  • Read the pyproject.toml file to get the index values for each package.

Summary:

  • feat(pypi): add uv.lock parsing support to parse_requirements
  • test(pypi): add tests for uv.lock parsing in parse_requirements
  • test(uv): add lock rule integration tests for uv.lock format
  • test: add uv_pypi end-to-end integration test
  • docs: add uv.lock documentation and sample files

Closes #3557
Work towards #2787

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for uv.lock files in rules_python, introducing a toml2json conversion utility and updating the lock rule and requirement parsing logic. The review identifies critical compatibility issues, specifically the toml2json tool's reliance on Python 3.11's tomllib and missing serialization for date/time objects. Furthermore, the feedback highlights logic errors in how package extras are handled—which could lead to dependency bloat or failed consistency checks—and suggests improvements for platform resolution and path handling in shell scripts.

"""Parse requirements using uv.lock as the primary source."""
ret = _parse_uv_lock_json(
uv_lock_json = uv_lock_json,
all_platforms = _get_all_platforms(requirements_by_platform) if requirements_by_platform else [],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

If requirements_by_platform is empty (which is common when using uv.lock as the primary source), all_platforms will be an empty list. This results in all packages having empty target_platforms, which will likely cause issues in downstream rules that expect platform information for wheel selection.

Suggested change
all_platforms = _get_all_platforms(requirements_by_platform) if requirements_by_platform else [],
all_platforms = _get_all_platforms(requirements_by_platform) if requirements_by_platform else sorted(platforms.keys()),

Comment on lines +192 to +194
for extra in pkg.get("provides-extras", pkg.get("extras", [])):
if extra not in entry["extras"]:
entry["extras"][extra] = None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Including all provides-extras in the requirement line for every package is likely incorrect. provides-extras lists all extras a package defines, not necessarily what was resolved or requested. Including all of them will force the installation of all optional dependencies for every package in the lock file, leading to significant dependency bloat. It might be better to omit extras from the requirement line if the lock file already provides the specific version and URL, or only include the extras that were part of the resolution.

Comment thread python/private/pypi/parse_requirements.bzl Outdated
Comment thread tools/toml2json/toml2json.py Outdated
Comment thread python/uv/private/lock.bzl Outdated
Comment thread tools/toml2json/toml2json.py Outdated
aignas added 2 commits May 17, 2026 02:18
- tomllib: try/except fallback to tomli for Python <3.11
- json_serializer: add datetime.date and datetime.time support
- all_platforms: use sorted(platforms.keys()) fallback
- $PWD/ path: check if python_path is absolute
- extra_pip_args: pass through to _parse_uv_lock_json
- Add uv_lock tests: multiple packages, extra_pip_args, multi-os
- Update plan.md with review cycle instructions
@aignas

aignas commented May 16, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed all review comments. Please re-review when you get a chance. @gemini-code-assist

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for uv.lock files in rules_python, adding a new lock_format attribute to the lock rule and a toml2json utility for parsing. It also implements a consistency check between uv.lock and requirements files. The reviewer identified a potential runtime error in the uv.lock parser due to unsafe dictionary access for optional hash keys and suggested simplifying redundant logic during hash extraction.

Comment thread python/private/pypi/parse_requirements.bzl Outdated
Comment thread python/private/pypi/parse_requirements.bzl Outdated
aignas added 3 commits May 17, 2026 03:38
- Add python_3_14 toolchain in MODULE.bazel
- Always use Python 3.14 interpreter for uv.lock JSON conversion
- Remove tomli fallback from toml2json.py (Python 3.14 has tomllib)
- Simplify convert_uv_lock_to_json to use fixed interpreter
- Add bazel-in-bazel integration test under tests/integration/uv_lock/
- Test converts uv.lock TOML to JSON using toml2json tool
- Remove dead uv_pypi test data (placeholder only)
- Restore tomli fallback in toml2json.py for backward compatibility
@aignas

aignas commented May 16, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed all review comments and added Python 3.14 toolchain + integration test. Please re-review. @gemini-code-assist

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for uv.lock files as a primary metadata source in rules_python. Key additions include a toml2json tool for parsing, a new uv_lock format for the lock rule, and consistency checks within parse_requirements. Reviewer feedback suggests adopting more idiomatic Starlark dictionary access, implementing safer hash prefix stripping, and improving the portability of shell commands by replacing hardcoded environment variables with Bazel-provided paths.

Comment thread python/private/pypi/parse_requirements.bzl Outdated
Comment thread python/private/pypi/parse_requirements.bzl Outdated
Comment thread python/private/pypi/parse_requirements.bzl Outdated
Comment thread python/private/pypi/parse_requirements.bzl Outdated
Comment thread python/uv/private/lock.bzl Outdated
@jvolkman

Copy link
Copy Markdown
Contributor

The latest release of toml.bzl makes bazel_lib a dev dependency. It now uses skylib for the bzl_library rules.

aignas added 2 commits May 18, 2026 22:11
Remove the old toml2json Python tool and uv_lock.bzl in favor of the
pure Starlark toml.bzl decoder. Update tests to pass toml_decode mock,
remove is_rules_python_root references, and fix virtual package test
expectations. Clean up BUILD.bazel files that referenced deleted targets.
Comment thread python/private/pypi/extension.bzl
),
logger = logger,
),
uv_lock = pip_attr.uv_lock,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Add a test to ensure this is tested.

Comment thread MODULE.bazel Outdated
Comment thread MODULE.bazel Outdated
aignas added 5 commits May 19, 2026 20:51
… lock support

Remove the lock_format attribute and detect whether to use uv lock or
uv pip compile from the output file extension (.lock = uv lock, else
requirements). Add a Windows bat template for uv lock support. The
python interpreter is passed through --python flag consistently.

@rickeylev rickeylev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Overall LGTM. Some minor questions and nits. But overall, this fit in rather nicely with the pipstar code you've written, nice!

Comment thread python/uv/private/lock.bzl Outdated
Comment thread python/uv/private/lock.bzl Outdated
Comment thread python/private/pypi/parse_requirements.bzl
Comment thread python/private/pypi/parse_requirements.bzl
Comment thread python/private/pypi/parse_requirements.bzl
Comment thread python/private/pypi/parse_requirements.bzl Outdated
Comment thread python/private/pypi/parse_requirements.bzl
Comment thread python/private/pypi/parse_requirements.bzl
Comment thread python/private/py_repositories.bzl
@aignas aignas marked this pull request as ready for review June 20, 2026 15:37
@rickeylev

Copy link
Copy Markdown
Collaborator

ai analysis of ci failure: path instead short_path should be used.

I think that's right? The logic has moved around a bit, but it looks like the is_windows branch of building the args previously did e.g. hasattr(arg, "path") and now it uses short_path

rickeylev and others added 9 commits June 21, 2026 23:02
Windows action execution was failing because the embedded paths in the
generated .bat files used 'short_path' (e.g., '../repo/file'), which is
relative to the runfiles directory. In the action execution environment
(execroot), these paths must be relative to the execroot (e.g.,
'external/repo/file'). Resolved by using 'path' instead of 'short_path'
for Windows action arguments in lock.bzl.
Fix Windows test assertions to support batch script syntax and preserve forward slashes in uv arguments to ensure cross-platform lockfile path consistency.
Fix Windows batch templates to return the actual command exit code and add a temporary unified diff test to capture generated vs expected requirements mismatches on Windows CI.
…bilize them.

This prevents the tests from resolving newer versions from PyPI on platforms with network access, ensuring reproducibility across all CI runners.
This resolves issues where the output file path was evaluated as empty and exit codes were masked inside parentheses. Also reverts temporary debug prints.
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.

3 participants