Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
7 changes: 3 additions & 4 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ import %workspace%/bazel/defaults.bazelrc

common --enable_bzlmod

# Ignore slow manual and release targets
# Prevents materializing crossbuild
common --build_tag_filters=-manual,-release

common --test_output=errors

# Define value used by tests
common --define=SOME_VAR=SOME_VALUE

# Set the default virtualenv to 'default'
common --@pypi//venv=default

common --incompatible_enable_cc_toolchain_resolution

# TODO(bzlmod): Don't break proto
Expand Down
52 changes: 28 additions & 24 deletions .bcr/patches/remove_dev_deps.patch
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
--- a/MODULE.bazel 2025-11-04 23:45:40.547616185 +0000
+++ b/MODULE.bazel 2025-11-04 23:45:40.547616185 +0000
@@ -24,554 +24,3 @@
"@aspect_rules_py//py/private/toolchain/shim/...",
)
--- a/MODULE.bazel 2025-11-06 12:48:12
+++ b/MODULE.bazel 2025-11-06 12:48:12
@@ -40,558 +40,5 @@
# HACK: In prod the includer's patch inserts the use_repo for multitool. This
# solves the problem of needing a use_repo here in prod and below in dev.

-################################################################################
-# Dev deps
Expand All @@ -29,7 +29,7 @@
-# include("//bazel/include:release.MODULE.bazel")
-# include("//bazel/include:multitool.MODULE.bazel")
-# include("//bazel/include:tools.MODULE.bazel")
-
-################################################################################
-# Begin included content
-
Expand Down Expand Up @@ -169,15 +169,7 @@
-# from bazel/include/rust.MODULE.bazel
-# Rust configuration
-
-bazel_dep(name = "rules_rust", version = "0.66.0")
-single_version_override(
- module_name = "rules_rust",
- patch_strip = 1,
- patches = [
- "//bazel/patches:rules_rust.patch",
- ],
-)
-
-bazel_dep(name = "rules_rust", version = "0.67.0")
-bazel_dep(name = "openssl", version = "3.3.1.bcr.6")
-
-RUST_EDITION = "2024"
Expand Down Expand Up @@ -493,23 +485,35 @@
- python_version = "3.12",
-)
-
-# We still use pip for testing the virtual deps machinery
-pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True)
-pip.parse(
- hub_name = "django",
- python_version = "3.9",
- requirements_lock = "//py/tests/virtual/django:requirements.txt",
-)
-pip.parse(
-use_repo(pip, "django")
-
-# For everything else, we use our own uv machinery
-uv = use_extension("//uv/unstable:extension.bzl", "uv", dev_dependency = True)
-uv.declare_hub(
- hub_name = "pypi",
- python_version = "3.9",
- requirements_lock = "//:requirements.txt",
-)
-pip.parse(
-uv.declare_venv(
- hub_name = "pypi",
- python_version = "3.12",
- requirements_lock = "//:requirements.txt",
- venv_name = "default",
-)
-uv.lockfile(
- src = "//:uv.lock",
- hub_name = "pypi",
- venv_name = "default",
-)
-uv.unstable_annotate_requirements(
- src = "//:annotations.toml",
- hub_name = "pypi",
- venv_name = "default",
-)
-use_repo(pip, "django", "pypi")
-use_repo(uv, "pypi")
-
-http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
-
Expand All @@ -536,18 +540,18 @@
-
-########################################
-# from bazel/include/release.MODULE.bazel
-bazel_dep(name = "with_cfg.bzl", version = "0.11.0")
-bazel_dep(name = "rules_pkg", version = "1.1.0")
-
-########################################
-# from bazel/include/multitool.MODULE.bazel
-# Multitool configuration
-
-# Multitool is a prod dep (for now) so we don't need this
-bazel_dep(name = "rules_multitool", version = "1.9.0")
-
-multitool = use_extension("@rules_multitool//multitool:extension.bzl", "multitool")
-multitool.hub(lockfile = "//tools:tools.lock.json")
-use_repo(multitool, "multitool")
use_repo(multitool, "multitool")
-
-########################################
-# from bazel/include/tools.MODULE.bazel
Expand Down
16 changes: 5 additions & 11 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
load("@gazelle//:def.bzl", "gazelle")
load("@pypi//:requirements.bzl", "all_whl_requirements")
load("@rules_python//python/pip_install:requirements.bzl", "compile_pip_requirements")
load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest")
load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")
load("//uv/private/manifest:defs.bzl", "gazelle_python_manifest")

# gazelle:exclude internal_python_deps.bzl
# gazelle:exclude internal_deps.bzl
Expand All @@ -12,9 +10,10 @@ load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")

gazelle_python_manifest(
name = "gazelle_python_manifest",
modules_mapping = ":modules_map",
pip_repository_name = "pypi",
requirements = "requirements.txt",
hub = "pypi",
venvs = [
"default",
],
)

gazelle(
Expand All @@ -28,8 +27,3 @@ compile_pip_requirements(
requirements_in = "requirements.in",
requirements_txt = "requirements.txt",
)

modules_mapping(
name = "modules_map",
wheels = all_whl_requirements,
)
54 changes: 37 additions & 17 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ bazel_dep(name = "bazel_lib", version = "3.0.0")
bazel_dep(name = "bazel_skylib", version = "1.4.2")
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "rules_python", version = "1.0.0")
bazel_dep(name = "with_cfg.bzl", version = "0.11.0")

tools = use_extension("//py:extensions.bzl", "py_tools")
tools.rules_py_tools()
Expand All @@ -24,6 +25,21 @@ register_toolchains(
"@aspect_rules_py//py/private/toolchain/shim/...",
)

toml = use_extension("//uv/private/tomltool:extension.bzl", "tomltool")
use_repo(
toml,
"toml2json_aarch64_linux_gnu",
"toml2json_aarch64_osx_libsystem",
"toml2json_x86_64_linux_gnu",
"toml2json_x86_64_osx_libsystem",
)

host = use_extension("//uv/private/host:extension.bzl", "host_platform")
use_repo(host, "aspect_rules_py_uv_host")

# HACK: In prod the includer's patch inserts the use_repo for multitool. This
# solves the problem of needing a use_repo here in prod and below in dev.

################################################################################
# Dev deps
#
Expand Down Expand Up @@ -189,15 +205,7 @@ platforms = [
# from bazel/include/rust.MODULE.bazel
# Rust configuration

bazel_dep(name = "rules_rust", version = "0.66.0")
single_version_override(
module_name = "rules_rust",
patch_strip = 1,
patches = [
"//bazel/patches:rules_rust.patch",
],
)

bazel_dep(name = "rules_rust", version = "0.67.0")
bazel_dep(name = "openssl", version = "3.3.1.bcr.6")

RUST_EDITION = "2024"
Expand Down Expand Up @@ -513,23 +521,35 @@ python.toolchain(
python_version = "3.12",
)

# We still use pip for testing the virtual deps machinery
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True)
pip.parse(
hub_name = "django",
python_version = "3.9",
requirements_lock = "//py/tests/virtual/django:requirements.txt",
)
pip.parse(
use_repo(pip, "django")

# For everything else, we use our own uv machinery
uv = use_extension("//uv/unstable:extension.bzl", "uv", dev_dependency = True)
uv.declare_hub(
hub_name = "pypi",
python_version = "3.9",
requirements_lock = "//:requirements.txt",
)
pip.parse(
uv.declare_venv(
hub_name = "pypi",
python_version = "3.12",
requirements_lock = "//:requirements.txt",
venv_name = "default",
)
use_repo(pip, "django", "pypi")
uv.lockfile(
src = "//:uv.lock",
hub_name = "pypi",
venv_name = "default",
)
uv.unstable_annotate_requirements(
src = "//:annotations.toml",
hub_name = "pypi",
venv_name = "default",
)
use_repo(uv, "pypi")

http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")

Expand All @@ -556,13 +576,13 @@ http_file(

########################################
# from bazel/include/release.MODULE.bazel
bazel_dep(name = "with_cfg.bzl", version = "0.11.0")
bazel_dep(name = "rules_pkg", version = "1.1.0")

########################################
# from bazel/include/multitool.MODULE.bazel
# Multitool configuration

# Multitool is a prod dep (for now) so we don't need this
bazel_dep(name = "rules_multitool", version = "1.9.0")

multitool = use_extension("@rules_multitool//multitool:extension.bzl", "multitool")
Expand Down
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Aspect's Bazel rules for Python

`aspect_rules_py` is a layer on top of `rules_python`, the standard Python ruleset hosted at
https://github.com/bazelbuild/rules_python.
The lower layer of `rules_python` is currently reused, dealing with the toolchain and dependencies.
`aspect_rules_py` is a layer on top of [rules_python](https://github.com/bazel-contrib/rules_python), the reference Python ruleset.

However, this ruleset introduces a new implementation of `py_library`, `py_binary`, and `py_test`.
The lower layer of `rules_python` is currently reused, dealing with interpreter toolchains and other details.

However, this ruleset introduces new implementations of `py_library`, `py_binary`, `py_test` and now `uv`.
Our philosophy is to behave more like idiomatic python ecosystem tools, where rules_python is closely
tied to the way Google does Python development in their internal monorepo, google3.
However we try to maintain compatibility with rules_python's rules for most use cases.

| Layer | Legacy | Recommended |
| ------------------------------------------- | ------------ | -------------------- |
| toolchain: fetch hermetic interpreter | rules_python | rules_python |
| pip.parse: fetch and install deps from pypi | rules_python | rules_python |
| gazelle: generate BUILD files | rules_python | [`aspect configure`] |
| rules: user-facing implementations | rules_python | **rules_py** |
| Layer | Legacy | Recommended |
| ------------------------------------- | ------------ | ----------------------- |
| toolchain: fetch hermetic interpreter | rules_python | rules_python |
| deps: fetch and install from pypi | rules_python | **aspect_rules_py//uv** |
| rules: user-facing implementations | rules_python | **aspect_rules_py//py** |
| gazelle: generate BUILD files | rules_python | [`aspect configure`] |

[`aspect configure`]: https://docs.aspect.build/cli/commands/aspect_configure

Expand Down
42 changes: 42 additions & 0 deletions annotations.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## Annotations.toml
#
# This is an aspect_rules_py//uv specific configuration file which allows
# packages to be annotated with their build time dependencies. This fills a gap in
# both the pylock and uv lockfile formats, neither of which allow for build
# requirements to be specified.
#
# For instance if a package requires cython be available, this is how you can
# configure it to be delivered.
#
# Takes the place of giant MODULE.bazel annotation tables.
#
# In future this machinery may allow for annotating requirements with
# Bazel-managed dependencies (C libraries, etc.) by label. The exact semantics
# there are TBD.

# We version lockfiles and support semver semantics here
version = "0.0.0"

# Bravado doesn't have bdists, need to build it. Mark explicitly that we need
# wheel setuptools and build in order to do so; build being the standard build
# tool driver.
[[package]]
name = "bravado-core"
build-dependencies = [
{ name = "build" },
{ name = "setuptools" },
]

# We can also annotate packages as providing console scripts we care about.
# Declared console scripts will have Bazel targets generated for them.
#
# Unlike `rules_python` which sees post-install package contents,
# `aspect_rules_py//uv` doesn't and so can't discover entrypoints to generate
# Bazel targets ahead of time. They have to be predeclared if you want to
# reference them as targets.
[[package]]
name = "pytest"

[package.entry-points.console-scripts]
pytest = "pytest:console_main"
"py.test" = "pytest:console_main"
1 change: 1 addition & 0 deletions bazel/include/multitool.MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Multitool configuration

# Multitool is a prod dep (for now) so we don't need this
bazel_dep(name = "rules_multitool", version = "1.9.0")

multitool = use_extension("@rules_multitool//multitool:extension.bzl", "multitool")
Expand Down
26 changes: 19 additions & 7 deletions bazel/include/python.MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,35 @@ python.toolchain(
python_version = "3.12",
)

# We still use pip for testing the virtual deps machinery
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True)
pip.parse(
hub_name = "django",
python_version = "3.9",
requirements_lock = "//py/tests/virtual/django:requirements.txt",
)
pip.parse(
use_repo(pip, "django")

# For everything else, we use our own uv machinery
uv = use_extension("//uv/unstable:extension.bzl", "uv", dev_dependency = True)
uv.declare_hub(
hub_name = "pypi",
python_version = "3.9",
requirements_lock = "//:requirements.txt",
)
pip.parse(
uv.declare_venv(
hub_name = "pypi",
python_version = "3.12",
requirements_lock = "//:requirements.txt",
venv_name = "default",
)
uv.lockfile(
src = "//:uv.lock",
hub_name = "pypi",
venv_name = "default",
)
uv.unstable_annotate_requirements(
src = "//:annotations.toml",
hub_name = "pypi",
venv_name = "default",
)
use_repo(pip, "django", "pypi")
use_repo(uv, "pypi")

http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")

Expand Down
1 change: 0 additions & 1 deletion bazel/include/release.MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
bazel_dep(name = "with_cfg.bzl", version = "0.11.0")
bazel_dep(name = "rules_pkg", version = "1.1.0")
Loading
Loading