Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: uv lock rule instead of genrule #2657

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ Unreleased changes template.

{#v0-0-0-added}
### Added
* Nothing added.
* (uv) A {obj}`lock` rule that is the replacement for the
{obj}`compile_pip_requirements`. This may still have rough corners
so please report issues with it in the
[#1975](https://github.com/bazel-contrib/rules_python/issues/1975).
Main highlights - the locking can be done within a build action or outside
it, there is no more automatic `test` target (but it can be added on the user
side by using `native_test`). For customizing the `uv` version that is used,
please check the {obj}`uv.configure` tag class.

{#v0-0-0-removed}
### Removed
Expand Down
8 changes: 6 additions & 2 deletions docs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,12 @@ lock(
name = "requirements",
srcs = ["pyproject.toml"],
out = "requirements.txt",
upgrade = True,
visibility = ["//private:__pkg__"],
args = [
"--emit-index-url",
"--universal",
"--upgrade",
],
visibility = ["//:__subpackages__"],
)

# Temporary compatibility aliases for some other projects depending on the old
Expand Down
3 changes: 3 additions & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ lock(
name = "bzlmod_requirements_3_9",
srcs = ["bzlmod/requirements.in"],
out = "bzlmod/requirements_lock_3_9.txt",
args = [
"--emit-index-url",
],
python_version = "3.9.19",
)
17 changes: 6 additions & 11 deletions examples/bzlmod/requirements_lock_3_9.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ chardet==4.0.0 \
colorama==0.4.6 \
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
# via
# -r examples/bzlmod/requirements.in
# pylint
# sphinx
# via -r examples/bzlmod/requirements.in
dill==0.3.6 \
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
Expand All @@ -46,7 +43,7 @@ imagesize==1.4.1 \
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
# via sphinx
importlib-metadata==8.4.0 ; python_version < '3.10' \
importlib-metadata==8.4.0 \
--hash=sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1 \
--hash=sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5
# via sphinx
Expand Down Expand Up @@ -265,9 +262,7 @@ s3cmd==2.1.0 \
setuptools==65.6.3 \
--hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
--hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
# via
# babel
# yamllint
# via yamllint
six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
Expand Down Expand Up @@ -316,15 +311,15 @@ tabulate==0.9.0 \
--hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
--hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
# via -r examples/bzlmod/requirements.in
tomli==2.0.1 ; python_version < '3.11' \
tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
# via pylint
tomlkit==0.11.6 \
--hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \
--hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73
# via pylint
typing-extensions==4.12.2 ; python_version < '3.10' \
typing-extensions==4.12.2 \
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
# via
Expand Down Expand Up @@ -480,7 +475,7 @@ yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r examples/bzlmod/requirements.in
zipp==3.20.0 ; python_version < '3.10' \
zipp==3.20.0 \
--hash=sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31 \
--hash=sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d
# via importlib-metadata
2 changes: 2 additions & 0 deletions private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ multirun(
] + [
"//docs:requirements.update",
],
tags = ["manual"],
)

# NOTE: The requirements for the pip dependencies may sometimes break the build
Expand All @@ -24,4 +25,5 @@ multirun(
alias(
name = "whl_library_requirements.update",
actual = "//tools/private/update_deps:update_pip_deps",
tags = ["manual"],
)
1 change: 1 addition & 0 deletions python/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ bzl_library(
name = "py_exec_tools_toolchain_bzl",
srcs = ["py_exec_tools_toolchain.bzl"],
deps = [
":common_bzl",
":py_exec_tools_info_bzl",
":sentinel_bzl",
":toolchain_types_bzl",
Expand Down
24 changes: 20 additions & 4 deletions python/private/py_exec_tools_info.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,31 @@ When running it in an action, use `DefaultInfo.files_to_run` to ensure all its
files are appropriately available. An exec interpreter may not be available,
e.g. if all the exec tools are prebuilt binaries.

NOTE: this interpreter is really only for use when a build tool cannot use
:::{note}
this interpreter is really only for use when a build tool cannot use
the Python toolchain itself. When possible, prefeer to define a `py_binary`
instead and use it via a `cfg=exec` attribute; this makes it much easier
to setup the runtime environment for the binary. See also:
`py_interpreter_program` rule.
:::

NOTE: What interpreter is used depends on the toolchain constraints. Ensure
the proper target constraints are being applied when obtaining this from
the toolchain.
:::{note}
What interpreter is used depends on the toolchain constraints. Ensure the
proper target constraints are being applied when obtaining this from the
toolchain.
:::

:::{warning}
This does not work correctly in case of RBE, please use exec_runtime instead.

Once https://github.com/bazelbuild/bazel/issues/23620 is resolved this warning
may be removed.
:::
""",
"exec_runtime": """
:type: PyRuntimeInfo | None

The forwarded {obj}`PyRuntimeInfo` field.
""",
"precompiler": """
:type: Target | None
Expand Down
23 changes: 17 additions & 6 deletions python/private/py_exec_tools_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,19 @@ def _py_exec_tools_toolchain_impl(ctx):
if SentinelInfo in ctx.attr.exec_interpreter:
exec_interpreter = None

return [platform_common.ToolchainInfo(
exec_tools = PyExecToolsInfo(
exec_interpreter = exec_interpreter,
precompiler = ctx.attr.precompiler,
# Forward the provider fields from the toolchain itself.
exec_runtime = ctx.attr.exec_interpreter[platform_common.ToolchainInfo]

return [
platform_common.ToolchainInfo(
exec_tools = PyExecToolsInfo(
exec_interpreter = exec_interpreter,
exec_runtime = exec_runtime,
precompiler = ctx.attr.precompiler,
),
**extra_kwargs
),
**extra_kwargs
)]
]

py_exec_tools_toolchain = rule(
implementation = _py_exec_tools_toolchain_impl,
Expand All @@ -51,6 +57,11 @@ This provides `ToolchainInfo` with the following attributes:
attrs = {
"exec_interpreter": attr.label(
default = "//python/private:current_interpreter_executable",
providers = [
DefaultInfo,
# Add the toolchain provider so that we can forward provider fields.
platform_common.ToolchainInfo,
],
cfg = "exec",
doc = """
An interpreter that is directly usable in the exec configuration
Expand Down
6 changes: 5 additions & 1 deletion python/private/sentinel.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ SentinelInfo = provider(

def _sentinel_impl(ctx):
_ = ctx # @unused
return [SentinelInfo()]
return [
SentinelInfo(),
# Also output ToolchainInfo
platform_common.ToolchainInfo(),
]

sentinel = rule(implementation = _sentinel_impl)
26 changes: 26 additions & 0 deletions python/uv/lock.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,32 @@

"""The `uv` locking rule.

Differences with the legacy {obj}`compile_pip_requirements` rule:
- This is implemented as a rule that performs locking in a build action.
- Additionally one can use the runnable target.
- Uses `uv`.
- This does not error out if the output file does not exist yet.
- Supports transitions out of the box.

Note, this does not provide a `test` target, if you would like to add a test
target that always does the locking automatically to ensure that the
`requirements.txt` file is up-to-date, add something similar to:

```starlark
load("@bazel_skylib//rules:native_binary.bzl", "native_test")
load("@rules_python//python/uv:lock.bzl", "lock")

lock(
name = "requirements",
srcs = ["pyproject.toml"],
)

native_test(
name = "requirements_test",
src = "requirements.update",
)
```

EXPERIMENTAL: This is experimental and may be removed without notice
"""

Expand Down
25 changes: 24 additions & 1 deletion python/uv/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
# limitations under the License.

load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility

exports_files(
srcs = [
"lock_copier.py",
],
# only because this is used from a macro to template
visibility = ["//visibility:public"],
)

filegroup(
name = "distribution",
Expand All @@ -31,9 +40,13 @@ bzl_library(
srcs = ["lock.bzl"],
visibility = ["//python/uv:__subpackages__"],
deps = [
":toolchain_types_bzl",
"//python:py_binary_bzl",
"//python/private:bzlmod_enabled_bzl",
"@bazel_skylib//rules:write_file",
"//python/private:full_version_bzl",
"//python/private:toolchain_types_bzl",
"@bazel_skylib//lib:shell",
"@pythons_hub//:versions_bzl",
],
)

Expand Down Expand Up @@ -81,3 +94,13 @@ bzl_library(
"//python/private:text_util_bzl",
],
)

filegroup(
name = "lock_template",
srcs = select({
"@platforms//os:windows": ["lock.bat"],
"//conditions:default": ["lock.sh"],
}),
target_compatible_with = [] if BZLMOD_ENABLED else ["@platforms//:incompatible"],
visibility = ["//visibility:public"],
)
7 changes: 7 additions & 0 deletions python/uv/private/lock.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
if defined BUILD_WORKSPACE_DIRECTORY (
set "out=%BUILD_WORKSPACE_DIRECTORY%\{{src_out}}"
) else (
exit /b 1
)

"{{args}}" --output-file "%out%" %*
Loading