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): parse the dist-manifest.json to not hardcode sha256 in rules_python #2578

Merged
merged 51 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
902502c
feat(uv): allow specifying any uv version to use
aignas Jan 25, 2025
57377a8
update the example
aignas Jan 25, 2025
b8fa595
cleanup
aignas Jan 25, 2025
8548c69
add a note
aignas Jan 27, 2025
1be7704
Merge branch 'main' into feat/improve-uv-mgmt
aignas Feb 24, 2025
503a956
Merge branch 'main' into feat/improve-uv-mgmt
aignas Feb 24, 2025
069a04c
update changelog
aignas Feb 24, 2025
e46d8eb
more cleanup
aignas Feb 24, 2025
6b675f0
add a comment
aignas Feb 24, 2025
4b709f1
add docs
aignas Feb 24, 2025
49b586b
Merge branch 'main' into feat/improve-uv-mgmt
aignas Feb 24, 2025
f29c585
wip
aignas Feb 24, 2025
79855d2
wip
aignas Feb 25, 2025
9a79668
wip
aignas Feb 25, 2025
1ac0437
finish a test
aignas Feb 25, 2025
76d581c
Allow specifying the URL and sha256 values manually
aignas Feb 25, 2025
79f3a3d
docs
aignas Feb 25, 2025
a1a4072
fixup the tests
aignas Feb 25, 2025
a4f2cf8
add docs
aignas Feb 25, 2025
c4c8105
cleanup the handling of urls and do not download unnecessary sha256 f…
aignas Feb 27, 2025
df80ed8
improve docs
aignas Feb 27, 2025
832007c
simplify and reuse code
aignas Feb 27, 2025
8076549
more cleanup
aignas Feb 27, 2025
0ea9494
bump the default uv version to 0.6.3
aignas Feb 27, 2025
8d9eda6
Merge branch 'main' into feat/improve-uv-mgmt
aignas Mar 7, 2025
9382f6a
rename parse_modules to process_modules and create hub repo in it.
aignas Mar 7, 2025
2f7c38d
update the return value doc
aignas Mar 7, 2025
472f5fa
document the builder dicts
aignas Mar 7, 2025
18db761
ignore calls from non-rules_python non-root modules
aignas Mar 7, 2025
77672e6
ensure that default keys are set
aignas Mar 7, 2025
e66834c
base_url defalut setting
aignas Mar 7, 2025
b3dccf7
rename '_attr' to 'tag'
aignas Mar 7, 2025
5deabba
remove guard
aignas Mar 7, 2025
8eff080
use a list
aignas Mar 7, 2025
ef90b2f
document the file format
aignas Mar 7, 2025
3367366
buildifier errors
aignas Mar 7, 2025
d07de0b
rename toolchain_labels
aignas Mar 7, 2025
479449a
document version
aignas Mar 7, 2025
9ed3b7c
rename toolchain_labels to toolchain_implementations and remove uv_re…
aignas Mar 7, 2025
019c6a1
add an analysis test to check lexicographical registration order
aignas Mar 7, 2025
621b80d
attempt to clarify the documentation wording.
aignas Mar 7, 2025
929b3e4
cleanup docs
aignas Mar 7, 2025
f63d453
improve the toolchain hub generation
aignas Mar 8, 2025
f82fc81
further cleanup
aignas Mar 9, 2025
e61a251
add documentation
aignas Mar 9, 2025
d00ee31
fix the toolchains registration and document the algorithm
aignas Mar 9, 2025
52db4c9
Merge branch 'main' into feat/improve-uv-mgmt
aignas Mar 9, 2025
f2b8ad7
add a test for non-root modules
aignas Mar 10, 2025
c2f76d8
ensure rules_python never overrides settings from the root module
aignas Mar 10, 2025
3cd8e4d
address review comments
aignas Mar 11, 2025
c2ed9ae
buildifier
aignas Mar 11, 2025
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ Unreleased changes template.
* {obj}`//python/bin:python`: convenience target for directly running an
interpreter. {obj}`--//python/bin:python_src` can be used to specify a
binary whose interpreter to use.
* (uv) Now the extension can be fully configured via `bzlmod` APIs without the
need to patch `rules_python`. The documentation has been added to `rules_python`
docs but usage of the extension may result in your setup breaking without any
notice. What is more, the URLs and SHA256 values will be retrieved from the
GitHub releases page metadata published by the `uv` project.
* (pypi) An extra argument to add the interpreter lib dir to `LDFLAGS` when
building wheels from `sdist`.

Expand Down
83 changes: 75 additions & 8 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,83 @@ use_repo(
"build_bazel_bazel_self",
)

# EXPERIMENTAL: This is experimental and may be removed without notice
uv = use_extension(
# TODO @aignas 2025-01-27: should this be moved to `//python/extensions:uv.bzl` or should
# it stay as it is? I think I may prefer to move it.
uv = use_extension("//python/uv:uv.bzl", "uv")

# Here is how we can define platforms for the `uv` binaries - this will affect
# all of the downstream callers because we are using the extension without
# `dev_dependency = True`.
uv.default(
base_url = "https://github.com/astral-sh/uv/releases/download",
manifest_filename = "dist-manifest.json",
version = "0.6.3",
)
uv.default(
compatible_with = [
"@platforms//os:macos",
"@platforms//cpu:aarch64",
],
platform = "aarch64-apple-darwin",
)
uv.default(
compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:aarch64",
],
platform = "aarch64-unknown-linux-gnu",
)
uv.default(
compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:ppc",
],
platform = "powerpc64-unknown-linux-gnu",
)
uv.default(
compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:ppc64le",
],
platform = "powerpc64le-unknown-linux-gnu",
)
uv.default(
compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:s390x",
],
platform = "s390x-unknown-linux-gnu",
)
uv.default(
compatible_with = [
"@platforms//os:macos",
"@platforms//cpu:x86_64",
],
platform = "x86_64-apple-darwin",
)
uv.default(
compatible_with = [
"@platforms//os:windows",
"@platforms//cpu:x86_64",
],
platform = "x86_64-pc-windows-msvc",
)
uv.default(
compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
platform = "x86_64-unknown-linux-gnu",
)
use_repo(uv, "uv")

register_toolchains("@uv//:all")

uv_dev = use_extension(
"//python/uv:uv.bzl",
"uv",
dev_dependency = True,
)
uv.toolchain(uv_version = "0.4.25")
use_repo(uv, "uv_toolchains")

register_toolchains(
"@uv_toolchains//:all",
dev_dependency = True,
uv_dev.configure(
version = "0.6.2",
)
15 changes: 9 additions & 6 deletions examples/bzlmod/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,15 @@ python.single_version_platform_override(
# rules based on the `python_version` arg values.
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:uv.bzl", "uv")
uv.toolchain(uv_version = "0.4.25")
use_repo(uv, "uv_toolchains")

register_toolchains("@uv_toolchains//:all")
# EXPERIMENTAL: This is experimental and may be changed or removed without notice
uv = use_extension(
"@rules_python//python/uv:uv.bzl",
"uv",
# Use `dev_dependency` so that the toolchains are not defined pulled when your
# module is used elsewhere.
dev_dependency = True,
)
uv.configure(version = "0.6.2")

# This extension allows a user to create modifications to how rules_python
# creates different wheel repositories. Different attributes allow the user
Expand Down
21 changes: 7 additions & 14 deletions python/uv/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,19 @@ bzl_library(
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_repository_bzl",
":uv_toolchains_repo_bzl",
":versions_bzl",
],
)

bzl_library(
name = "uv_repository_bzl",
srcs = ["uv_repository.bzl"],
visibility = ["//python/uv:__subpackages__"],
)

bzl_library(
name = "uv_toolchain_bzl",
srcs = ["uv_toolchain.bzl"],
Expand All @@ -82,9 +81,3 @@ bzl_library(
"//python/private:text_util_bzl",
],
)

bzl_library(
name = "versions_bzl",
srcs = ["versions.bzl"],
visibility = ["//python/uv:__subpackages__"],
)
8 changes: 5 additions & 3 deletions python/uv/private/lock.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ def lock(*, name, srcs, out, upgrade = False, universal = True, args = [], **kwa
"""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 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.
- The execution of the lock file generation is happening inside of a build
action in a `genrule`.

Args:
name: The name of the target to run for updating the requirements.
Expand All @@ -41,8 +43,8 @@ def lock(*, name, srcs, out, upgrade = False, universal = True, args = [], **kwa
upgrade: Tell `uv` to always upgrade the dependencies instead of
keeping them as they are.
universal: Tell `uv` to generate a universal lock file.
args: Extra args to pass to `uv`.
**kwargs: Extra kwargs passed to the {obj}`py_binary` rule.
args: Extra args to pass to the rule.
**kwargs: Extra kwargs passed to the binary rule.
"""
pkg = native.package_name()
update_target = name + ".update"
Expand Down
65 changes: 65 additions & 0 deletions python/uv/private/toolchains_hub.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# 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.

"""A macro used from the uv_toolchain hub repo."""

load(":toolchain_types.bzl", "UV_TOOLCHAIN_TYPE")

def toolchains_hub(
*,
name,
toolchains,
implementations,
target_compatible_with,
target_settings):
"""Define the toolchains so that the lexicographical order registration is deterministic.

TODO @aignas 2025-03-09: see if this can be reused in the python toolchains.

Args:
name: The prefix to all of the targets, which goes after a numeric prefix.
toolchains: The toolchain names for the targets defined by this macro.
The earlier occurring items take precedence over the later items if
they match the target platform and target settings.
implementations: The name to label mapping.
target_compatible_with: The name to target_compatible_with list mapping.
target_settings: The name to target_settings list mapping.
"""
if len(toolchains) != len(implementations):
fail("Each name must have an implementation")

# We are defining the toolchains so that the order of toolchain matching is
# the same as the order of the toolchains, because:
# * the toolchains are matched by target settings and target_compatible_with
# * the first toolchain satisfying the above wins
#
# this means we need to register the toolchains prefixed with a number of
# format 00xy, where x and y are some digits and the leading zeros to
# ensure lexicographical sorting.
#
# Add 1 so that there is always a leading zero
prefix_len = len(str(len(toolchains))) + 1
prefix = "0" * (prefix_len - 1)

for i, toolchain in enumerate(toolchains):
# prefix with a prefix and then truncate the string.
number_prefix = "{}{}".format(prefix, i)[-prefix_len:]

native.toolchain(
name = "{}_{}_{}".format(number_prefix, name, toolchain),
target_compatible_with = target_compatible_with.get(toolchain, []),
target_settings = target_settings.get(toolchain, []),
toolchain = implementations[toolchain],
toolchain_type = UV_TOOLCHAIN_TYPE,
)
Loading
Loading