Skip to content

Commit 4fe0db3

Browse files
authored
feat(toolchain, pip.parse): introduce a new '_host' toolchain repo (#1644)
This is for passing it in repository_rules and relies on the canonical label representation introduced in bazel 6.0 and symlink support (needs to be present on Windows) to work. This allows the users to not need to `load` the interpreter label from a `.bzl` file but instead specify the label in the form of `@<mytoolchainrepo>_host//:python`. In order to make it work robustly on Windows, we do `repository_ctx.path(python_interpreter_label).realpath` to get the actual path of the Python interpreter on both, bzlmod and non-bzlmod setups on Windows within the `whl_library` repository rule. Work towards #1643.
1 parent 6d0d514 commit 4fe0db3

File tree

13 files changed

+104
-58
lines changed

13 files changed

+104
-58
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,21 @@ A brief description of the categories of changes:
2525

2626
### Fixed
2727

28+
* (bzlmod pip.parse) Use a platform-independent reference to the interpreter
29+
pip uses. This reduces (but doesn't eliminate) the amount of
30+
platform-specific content in `MODULE.bazel.lock` files; Follow
31+
[#1643](https://github.com/bazelbuild/rules_python/issues/1643) for removing
32+
platform-specific content in `MODULE.bazel.lock` files.
33+
2834
### Added
2935

36+
* (toolchains) `python_register_toolchains` now also generates a repository
37+
that is suffixed with `_host`, that has a single label `:python` that is a
38+
symlink to the python interpreter for the host platform. The intended use is
39+
mainly in `repository_rule`, which are always run using `host` platform
40+
Python. This means that `WORKSPACE` users can now copy the `requirements.bzl`
41+
file for vendoring as seen in the updated `pip_parse_vendored` example.
42+
3043
## [0.28.0] - 2024-01-07
3144

3245
[0.28.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.28.0

examples/build_file_generation/WORKSPACE

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ python_register_toolchains(
8484
python_version = "3.9",
8585
)
8686

87-
# Load the interpreter and pip_parse rules.
88-
load("@python39//:defs.bzl", "interpreter")
8987
load("@rules_python//python:pip.bzl", "pip_parse")
9088

9189
# This macro wraps the `pip_repository` rule that invokes `pip`, with `incremental` set.
@@ -114,7 +112,7 @@ pip_parse(
114112
# 3. Wrapper script, like in the autodetecting python toolchain.
115113
#
116114
# Here, we use the interpreter constant that resolves to the host interpreter from the default Python toolchain.
117-
python_interpreter_target = interpreter,
115+
python_interpreter_target = "@python39_host//:python",
118116
# Set the location of the lock file.
119117
requirements_lock = "//:requirements_lock.txt",
120118
requirements_windows = "//:requirements_windows.txt",

examples/multi_python_versions/WORKSPACE

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,15 @@ python_register_multi_toolchains(
2828
)
2929

3030
load("@python//:pip.bzl", "multi_pip_parse")
31-
load("@python//3.10:defs.bzl", interpreter_3_10 = "interpreter")
32-
load("@python//3.11:defs.bzl", interpreter_3_11 = "interpreter")
33-
load("@python//3.8:defs.bzl", interpreter_3_8 = "interpreter")
34-
load("@python//3.9:defs.bzl", interpreter_3_9 = "interpreter")
3531

3632
multi_pip_parse(
3733
name = "pypi",
3834
default_version = default_python_version,
3935
python_interpreter_target = {
40-
"3.10": interpreter_3_10,
41-
"3.11": interpreter_3_11,
42-
"3.8": interpreter_3_8,
43-
"3.9": interpreter_3_9,
36+
"3.10": "@python_3_10_host//:python",
37+
"3.11": "@python_3_11_host//:python",
38+
"3.8": "@python_3_8_host//:python",
39+
"3.9": "@python_3_9_host//:python",
4440
},
4541
requirements_lock = {
4642
"3.10": "//requirements:requirements_lock_3_10.txt",

examples/pip_parse/WORKSPACE

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ python_register_toolchains(
1414
python_version = "3.9",
1515
)
1616

17-
load("@python39//:defs.bzl", "interpreter")
1817
load("@rules_python//python:pip.bzl", "pip_parse")
1918

2019
pip_parse(
@@ -52,7 +51,7 @@ pip_parse(
5251
# 3. Wrapper script, like in the autodetecting python toolchain.
5352
#
5453
# Here, we use the interpreter constant that resolves to the host interpreter from the default Python toolchain.
55-
python_interpreter_target = interpreter,
54+
python_interpreter_target = "@python39_host//:python",
5655

5756
# (Optional) You can set quiet to False if you want to see pip output.
5857
#quiet = False,

examples/pip_parse_vendored/BUILD.bazel

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,6 @@ compile_pip_requirements(
99
src = "requirements.in",
1010
)
1111

12-
# The requirements.bzl file is generated with a reference to the interpreter for the host platform.
13-
# In order to check in a platform-agnostic file, we have to replace that reference with the symbol
14-
# loaded from our python toolchain.
15-
genrule(
16-
name = "make_platform_agnostic",
17-
srcs = ["@pip//:requirements.bzl"],
18-
outs = ["requirements.clean.bzl"],
19-
cmd = " | ".join([
20-
"cat $<",
21-
# Insert our load statement after the existing one so we don't produce a file with buildifier warnings
22-
"""sed -e '/^load.*.pip.bzl/i\\'$$'\\n''load("@python39//:defs.bzl", "interpreter")'""",
23-
# Replace the bazel 6.0.0 specific comment with something that bazel 5.4.0 would produce.
24-
# This enables this example to be run as a test under bazel 5.4.0.
25-
"""sed -e 's#@//#//#'""",
26-
"""sed 's#"@python39_.*//:bin/python3"#interpreter#' >$@""",
27-
]),
28-
)
29-
3012
write_file(
3113
name = "gen_update",
3214
out = "update.sh",
@@ -35,14 +17,14 @@ write_file(
3517
"#!/usr/bin/env bash",
3618
# Bazel gives us a way to access the source folder!
3719
"cd $BUILD_WORKSPACE_DIRECTORY",
38-
"cp -fv bazel-bin/requirements.clean.bzl requirements.bzl",
20+
"cp -fv bazel-pip_parse_vendored/external/pip/requirements.bzl requirements.bzl",
3921
],
4022
)
4123

4224
sh_binary(
4325
name = "vendor_requirements",
4426
srcs = ["update.sh"],
45-
data = [":make_platform_agnostic"],
27+
data = ["@pip//:requirements.bzl"],
4628
)
4729

4830
# Similarly ensures that the requirements.bzl file is updated
@@ -51,5 +33,5 @@ diff_test(
5133
name = "test_vendored",
5234
failure_message = "Please run: bazel run //:vendor_requirements",
5335
file1 = "requirements.bzl",
54-
file2 = ":make_platform_agnostic",
36+
file2 = "@pip//:requirements.bzl",
5537
)

examples/pip_parse_vendored/WORKSPACE

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@ python_register_toolchains(
1414
python_version = "3.9",
1515
)
1616

17-
load("@python39//:defs.bzl", "interpreter")
1817
load("@rules_python//python:pip.bzl", "pip_parse")
1918

2019
# This repository isn't referenced, except by our test that asserts the requirements.bzl is updated.
2120
# It also wouldn't be needed by users of this ruleset.
2221
pip_parse(
2322
name = "pip",
24-
python_interpreter_target = interpreter,
23+
python_interpreter_target = "@python39_host//:python",
2524
requirements_lock = "//:requirements.txt",
2625
)
2726

examples/pip_parse_vendored/requirements.bzl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"""Starlark representation of locked requirements.
22
33
@generated by rules_python pip_parse repository rule
4-
from //:requirements.txt
4+
from @//:requirements.txt
55
"""
66

7-
load("@python39//:defs.bzl", "interpreter")
87
load("@rules_python//python:pip.bzl", "pip_utils")
98
load("@rules_python//python/pip_install:pip_repository.bzl", "group_library", "whl_library")
109

@@ -17,7 +16,7 @@ all_whl_requirements = all_whl_requirements_by_package.values()
1716
all_data_requirements = ["@pip//certifi:data", "@pip//charset_normalizer:data", "@pip//idna:data", "@pip//requests:data", "@pip//urllib3:data"]
1817

1918
_packages = [("pip_certifi", "certifi==2023.7.22 --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"), ("pip_charset_normalizer", "charset-normalizer==2.1.1 --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"), ("pip_idna", "idna==3.4 --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"), ("pip_requests", "requests==2.28.1 --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"), ("pip_urllib3", "urllib3==1.26.13 --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8")]
20-
_config = {"download_only": False, "enable_implicit_namespace_pkgs": False, "environment": {}, "extra_pip_args": [], "isolated": True, "pip_data_exclude": [], "python_interpreter": "python3", "python_interpreter_target": interpreter, "quiet": True, "repo": "pip", "repo_prefix": "pip_", "timeout": 600}
19+
_config = {"download_only": False, "enable_implicit_namespace_pkgs": False, "environment": {}, "extra_pip_args": [], "isolated": True, "pip_data_exclude": [], "python_interpreter": "python3", "python_interpreter_target": "@python39_host//:python", "quiet": True, "repo": "pip", "repo_prefix": "pip_", "timeout": 600}
2120
_annotations = {}
2221

2322
def requirement(name):

examples/pip_repository_annotations/WORKSPACE

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ python_register_toolchains(
1414
python_version = "3.9",
1515
)
1616

17-
load("@python39//:defs.bzl", "interpreter")
1817
load("@rules_python//python:pip.bzl", "package_annotation", "pip_parse")
1918

2019
# Here we can see an example of annotations being applied to an arbitrary
@@ -54,7 +53,7 @@ write_file(
5453
pip_parse(
5554
name = "pip",
5655
annotations = ANNOTATIONS,
57-
python_interpreter_target = interpreter,
56+
python_interpreter_target = "@python39_host//:python",
5857
requirements_lock = "//:requirements.txt",
5958
)
6059

python/pip_install/pip_repository.bzl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ load("//python/pip_install:requirements_parser.bzl", parse_requirements = "parse
2222
load("//python/pip_install/private:generate_group_library_build_bazel.bzl", "generate_group_library_build_bazel")
2323
load("//python/pip_install/private:generate_whl_library_build_bazel.bzl", "generate_whl_library_build_bazel")
2424
load("//python/pip_install/private:srcs.bzl", "PIP_INSTALL_PY_SRCS")
25-
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
2625
load("//python/private:normalize_name.bzl", "normalize_name")
2726
load("//python/private:parse_whl_name.bzl", "parse_whl_name")
2827
load("//python/private:patch_whl.bzl", "patch_whl")
@@ -87,13 +86,12 @@ def _resolve_python_interpreter(rctx):
8786
if rctx.attr.python_interpreter_target != None:
8887
python_interpreter = rctx.path(rctx.attr.python_interpreter_target)
8988

90-
if BZLMOD_ENABLED:
91-
(os, _) = get_host_os_arch(rctx)
89+
(os, _) = get_host_os_arch(rctx)
9290

93-
# On Windows, the symlink doesn't work because Windows attempts to find
94-
# Python DLLs where the symlink is, not where the symlink points.
95-
if os == WINDOWS_NAME:
96-
python_interpreter = python_interpreter.realpath
91+
# On Windows, the symlink doesn't work because Windows attempts to find
92+
# Python DLLs where the symlink is, not where the symlink points.
93+
if os == WINDOWS_NAME:
94+
python_interpreter = python_interpreter.realpath
9795
elif "/" not in python_interpreter:
9896
# It's a plain command, e.g. "python3", to look up in the environment.
9997
found_python_interpreter = rctx.which(python_interpreter)

python/private/bzlmod/pip.bzl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides):
8787
# we programmatically find it.
8888
hub_name = pip_attr.hub_name
8989
if python_interpreter_target == None and not pip_attr.python_interpreter:
90-
python_name = "python_" + version_label(pip_attr.python_version, sep = "_")
91-
if python_name not in INTERPRETER_LABELS.keys():
90+
python_name = "python_{}_host".format(
91+
version_label(pip_attr.python_version, sep = "_"),
92+
)
93+
if python_name not in INTERPRETER_LABELS:
9294
fail((
9395
"Unable to find interpreter for pip hub '{hub_name}' for " +
9496
"python_version={version}: Make sure a corresponding " +

0 commit comments

Comments
 (0)