Skip to content

Commit 5eff339

Browse files
authored
fix(bzlmod): keep the lockfile platform independent when resolving python (#2135)
Before this PR the lockfile would become platform dependent when the `requirements` file would have env markers. This was not caught because we do not have MODULE.bazel.lock checked into the `rules_python` repository because the CI is running against many versions and the lock file is different, therefore we would not be able to run with `bazel build --lockfile_mode=error`. With this change we use the label to `BUILD.bazel` which is living next to the `python` symlink and since the `BUILD.bazel` is the same on all platforms, the lockfile will remain the same. Summary * refactor(uv): create a reusable macro for using uv for locking reqs. * test(bzlmod): enable testing the MODULE.bazel.lock breakage across platforms. * test(bzlmod): use a universal requirements file for 3.9. This breaks the CI, because the python interpreter file hash is added to the lock file. * fix(bzlmod): keep the lockfile platform independent when resolving python Fixes #1105 and #1868 for real this time. Implements an additional helper for #1975.
1 parent dac8a5f commit 5eff339

14 files changed

+8771
-613
lines changed

.bazelci/presubmit.yml

+6
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ tasks:
223223
name: "examples/bzlmod: Ubuntu, minimum Bazel"
224224
working_directory: examples/bzlmod
225225
platform: ubuntu2004
226+
build_flags:
227+
- "--lockfile_mode=update"
228+
test_flags:
229+
- "--lockfile_mode=update"
230+
coverage_flags:
231+
- "--lockfile_mode=update"
226232
integration_test_bzlmod_ubuntu:
227233
<<: *reusable_build_test_all
228234
<<: *coverage_targets_example_bzlmod

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ user.bazelrc
5252
# MODULE.bazel.lock is ignored for now as per recommendation from upstream.
5353
# See https://github.com/bazelbuild/bazel/issues/20369
5454
MODULE.bazel.lock
55+
!/examples/bzlmod/MODULE.bazel.lock

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ A brief description of the categories of changes:
2828
* (gazelle): Update error messages when unable to resolve a dependency to be more human-friendly.
2929

3030
### Fixed
31+
* (bzlmod) get the path to the host python interpreter in a way that results in
32+
platform non-dependent hashes in the lock file when the requirement markers need
33+
to be evaluated.
34+
* (bzlmod) correctly watch sources used for evaluating requirement markers for
35+
any changes so that the repository rule or module extensions can be
36+
re-evaluated when the said files change.
3137
* (gazelle): Fix incorrect use of `t.Fatal`/`t.Fatalf` in tests.
3238
* (toolchain) Omit third-party python packages from coverage reports from
3339
stage2 bootstrap template.

docs/BUILD.bazel

+4-64
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@
1313
# limitations under the License.
1414

1515
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
16-
load("@bazel_skylib//rules:write_file.bzl", "write_file")
1716
load("@dev_pip//:requirements.bzl", "requirement")
18-
load("//python:py_binary.bzl", "py_binary")
1917
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility
2018
load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER") # buildifier: disable=bzl-visibility
19+
load("//python/uv/private:lock.bzl", "lock") # buildifier: disable=bzl-visibility
2120
load("//sphinxdocs:readthedocs.bzl", "readthedocs_install")
2221
load("//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs")
2322
load("//sphinxdocs:sphinx_stardoc.bzl", "sphinx_stardoc", "sphinx_stardocs")
@@ -140,71 +139,12 @@ sphinx_build_binary(
140139
],
141140
)
142141

143-
_REQUIREMENTS_TARGET_COMPATIBLE_WITH = select({
144-
"@platforms//os:linux": [],
145-
"@platforms//os:macos": [],
146-
"@platforms//os:windows": [],
147-
"//conditions:default": ["@platforms//:incompatible"],
148-
}) if BZLMOD_ENABLED else ["@platforms//:incompatible"]
149-
150142
# Run bazel run //docs:requirements.update
151-
genrule(
143+
lock(
152144
name = "requirements",
153145
srcs = ["pyproject.toml"],
154-
outs = ["_requirements.txt"],
155-
cmd = "$(UV_BIN) pip compile " + " ".join([
156-
"--custom-compile-command='bazel run //docs:requirements.update'",
157-
"--generate-hashes",
158-
"--universal",
159-
"--emit-index-url",
160-
"--no-strip-extras",
161-
"--no-build",
162-
"--python=$(PYTHON3)",
163-
"$<",
164-
"--output-file=$@",
165-
# Always try upgrading
166-
"--upgrade",
167-
]),
168-
tags = [
169-
"local",
170-
"manual",
171-
"no-cache",
172-
],
173-
target_compatible_with = _REQUIREMENTS_TARGET_COMPATIBLE_WITH,
174-
toolchains = [
175-
"//python/uv:current_toolchain",
176-
"//python:current_py_toolchain",
177-
],
178-
)
179-
180-
# Write a script that can be used for updating the in-tree version of the
181-
# requirements file
182-
write_file(
183-
name = "gen_update_requirements",
184-
out = "requirements.update.py",
185-
content = [
186-
"from os import environ",
187-
"from pathlib import Path",
188-
"from sys import stderr",
189-
"",
190-
'src = Path(environ["REQUIREMENTS_FILE"])',
191-
'dst = Path(environ["BUILD_WORKSPACE_DIRECTORY"]) / "docs" / "requirements.txt"',
192-
'print(f"Writing requirements contents from {src} to {dst}", file=stderr)',
193-
"dst.write_text(src.read_text())",
194-
'print("Success!", file=stderr)',
195-
],
196-
target_compatible_with = _REQUIREMENTS_TARGET_COMPATIBLE_WITH,
197-
)
198-
199-
py_binary(
200-
name = "requirements.update",
201-
srcs = ["requirements.update.py"],
202-
data = [":requirements"],
203-
env = {
204-
"REQUIREMENTS_FILE": "$(location :requirements)",
205-
},
206-
tags = ["manual"],
207-
target_compatible_with = _REQUIREMENTS_TARGET_COMPATIBLE_WITH,
146+
out = "requirements.txt",
147+
upgrade = True,
208148
)
209149

210150
licenses(["notice"]) # Apache 2.0

examples/BUILD.bazel

+10
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,14 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
# The following is experimental API and currently not intended for use outside this example.
16+
load("@rules_python//python/uv/private:lock.bzl", "lock") # buildifier: disable=bzl-visibility
17+
1518
licenses(["notice"]) # Apache 2.0
19+
20+
lock(
21+
name = "bzlmod_requirements_3_9",
22+
srcs = ["bzlmod/requirements.in"],
23+
out = "bzlmod/requirements_lock_3_9.txt",
24+
python_version = "3.9.19",
25+
)

examples/bzlmod/.bazelrc

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
common --enable_bzlmod
22

3+
# Update the lockfile by running:
4+
# bazel mod deps --lockfile_mode=update
5+
common --lockfile_mode=error
6+
37
coverage --java_runtime_version=remotejdk_11
48

59
test --test_output=errors --enable_runfiles

examples/bzlmod/BUILD.bazel

+1-11
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,10 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test")
99
load("@pip//:requirements.bzl", "all_data_requirements", "all_requirements", "all_whl_requirements", "requirement")
1010
load("@python_3_9//:defs.bzl", py_test_with_transition = "py_test")
1111
load("@python_versions//3.10:defs.bzl", compile_pip_requirements_3_10 = "compile_pip_requirements")
12-
load("@python_versions//3.9:defs.bzl", compile_pip_requirements_3_9 = "compile_pip_requirements")
1312
load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
1413

1514
# This stanza calls a rule that generates targets for managing pip dependencies
16-
# with pip-compile.
17-
compile_pip_requirements_3_9(
18-
name = "requirements_3_9",
19-
src = "requirements.in",
20-
requirements_txt = "requirements_lock_3_9.txt",
21-
requirements_windows = "requirements_windows_3_9.txt",
22-
)
23-
24-
# This stanza calls a rule that generates targets for managing pip dependencies
25-
# with pip-compile.
15+
# with pip-compile for a particular python version.
2616
compile_pip_requirements_3_10(
2717
name = "requirements_3_10",
2818
timeout = "moderate",

examples/bzlmod/MODULE.bazel

+12-13
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,7 @@ pip.parse(
135135
],
136136
hub_name = "pip",
137137
python_version = "3.9",
138-
# The requirements files for each platform that we want to support.
139-
requirements_by_platform = {
140-
# Default requirements file for needs to explicitly provide the platforms
141-
"//:requirements_lock_3_9.txt": "linux_*,osx_*",
142-
# This API allows one to specify additional platforms that the users
143-
# configure the toolchains for themselves. In this example we add
144-
# `windows_aarch64` to illustrate that `rules_python` won't fail to
145-
# process the value, but it does not mean that this example will work
146-
# on Windows ARM.
147-
"//:requirements_windows_3_9.txt": "windows_x86_64,windows_aarch64",
148-
},
138+
requirements_lock = "requirements_lock_3_9.txt",
149139
# These modifications were created above and we
150140
# are providing pip.parse with the label of the mod
151141
# and the name of the wheel.
@@ -179,8 +169,17 @@ pip.parse(
179169
],
180170
hub_name = "pip",
181171
python_version = "3.10",
182-
requirements_lock = "//:requirements_lock_3_10.txt",
183-
requirements_windows = "//:requirements_windows_3_10.txt",
172+
# The requirements files for each platform that we want to support.
173+
requirements_by_platform = {
174+
# Default requirements file for needs to explicitly provide the platforms
175+
"//:requirements_lock_3_10.txt": "linux_*,osx_*",
176+
# This API allows one to specify additional platforms that the users
177+
# configure the toolchains for themselves. In this example we add
178+
# `windows_aarch64` to illustrate that `rules_python` won't fail to
179+
# process the value, but it does not mean that this example will work
180+
# on Windows ARM.
181+
"//:requirements_windows_3_10.txt": "windows_x86_64,windows_aarch64",
182+
},
184183
# These modifications were created above and we
185184
# are providing pip.parse with the label of the mod
186185
# and the name of the wheel.

0 commit comments

Comments
 (0)