Bazel rules to enable use of uv to compile pip requirements and generate virtual envs.
Installing with bzlmod, add to MODULE.bazel (adjust version as appropriate):
bazel_dep(name = "rules_uv", version = "<version>")
Note: rules_uv requires a Python toolchain to be available. One can be obtained by having rules_python installed using:
bazel_dep(name = "rules_python", version = "<rules_python version>")
Create a requirements.in or pyproject.toml -> requirements.txt compilation target and diff test:
load("@rules_uv//uv:pip.bzl", "pip_compile")
pip_compile(
name = "generate_requirements_txt",
requirements_in = "//:requirements.in", # default
requirements_txt = "//:requirements.txt", # default
)
Ensure both requirements.in and requirements.txt exist (the latter must exist but may be empty).
Run the compilation step with bazel run //:generate_requirements_txt
.
This will automatically register a diff test with name [name]_test
.
Additionally, you can specify the following optional args:
python_platform
: theuv pip compile
compatible--python-platform
value to pass to uvargs
: override the default arguments passed to uv (--generate-hashes
,--emit-index-url
and--no-strip-extras
)data
: pass additional files to be present when generating and testing requirements txt files (see also examples/multiple-inputs)tags
: tags to apply to the test targettarget_compatible_with
: restrict targets to running on the specified Bazel platform
Create a virtual environment creation target:
load("@rules_uv//uv:venv.bzl", "create_venv")
create_venv(
name = "create_venv",
requirements_txt = "//:requirements.txt", # default
)
Create a virtual environment with default path venv
by running bazel run //:create_venv
. The generated script accepts a single, optional argument to define the virtual environment path.
The created venv will use the default Python 3 runtime defined in rules_python.
If you want to use this script cross-platform including Windows, you must use a .cmd
or .bat
ending
for the command name (e.g., name = "create_venv.cmd"
) since Windows expects to identify the executable scripts by the file ending of the target.
For this target to work on Windows, you also have to enable symlinks and enable runfiles. If you want to add this options to
your .bazelrc
file, you can do so with
startup --windows_enable_symlinks
common --enable_runfiles
uv
supports generating platform-specific requirements files, and rules_uv
exposes this configuration, and a multi-platform setup might look like this:
load("@rules_multirun//:defs.bzl", "multirun")
load("@rules_uv//uv:pip.bzl", "pip_compile")
load("@rules_uv//uv:venv.bzl", "create_venv")
pip_compile(
name = "generate_requirements_linux_txt",
python_platform = "x86_64-unknown-linux-gnu",
requirements_txt = "requirements_linux.txt",
)
pip_compile(
name = "generate_requirements_macos_txt",
python_platform = "aarch64-apple-darwin",
requirements_txt = "requirements_macos.txt",
)
multirun(
name = "generate_requirements_lock",
commands = [
":generate_requirements_linux_txt",
":generate_requirements_macos_txt",
],
# Running in a single threaded mode allows consecutive `uv` invocations to benefit
# from the `uv` cache from the first run.
jobs = 1,
)
create_venv(
name = "create_venv",
requirements_txt = select({
"@platforms//os:linux": ":requirements_linux.txt",
"@platforms//os:osx": ":requirements_macos.txt",
}),
)
This makes use of the excellent rules_multirun.
To match up with rules_python
, a bzlmod config will look something like:
pip.parse(
hub_name = "pip",
python_version = "3.11",
requirements_darwin = "//:requirements_macos.txt",
requirements_linux = "//:requirements_linux.txt",
)