Skip to content
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
37 changes: 37 additions & 0 deletions docs/api/rules_python/python/uv/bin/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
:::{default-domain} bzl
Comment thread
rickeylev marked this conversation as resolved.
:::
:::{bzl:currentfile} //python/uv/bin:BUILD.bazel
:::

# //python/uv/bin

Executable aliases for the configured `uv` binary. These targets can be run
directly with `bazel run` or passed to tools such as
[`bazel_env.bzl`](https://github.com/buildbuddy-io/bazel_env.bzl) (or via
{obj}`//python/uv:current_toolchain` and `$(UV)`).

::::{bzl:target} bin

Alias for {obj}`//python/uv:current_toolchain` to directly run the configured
`uv` binary:

```sh
bazel run @rules_python//python/uv/bin -- --help
```

:::{versionadded} VERSION_NEXT_FEATURE
:::
::::

::::{bzl:target} uv

Alias for {obj}`//python/uv:current_toolchain` to directly run the configured
`uv` binary:

```sh
bazel run @rules_python//python/uv/bin:uv -- --help
```

:::{versionadded} VERSION_NEXT_FEATURE
:::
::::
43 changes: 43 additions & 0 deletions docs/api/rules_python/python/uv/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
:::{default-domain} bzl
:::
:::{bzl:currentfile} //python/uv:BUILD.bazel
:::

# //python/uv

::::{bzl:target} current_toolchain

Exposes the resolved `uv` toolchain for the target/execution platform as an
executable target and template variable provider (`$(UV)` and `$(UV_BIN)`).

Can be run directly with `bazel run`:

```sh
bazel run @rules_python//python/uv:current_toolchain -- --help
```

Or integrated with
[`bazel_env.bzl`](https://github.com/buildbuddy-io/bazel_env.bzl) to expose
`uv` on your local `PATH`:

```bzl
bazel_env(
name = "bazel_env",
toolchains = {
"uv": "@rules_python//python/uv:current_toolchain",
},
tools = {
"uv": "$(UV)",
},
)
```

:::{versionadded} VERSION_NEXT_FEATURE
:::
::::

:::{bzl:target} uv_toolchain_type

Toolchain type identifier for the `uv` toolchain, implemented by
{obj}`uv_toolchain`.
:::
3 changes: 3 additions & 0 deletions docs/pypi/lock.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ uv.configure(version = "0.13.5")

Without `version`, the default version specified by `rules_python` is used.
See {obj}`uv.configure` for using a mirror, explicit URLs or extra platforms.
To run the configured `uv` binary directly, run
`bazel run @rules_python//python/uv/bin:uv -- <args>` (or add
`use_repo(uv, "uv")` and run `bazel run @uv//bin:bin -- <args>`).

(uv-workspace-setup)=
##### WORKSPACE
Expand Down
5 changes: 5 additions & 0 deletions news/uv-bin-target.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(uv) Added `@uv//bin:bin`, {obj}`//python/uv/bin:uv`,
{obj}`//python/uv/bin:bin`, and public visibility on
{obj}`//python/uv:current_toolchain` (along with the `$(UV)` make variable) to
run the configured `uv` binary directly (e.g.
`bazel run @uv//bin:bin -- --help`).
6 changes: 1 addition & 5 deletions python/uv/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,7 @@ current_toolchain(
# Marked manual so that `bazel test //...` passes
# even if no toolchain is registered.
tags = ["manual"],
# EXPERIMENTAL: Visibility is restricted to allow for changes.
visibility = [
"//:__subpackages__",
"@rules_python//examples:__subpackages__",
],
visibility = ["//visibility:public"],
)

bzl_library(
Expand Down
21 changes: 21 additions & 0 deletions python/uv/bin/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load("//python/private:distribution_filegroup.bzl", "distribution_filegroup")

package(default_visibility = ["//:__subpackages__"])

distribution_filegroup(
name = "distribution",
)

alias(
name = "bin",
actual = "//python/uv:current_toolchain",
tags = ["manual"],
visibility = ["//visibility:public"],
)

alias(
name = "uv",
actual = "//python/uv:current_toolchain",
tags = ["manual"],
visibility = ["//visibility:public"],
)
19 changes: 16 additions & 3 deletions python/uv/private/current_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,29 @@ def _current_toolchain_impl(ctx):
original_uv_executable = toolchain_info.uv_toolchain_info.uv[DefaultInfo].files_to_run.executable

# 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)
if original_uv_executable.extension:
ext = "." + original_uv_executable.extension
else:
ext = ""
symlink_uv_executable = ctx.actions.declare_file(
"{}/uv{}".format(ctx.label.name, ext),
)
ctx.actions.symlink(
output = symlink_uv_executable,
target_file = original_uv_executable,
is_executable = True,
)

new_default_info = DefaultInfo(
files = depset([symlink_uv_executable]),
runfiles = toolchain_info.default_info.default_runfiles,
runfiles = ctx.runfiles(files = [original_uv_executable]).merge(
toolchain_info.default_info.default_runfiles,
),
executable = symlink_uv_executable,
)

template_variable_info = platform_common.TemplateVariableInfo({
"UV": symlink_uv_executable.path,
"UV_BIN": symlink_uv_executable.path,
})

Expand Down
13 changes: 13 additions & 0 deletions python/uv/private/uv.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,21 @@ uv = use_extension(
uv.configure(version = "0.13.5")
```

To run `uv` directly:
```sh
bazel run @rules_python//python/uv/bin:uv -- --help
# Or, if `use_repo(uv, "uv")` is in MODULE.bazel:
bazel run @uv//bin:bin -- --help
```

Since this is only for locking the requirements files, it should be always
marked as a `dev_dependency`.

:::{versionchanged} VERSION_NEXT_FEATURE
Added `@uv//bin:bin` and {obj}`//python/uv/bin:uv` (aliases for
{obj}`//python/uv:current_toolchain`) to run the configured `uv` binary
directly.
:::
"""

_DEFAULT_ATTRS = {
Expand Down
3 changes: 2 additions & 1 deletion python/uv/private/uv_register_toolchains.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ def uv_register_toolchains(
This is the WORKSPACE equivalent of the {obj}`uv` module extension. It
creates one download repository per `uv` version and platform, and the
toolchain hub repository `name` with a `toolchain` for each of them, which
it registers as `@{name}//:all`; {obj}`lock` can then be used. See the
it registers as `@{name}//:all`; {obj}`lock` can then be used, and `uv` can
be run directly via `bazel run @{name}//bin:bin -- <args>`. See the
{ref}`WORKSPACE setup guide <uv-workspace-setup>` for usage examples.

Platforms without an archive in a manifest get no toolchain. The
Expand Down
9 changes: 9 additions & 0 deletions python/uv/private/uv_toolchains_repo.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ load("@rules_python//python/uv/private:toolchains_hub.bzl", "toolchains_hub")
{}
"""

_BIN_BUILD_TEMPLATE = """\
alias(
name = "bin",
actual = "@rules_python//python/uv:current_toolchain",
visibility = ["//visibility:public"],
)
"""

def _non_empty(d):
return {k: v for k, v in d.items() if v}

Expand All @@ -45,6 +53,7 @@ def _toolchains_repo_impl(repository_ctx):
),
)
repository_ctx.file("BUILD.bazel", contents)
repository_ctx.file("bin/BUILD.bazel", _BIN_BUILD_TEMPLATE)

uv_toolchains_repo = repository_rule(
_toolchains_repo_impl,
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/bzlmod_lockfile/MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 15 additions & 3 deletions tests/uv/toolchain/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@ load("//python:py_test.bzl", "py_test")
genrule(
name = "uv_help",
outs = ["uv_help.txt"],
cmd = "$(UV_BIN) --python-fetch manual --help >$@",
cmd = 'test "$(UV)" = "$(UV_BIN)" && $(UV) --python-fetch manual --help >$@',
toolchains = ["//python/uv:current_toolchain"],
)

py_test(
name = "uv_help_test",
srcs = ["uv_help_test.py"],
data = [":uv_help"],
env = {"DATA": "$(rlocationpath :uv_help)"},
data = [
":uv_help",
"//python/uv:current_toolchain",
"//python/uv/bin",
"//python/uv/bin:uv",
"@uv//bin",
],
env = {
"DATA": "$(rlocationpath :uv_help)",
"UV_BIN": "$(rlocationpath @uv//bin:bin)",
"UV_CURRENT_TOOLCHAIN": "$(rlocationpath //python/uv:current_toolchain)",
"UV_RULES_PYTHON_BIN": "$(rlocationpath //python/uv/bin:bin)",
"UV_RULES_PYTHON_UV": "$(rlocationpath //python/uv/bin:uv)",
Comment thread
rickeylev marked this conversation as resolved.
},
deps = ["//python/runfiles"],
)
24 changes: 23 additions & 1 deletion tests/uv/toolchain/uv_help_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python

import os
import subprocess
import unittest
from pathlib import Path

Expand All @@ -20,7 +21,28 @@ def test_uv_help(self):

uv_help = Path(uv_help_path).read_text()

self.assertIn("Usage: uv [OPTIONS] <COMMAND>", uv_help)
self.assertRegex(uv_help, r"Usage: uv(\.exe)? \[OPTIONS\] <COMMAND>")

def test_uv_bin(self):
root = runfiles.CreateOrRaise().root()

for env_var in (
"UV_BIN",
"UV_CURRENT_TOOLCHAIN",
"UV_RULES_PYTHON_BIN",
"UV_RULES_PYTHON_UV",
):
with self.subTest(env_var=env_var):
uv_bin_path = root / os.environ[env_var]
result = subprocess.run(
[uv_bin_path, "--python-fetch", "manual", "--help"],
capture_output=True,
text=True,
check=True,
)
self.assertRegex(
result.stdout, r"Usage: uv(\.exe)? \[OPTIONS\] <COMMAND>"
)


if __name__ == "__main__":
Expand Down
Loading