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