From c63939d4cfc27a870724a063d0ee7df564d0677f Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius <240938+aignas@users.noreply.github.com> Date: Sat, 25 Jan 2025 15:19:18 +0900 Subject: [PATCH] refactor(uv): move around uv implementation files This PR starts establishing a structure that will eventually become a part of our API. This is a prerequisite for #2578 which removes the versions.bzl file in favour of a more dynamic configuration of the extension. We also remove the `defs.bzl` to establish a one symbol per file convention. Things that I wish we could change is `//python/uv:extensions.bzl` and the fact that we have `extensions` in the load path. I think it cannot be removed, because that may break the BCR test. On the other hand, maybe we could remove it and do an alpha release to verify this assumption. Work towards #1975 --- MODULE.bazel | 2 +- docs/BUILD.bazel | 6 ++- examples/bzlmod/MODULE.bazel | 2 +- python/uv/BUILD.bazel | 28 +++++----- python/uv/lock.bzl | 22 ++++++++ python/uv/private/BUILD.bazel | 52 +++++++++++++++++-- python/uv/private/lock.bzl | 24 ++++----- python/uv/{extensions.bzl => private/uv.bzl} | 13 +++-- .../uv_repositories.bzl} | 14 ++--- .../uv_toolchain.bzl} | 2 +- .../{providers.bzl => uv_toolchain_info.bzl} | 0 ...chains_repo.bzl => uv_toolchains_repo.bzl} | 0 python/uv/uv.bzl | 22 ++++++++ python/uv/uv_toolchain.bzl | 22 ++++++++ python/uv/{defs.bzl => uv_toolchain_info.bzl} | 9 ++-- 15 files changed, 161 insertions(+), 57 deletions(-) create mode 100644 python/uv/lock.bzl rename python/uv/{extensions.bzl => private/uv.bzl} (85%) rename python/uv/{repositories.bzl => private/uv_repositories.bzl} (89%) rename python/uv/{toolchain.bzl => private/uv_toolchain.bzl} (96%) rename python/uv/private/{providers.bzl => uv_toolchain_info.bzl} (100%) rename python/uv/private/{toolchains_repo.bzl => uv_toolchains_repo.bzl} (100%) create mode 100644 python/uv/uv.bzl create mode 100644 python/uv/uv_toolchain.bzl rename python/uv/{defs.bzl => uv_toolchain_info.bzl} (78%) diff --git a/MODULE.bazel b/MODULE.bazel index 2ac5a27223..7034357f61 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -175,7 +175,7 @@ use_repo( # EXPERIMENTAL: This is experimental and may be removed without notice uv = use_extension( - "//python/uv:extensions.bzl", + "//python/uv:uv.bzl", "uv", dev_dependency = True, ) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index e365532d01..ea386f114a 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -16,7 +16,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@dev_pip//:requirements.bzl", "requirement") load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER") # buildifier: disable=bzl-visibility -load("//python/uv/private:lock.bzl", "lock") # buildifier: disable=bzl-visibility +load("//python/uv:lock.bzl", "lock") # buildifier: disable=bzl-visibility load("//sphinxdocs:readthedocs.bzl", "readthedocs_install") load("//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs") load("//sphinxdocs:sphinx_docs_library.bzl", "sphinx_docs_library") @@ -105,6 +105,10 @@ sphinx_stardocs( "//python/private/api:py_common_api_bzl", "//python/private/pypi:config_settings_bzl", "//python/private/pypi:pkg_aliases_bzl", + "//python/uv:lock_bzl", + "//python/uv:uv_bzl", + "//python/uv:uv_toolchain_bzl", + "//python/uv:uv_toolchain_info_bzl", ] + ([ # Bazel 6 + Stardoc isn't able to parse something about the python bzlmod extension "//python/extensions:python_bzl", diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel index 536e3b2b67..d8535a0115 100644 --- a/examples/bzlmod/MODULE.bazel +++ b/examples/bzlmod/MODULE.bazel @@ -105,7 +105,7 @@ python.single_version_platform_override( use_repo(python, "python_3_10", "python_3_9", "python_versions", "pythons_hub") # EXPERIMENTAL: This is experimental and may be removed without notice -uv = use_extension("@rules_python//python/uv:extensions.bzl", "uv") +uv = use_extension("@rules_python//python/uv:uv.bzl", "uv") uv.toolchain(uv_version = "0.4.25") use_repo(uv, "uv_toolchains") diff --git a/python/uv/BUILD.bazel b/python/uv/BUILD.bazel index 383bdfcc3c..7ce6ce0523 100644 --- a/python/uv/BUILD.bazel +++ b/python/uv/BUILD.bazel @@ -27,9 +27,6 @@ filegroup( visibility = ["//:__subpackages__"], ) -# For stardoc to reference the files -exports_files(["defs.bzl"]) - toolchain_type( name = "uv_toolchain_type", visibility = ["//visibility:public"], @@ -48,34 +45,33 @@ current_toolchain( ) bzl_library( - name = "defs", - srcs = ["defs.bzl"], + name = "lock_bzl", + srcs = ["lock.bzl"], # EXPERIMENTAL: Visibility is restricted to allow for changes. visibility = ["//:__subpackages__"], + deps = ["//python/uv/private:lock_bzl"], ) bzl_library( - name = "extensions", - srcs = ["extensions.bzl"], + name = "uv_bzl", + srcs = ["uv.bzl"], # EXPERIMENTAL: Visibility is restricted to allow for changes. visibility = ["//:__subpackages__"], - deps = [":repositories"], + deps = ["//python/uv/private:uv_bzl"], ) bzl_library( - name = "repositories", - srcs = ["repositories.bzl"], + name = "uv_toolchain_bzl", + srcs = ["uv_toolchain.bzl"], # EXPERIMENTAL: Visibility is restricted to allow for changes. visibility = ["//:__subpackages__"], - deps = [ - "//python/uv/private:toolchains_repo", - "//python/uv/private:versions", - ], + deps = ["//python/uv/private:uv_toolchain_bzl"], ) bzl_library( - name = "toolchain", - srcs = ["toolchain.bzl"], + name = "uv_toolchain_info_bzl", + srcs = ["uv_toolchain_info.bzl"], # EXPERIMENTAL: Visibility is restricted to allow for changes. visibility = ["//:__subpackages__"], + deps = ["//python/uv/private:uv_toolchain_info_bzl"], ) diff --git a/python/uv/lock.bzl b/python/uv/lock.bzl new file mode 100644 index 0000000000..edffe4728c --- /dev/null +++ b/python/uv/lock.bzl @@ -0,0 +1,22 @@ +# Copyright 2025 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""The `uv` locking rule. + +EXPERIMENTAL: This is experimental and may be removed without notice +""" + +load("//python/uv/private:lock.bzl", _lock = "lock") + +lock = _lock diff --git a/python/uv/private/BUILD.bazel b/python/uv/private/BUILD.bazel index 80fd23913f..006c856d02 100644 --- a/python/uv/private/BUILD.bazel +++ b/python/uv/private/BUILD.bazel @@ -21,20 +21,62 @@ filegroup( ) bzl_library( - name = "current_toolchain", + name = "current_toolchain_bzl", srcs = ["current_toolchain.bzl"], visibility = ["//python/uv:__subpackages__"], ) bzl_library( - name = "toolchain_types", + name = "lock_bzl", + srcs = ["lock.bzl"], + visibility = ["//python/uv:__subpackages__"], + deps = [ + "//python:py_binary_bzl", + "//python/private:bzlmod_enabled_bzl", + "@bazel_skylib//rules:write_file", + ], +) + +bzl_library( + name = "toolchain_types_bzl", srcs = ["toolchain_types.bzl"], visibility = ["//python/uv:__subpackages__"], ) bzl_library( - name = "toolchains_repo", - srcs = ["toolchains_repo.bzl"], + name = "uv_bzl", + srcs = ["uv.bzl"], + visibility = ["//python/uv:__subpackages__"], + deps = [":uv_repositories_bzl"], +) + +bzl_library( + name = "uv_repositories_bzl", + srcs = ["uv_repositories.bzl"], + visibility = ["//python/uv:__subpackages__"], + deps = [ + ":toolchain_types_bzl", + ":uv_toolchains_repo_bzl", + ":versions_bzl", + ], +) + +bzl_library( + name = "uv_toolchain_bzl", + srcs = ["uv_toolchain.bzl"], + visibility = ["//python/uv:__subpackages__"], + deps = [":uv_toolchain_info_bzl"], +) + +bzl_library( + name = "uv_toolchain_info_bzl", + srcs = ["uv_toolchain_info.bzl"], + visibility = ["//python/uv:__subpackages__"], +) + +bzl_library( + name = "uv_toolchains_repo_bzl", + srcs = ["uv_toolchains_repo.bzl"], visibility = ["//python/uv:__subpackages__"], deps = [ "//python/private:text_util_bzl", @@ -42,7 +84,7 @@ bzl_library( ) bzl_library( - name = "versions", + name = "versions_bzl", srcs = ["versions.bzl"], visibility = ["//python/uv:__subpackages__"], ) diff --git a/python/uv/private/lock.bzl b/python/uv/private/lock.bzl index f4dfa36eff..e0491b282c 100644 --- a/python/uv/private/lock.bzl +++ b/python/uv/private/lock.bzl @@ -26,9 +26,14 @@ _REQUIREMENTS_TARGET_COMPATIBLE_WITH = select({ "//conditions:default": [], }) if BZLMOD_ENABLED else ["@platforms//:incompatible"] -def lock(*, name, srcs, out, upgrade = False, universal = True, python_version = None, args = [], **kwargs): +def lock(*, name, srcs, out, upgrade = False, universal = True, args = [], **kwargs): """Pin the requirements based on the src files. + Differences with the current {obj}`compile_pip_requirements` rule: + - This is implemented in shell and uv. + - This does not error out if the output file does not exist yet. + - Supports transitions out of the box. + Args: name: The name of the target to run for updating the requirements. srcs: The srcs to use as inputs. @@ -36,15 +41,8 @@ def lock(*, name, srcs, out, upgrade = False, universal = True, python_version = upgrade: Tell `uv` to always upgrade the dependencies instead of keeping them as they are. universal: Tell `uv` to generate a universal lock file. - python_version: Tell `rules_python` to use a particular version. - Defaults to the default py toolchain. - args: Extra args to pass to the rule. - **kwargs: Extra kwargs passed to the binary rule. - - Differences with the current pip-compile rule: - - This is implemented in shell and uv. - - This does not error out if the output file does not exist yet. - - Supports transitions out of the box. + args: Extra args to pass to `uv`. + **kwargs: Extra kwargs passed to the {obj}`py_binary` rule. """ pkg = native.package_name() update_target = name + ".update" @@ -92,10 +90,6 @@ def lock(*, name, srcs, out, upgrade = False, universal = True, python_version = Label("//python:current_py_toolchain"), ], ) - if python_version: - py_binary_rule = lambda *args, **kwargs: py_binary(python_version = python_version, *args, **kwargs) - else: - py_binary_rule = py_binary # Write a script that can be used for updating the in-tree version of the # requirements file @@ -116,7 +110,7 @@ def lock(*, name, srcs, out, upgrade = False, universal = True, python_version = ], ) - py_binary_rule( + py_binary( name = update_target, srcs = [update_target + ".py"], main = update_target + ".py", diff --git a/python/uv/extensions.bzl b/python/uv/private/uv.bzl similarity index 85% rename from python/uv/extensions.bzl rename to python/uv/private/uv.bzl index 82560eb17c..886e7fe748 100644 --- a/python/uv/extensions.bzl +++ b/python/uv/private/uv.bzl @@ -18,15 +18,18 @@ EXPERIMENTAL: This is experimental and may be removed without notice A module extension for working with uv. """ -load("//python/uv:repositories.bzl", "uv_register_toolchains") +load(":uv_repositories.bzl", "uv_repositories") _DOC = """\ A module extension for working with uv. """ -uv_toolchain = tag_class(attrs = { - "uv_version": attr.string(doc = "Explicit version of uv.", mandatory = True), -}) +uv_toolchain = tag_class( + doc = "Configure uv toolchain for lock file generation.", + attrs = { + "uv_version": attr.string(doc = "Explicit version of uv.", mandatory = True), + }, +) def _uv_toolchain_extension(module_ctx): for mod in module_ctx.modules: @@ -38,7 +41,7 @@ def _uv_toolchain_extension(module_ctx): "NOTE: We may wish to enforce a policy where toolchain configuration is only allowed in the root module, or in rules_python. See https://github.com/bazelbuild/bazel/discussions/22024", ) - uv_register_toolchains( + uv_repositories( uv_version = toolchain.uv_version, register_toolchains = False, ) diff --git a/python/uv/repositories.bzl b/python/uv/private/uv_repositories.bzl similarity index 89% rename from python/uv/repositories.bzl rename to python/uv/private/uv_repositories.bzl index 0125b2033b..751126a138 100644 --- a/python/uv/repositories.bzl +++ b/python/uv/private/uv_repositories.bzl @@ -18,9 +18,9 @@ EXPERIMENTAL: This is experimental and may be removed without notice Create repositories for uv toolchain dependencies """ -load("//python/uv/private:toolchain_types.bzl", "UV_TOOLCHAIN_TYPE") -load("//python/uv/private:toolchains_repo.bzl", "uv_toolchains_repo") -load("//python/uv/private:versions.bzl", "UV_PLATFORMS", "UV_TOOL_VERSIONS") +load(":toolchain_types.bzl", "UV_TOOLCHAIN_TYPE") +load(":uv_toolchains_repo.bzl", "uv_toolchains_repo") +load(":versions.bzl", "UV_PLATFORMS", "UV_TOOL_VERSIONS") UV_BUILD_TMPL = """\ # Generated by repositories.bzl @@ -77,13 +77,13 @@ uv_repository = repository_rule( }, ) -# buildifier: disable=unnamed-macro -def uv_register_toolchains(uv_version = None, register_toolchains = True): +def uv_repositories(name = "uv_toolchains", uv_version = None, register_toolchains = True): """Convenience macro which does typical toolchain setup Skip this macro if you need more control over the toolchain setup. Args: + name: {type}`str` The name of the toolchains repo. uv_version: The uv toolchain version to download. register_toolchains: If true, repositories will be generated to produce and register `uv_toolchain` targets. """ @@ -109,7 +109,7 @@ def uv_register_toolchains(uv_version = None, register_toolchains = True): toolchain_compatible_with_by_toolchain[toolchain_name] = UV_PLATFORMS[platform].compatible_with uv_toolchains_repo( - name = "uv_toolchains", + name = name, toolchain_type = str(UV_TOOLCHAIN_TYPE), toolchain_names = toolchain_names, toolchain_labels = toolchain_labels_by_toolchain, @@ -117,4 +117,4 @@ def uv_register_toolchains(uv_version = None, register_toolchains = True): ) if register_toolchains: - native.register_toolchains("@uv_toolchains//:all") + native.register_toolchains("@{}/:all".format(name)) diff --git a/python/uv/toolchain.bzl b/python/uv/private/uv_toolchain.bzl similarity index 96% rename from python/uv/toolchain.bzl rename to python/uv/private/uv_toolchain.bzl index 3cd5850acd..3b51f5f533 100644 --- a/python/uv/toolchain.bzl +++ b/python/uv/private/uv_toolchain.bzl @@ -18,7 +18,7 @@ EXPERIMENTAL: This is experimental and may be removed without notice This module implements the uv toolchain rule """ -load("//python/uv/private:providers.bzl", "UvToolchainInfo") +load(":uv_toolchain_info.bzl", "UvToolchainInfo") def _uv_toolchain_impl(ctx): uv = ctx.attr.uv diff --git a/python/uv/private/providers.bzl b/python/uv/private/uv_toolchain_info.bzl similarity index 100% rename from python/uv/private/providers.bzl rename to python/uv/private/uv_toolchain_info.bzl diff --git a/python/uv/private/toolchains_repo.bzl b/python/uv/private/uv_toolchains_repo.bzl similarity index 100% rename from python/uv/private/toolchains_repo.bzl rename to python/uv/private/uv_toolchains_repo.bzl diff --git a/python/uv/uv.bzl b/python/uv/uv.bzl new file mode 100644 index 0000000000..d72ab9dc3d --- /dev/null +++ b/python/uv/uv.bzl @@ -0,0 +1,22 @@ +# Copyright 2025 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" EXPERIMENTAL: This is experimental and may be removed without notice. + +The uv toolchain extension. +""" + +load("//python/uv/private:uv.bzl", _uv = "uv") + +uv = _uv diff --git a/python/uv/uv_toolchain.bzl b/python/uv/uv_toolchain.bzl new file mode 100644 index 0000000000..a4b466cb1b --- /dev/null +++ b/python/uv/uv_toolchain.bzl @@ -0,0 +1,22 @@ +# Copyright 2025 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""The `uv_toolchain` rule. + +EXPERIMENTAL: This is experimental and may be removed without notice +""" + +load("//python/uv/private:uv_toolchain.bzl", _uv_toolchain = "uv_toolchain") + +uv_toolchain = _uv_toolchain diff --git a/python/uv/defs.bzl b/python/uv/uv_toolchain_info.bzl similarity index 78% rename from python/uv/defs.bzl rename to python/uv/uv_toolchain_info.bzl index 20b426a355..1ae89636be 100644 --- a/python/uv/defs.bzl +++ b/python/uv/uv_toolchain_info.bzl @@ -1,4 +1,4 @@ -# Copyright 2024 The Bazel Authors. All rights reserved. +# Copyright 2025 The Bazel Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -""" -EXPERIMENTAL: This is experimental and may be removed without notice +"""The `UvToolchainInfo` provider. -A toolchain for uv +EXPERIMENTAL: This is experimental and may be removed without notice """ -load("//python/uv/private:providers.bzl", _UvToolchainInfo = "UvToolchainInfo") +load("//python/uv/private:uv_toolchain_info.bzl", _UvToolchainInfo = "UvToolchainInfo") UvToolchainInfo = _UvToolchainInfo