From 81437b78c6cd42ff12ae573bdb69957dbffed71e Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius <240938+aignas@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:16:44 +0900 Subject: [PATCH 1/3] fix(uv): fix UV_BIN usage with current_toolchain Before this PR the `uv` toolchain could not be used in a `genrule` it seems because the `//python/uv:toolchain` does not have the necessary providers for using the make variables and the re-exporting of the make variables from the `toolchain` in the `current_toolchain` rule did not seem to work. This PR removes the provider construction in the `toolchain` and does that only in the `current_toolchain`. This better mirrors how the Python toolchains are setup (grepping `PYTHON3` is sufficient to get examples). This also splits out work done in #2059 to decrease its scope, so that this can be discussed separately. Work towards #1975 --- .bazelrc | 4 ++-- MODULE.bazel | 14 ++++++++++++++ python/uv/BUILD.bazel | 5 ++++- python/uv/private/current_toolchain.bzl | 10 ++++++++-- python/uv/toolchain.bzl | 5 ----- tests/uv/toolchain/BUILD.bazel | 16 ++++++++++++++++ 6 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 tests/uv/toolchain/BUILD.bazel diff --git a/.bazelrc b/.bazelrc index 0833d8d979..1ca469cd75 100644 --- a/.bazelrc +++ b/.bazelrc @@ -4,8 +4,8 @@ # (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it) # To update these lines, execute # `bazel run @rules_bazel_integration_test//tools:update_deleted_packages` -build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered -query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered +build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered +query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered test --test_output=errors diff --git a/MODULE.bazel b/MODULE.bazel index b6d198ffc1..2e0d06dc5f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -130,3 +130,17 @@ use_repo( "build_bazel_bazel_rolling", "build_bazel_bazel_self", ) + +# EXPERIMENTAL: This is experimental and may be removed without notice +uv = use_extension( + "//python/uv:extensions.bzl", + "uv", + dev_dependency = True, +) +uv.toolchain(uv_version = "0.2.23") +use_repo(uv, "uv_toolchains") + +register_toolchains( + "@uv_toolchains//:all", + dev_dependency = True, +) diff --git a/python/uv/BUILD.bazel b/python/uv/BUILD.bazel index 3961c908ac..383bdfcc3c 100644 --- a/python/uv/BUILD.bazel +++ b/python/uv/BUILD.bazel @@ -41,7 +41,10 @@ current_toolchain( # even if no toolchain is registered. tags = ["manual"], # EXPERIMENTAL: Visibility is restricted to allow for changes. - visibility = ["@rules_python//examples:__subpackages__"], + visibility = [ + "//:__subpackages__", + "@rules_python//examples:__subpackages__", + ], ) bzl_library( diff --git a/python/uv/private/current_toolchain.bzl b/python/uv/private/current_toolchain.bzl index cd4a5926d2..91a25cb50f 100644 --- a/python/uv/private/current_toolchain.bzl +++ b/python/uv/private/current_toolchain.bzl @@ -30,7 +30,9 @@ def _current_toolchain_impl(ctx): # Bazel requires executable rules to create the executable themselves, # so we create a symlink in this rule so that it appears this rule created its executable. original_uv_executable = toolchain_info.uv_toolchain_info.uv[DefaultInfo].files_to_run.executable - symlink_uv_executable = ctx.actions.declare_file("uv_symlink_{}".format(original_uv_executable.basename)) + + # Use `uv` as the name of the binary to make the help message well formatted + symlink_uv_executable = ctx.actions.declare_file("current_toolchain/uv".format(original_uv_executable.basename)) ctx.actions.symlink(output = symlink_uv_executable, target_file = original_uv_executable) new_default_info = DefaultInfo( @@ -39,10 +41,14 @@ def _current_toolchain_impl(ctx): executable = symlink_uv_executable, ) + template_variable_info = platform_common.TemplateVariableInfo({ + "UV_BIN": symlink_uv_executable.path, + }) + return [ toolchain_info, new_default_info, - toolchain_info.template_variable_info, + template_variable_info, toolchain_info.uv_toolchain_info, ] diff --git a/python/uv/toolchain.bzl b/python/uv/toolchain.bzl index dbfda0b70c..3cd5850acd 100644 --- a/python/uv/toolchain.bzl +++ b/python/uv/toolchain.bzl @@ -31,21 +31,16 @@ def _uv_toolchain_impl(ctx): uv = uv, version = ctx.attr.version, ) - template_variable_info = platform_common.TemplateVariableInfo({ - "UV_BIN": uv[DefaultInfo].files_to_run.executable.path, - }) # Export all the providers inside our ToolchainInfo # so the current_toolchain rule can grab and re-export them. toolchain_info = platform_common.ToolchainInfo( default_info = default_info, - template_variable_info = template_variable_info, uv_toolchain_info = uv_toolchain_info, ) return [ default_info, toolchain_info, - template_variable_info, ] uv_toolchain = rule( diff --git a/tests/uv/toolchain/BUILD.bazel b/tests/uv/toolchain/BUILD.bazel new file mode 100644 index 0000000000..5ec4576aa7 --- /dev/null +++ b/tests/uv/toolchain/BUILD.bazel @@ -0,0 +1,16 @@ +load("@bazel_skylib//rules:build_test.bzl", "build_test") + +genrule( + name = "uv_help", + outs = ["uv_help.txt"], + cmd = "$(UV_BIN) --python-fetch manual --help >$@", + toolchains = [ + "//python/uv:current_toolchain", + "//python:current_py_toolchain", + ], +) + +build_test( + name = "test_uv_toolchain_make_vars", + targets = [":uv_help"], +) From 2fa2976c27a72b75be5830324fb3582d91e3bc11 Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius <240938+aignas@users.noreply.github.com> Date: Fri, 19 Jul 2024 10:13:59 +0900 Subject: [PATCH 2/3] use py_test instead of build_test to ensure nice path naming --- tests/uv/toolchain/BUILD.bazel | 16 ++++++++-------- tests/uv/toolchain/uv_help_test.py | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) create mode 100755 tests/uv/toolchain/uv_help_test.py diff --git a/tests/uv/toolchain/BUILD.bazel b/tests/uv/toolchain/BUILD.bazel index 5ec4576aa7..9017396ffe 100644 --- a/tests/uv/toolchain/BUILD.bazel +++ b/tests/uv/toolchain/BUILD.bazel @@ -1,16 +1,16 @@ -load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("//python:py_test.bzl", "py_test") genrule( name = "uv_help", outs = ["uv_help.txt"], cmd = "$(UV_BIN) --python-fetch manual --help >$@", - toolchains = [ - "//python/uv:current_toolchain", - "//python:current_py_toolchain", - ], + toolchains = ["//python/uv:current_toolchain"], ) -build_test( - name = "test_uv_toolchain_make_vars", - targets = [":uv_help"], +py_test( + name = "uv_help_test", + srcs = ["uv_help_test.py"], + data = [":uv_help"], + env = {"DATA": "$(rlocationpath :uv_help)"}, + deps = ["//python/runfiles"], ) diff --git a/tests/uv/toolchain/uv_help_test.py b/tests/uv/toolchain/uv_help_test.py new file mode 100755 index 0000000000..be5e755d91 --- /dev/null +++ b/tests/uv/toolchain/uv_help_test.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import os +import unittest +from pathlib import Path + +from python.runfiles import runfiles + + +class TestUV(unittest.TestCase): + def test_uv_help(self): + rfiles = runfiles.Create() + assert rfiles is not None, "rfiles creation failed" + + data_rpath = os.environ["DATA"] + uv_help_path = rfiles.Rlocation(data_rpath) + assert ( + uv_help_path is not None + ), f"the rlocation path was not found: {data_rpath}" + + uv_help = Path(uv_help_path).read_text() + + self.assertIn("Usage: uv [OPTIONS] ", uv_help) + + +if __name__ == "__main__": + unittest.main() From 6b130b854b5d67eabae14c0b152ee650082f673b Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius <240938+aignas@users.noreply.github.com> Date: Fri, 19 Jul 2024 10:22:38 +0900 Subject: [PATCH 3/3] fixup: set target_compatible_with to exclude the test from non-bzlmod --- tests/uv/toolchain/BUILD.bazel | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/uv/toolchain/BUILD.bazel b/tests/uv/toolchain/BUILD.bazel index 9017396ffe..137b4e041f 100644 --- a/tests/uv/toolchain/BUILD.bazel +++ b/tests/uv/toolchain/BUILD.bazel @@ -1,9 +1,14 @@ load("//python:py_test.bzl", "py_test") +load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility + +# We only test this feature when `bzlmod` is enabled. +_TARGET_COMPATIBLE_WITH = [] if BZLMOD_ENABLED else ["@platforms//:incompatible"] genrule( name = "uv_help", outs = ["uv_help.txt"], cmd = "$(UV_BIN) --python-fetch manual --help >$@", + target_compatible_with = _TARGET_COMPATIBLE_WITH, toolchains = ["//python/uv:current_toolchain"], ) @@ -12,5 +17,6 @@ py_test( srcs = ["uv_help_test.py"], data = [":uv_help"], env = {"DATA": "$(rlocationpath :uv_help)"}, + target_compatible_with = _TARGET_COMPATIBLE_WITH, deps = ["//python/runfiles"], )