8000 feat: use rules_python implemented py_runtime, py_runtime_pair, PyRun… · kshramt/rules_python@69abe80 · GitHub
[go: up one dir, main page]

Skip to content

Commit 69abe80

Browse files
authored
feat: use rules_python implemented py_runtime, py_runtime_pair, PyRuntimeInfo (bazel-contrib#1574)
This switches over to using the rules_python implementation of `py_runtime`, `py_runtime_pair`, and `PyRuntimeInfo` for Bazel 6 and higher. Bazel 5 lacks features (specifically provider ctors) to allow enabling it on that version. This is possible because the rules don't directly use the PyRuntimeInfo provider (mostly, see below), they only care about the structure of it as exposed from the ToolchainInfo provider. Switching the toolchain providers and rules over early allows some development of the toolchain prior to Bazel 7 and the rest of the rules_python Starlark implementation being enabled. The builtin PyRuntimeInfo is still returned and accepted for two reasons: * Better compatibility with the builtin rules to make transitioning easier * `py_binary` has an old, possibly defunct (not sure) code path that will look up the the PyRuntimeInfo from a flag/implicit attribute.
1 parent f676656 commit 69abe80

File tree

14 files changed

+214
-85
lines changed

14 files changed

+214
-85
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ A brief description of the categories of changes:
1919

2020
## Unreleased
2121

22+
### Changed
23+
24+
* (toolchains) `py_runtime`, `py_runtime_pair`, and `PyRuntimeInfo` now use the
25+
rules_python Starlark implementation, not the one built into Bazel. NOTE: This
26+
only applies to Bazel 6+; Bazel 5 still uses the builtin implementation.
27+
2228
[0.XX.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.XX.0
2329

2430
## [0.27.0] - 2023-11-16

python/BUILD.bazel

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ bzl_library(
157157
deps = [
158158
"//python/private:util_bzl",
159159
"//python/private/common:py_runtime_macro_bzl",
160-
"@rules_python_internal//:rules_python_config_bzl",
161160
],
162161
)
163162

@@ -167,7 +166,7 @@ bzl_library(
167166
deps = [
168167
"//python/private:bazel_tools_bzl",
169168
"//python/private:py_runtime_pair_macro_bzl",
170-
"@rules_python_internal//:rules_python_config_bzl",
169+
"//python/private:util_bzl",
171170
],
172171
)
173172

@@ -176,8 +175,8 @@ bzl_library(
176175
srcs = ["py_runtime_info.bzl"],
177176
deps = [
178177
"//python/private:reexports_bzl",
178+
"//python/private:util_bzl",
179179
"//python/private/common:providers_bzl",
180-
"@rules_python_internal//:rules_python_config_bzl",
181180
],
182181
)
183182

python/private/common/BUILD.bazel

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ bzl_library(
7474
srcs = ["providers.bzl"],
7575
deps = [
7676
":semantics_bzl",
77-
"@rules_python_internal//:rules_python_config_bzl",
77+
"//python/private:util_bzl",
7878
],
7979
)
8080

@@ -171,9 +171,10 @@ bzl_library(
171171
srcs = ["py_runtime_rule.bzl"],
172172
deps = [
173173
":attributes_bzl",
174-
":common_bzl",
175174
":providers_bzl",
176175
":py_internal_bzl",
176+
"//python/private:reexports_bzl",
177+
"//python/private:util_bzl",
177178
"@bazel_skylib//lib:dicts",
178179
"@bazel_skylib//lib:paths",
179180
],

python/private/common/providers.bzl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
# limitations under the License.
1414
"""Providers for Python rules."""
1515

16-
load("@rules_python_internal//:rules_python_config.bzl", "config")
16+
load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER")
1717

1818
# TODO: load CcInfo from rules_cc
1919
_CcInfo = CcInfo
2020

2121
DEFAULT_STUB_SHEBANG = "#!/usr/bin/env python3"
2222

23-
DEFAULT_BOOTSTRAP_TEMPLATE = "@bazel_tools//tools/python:python_bootstrap_template.txt"
23+
DEFAULT_BOOTSTRAP_TEMPLATE = Label("//python/private:python_bootstrap_template.txt")
24+
2425
_PYTHON_VERSION_VALUES = ["PY2", "PY3"]
2526

2627
# Helper to make the provider definitions not crash under Bazel 5.4:
@@ -31,7 +32,7 @@ _PYTHON_VERSION_VALUES = ["PY2", "PY3"]
3132
# This isn't actually used under Bazel 5.4, so just stub out the values
3233
# to get past the loading phase.
3334
def _define_provider(doc, fields, **kwargs):
34-
if not config.enable_pystar:
35+
if not IS_BAZEL_6_OR_HIGHER:
3536
return provider("Stub, not used", fields = []), None
3637
return provider(doc = doc, fields = fields, **kwargs)
3738

python/private/common/py_runtime_rule.bzl

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@
1515

1616
load("@bazel_skylib//lib:dicts.bzl", "dicts")
1717
load("@bazel_skylib//lib:paths.bzl", "paths")
18+
load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo")
19+
load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER")
1820
load(":attributes.bzl", "NATIVE_RULES_ALLOWLIST_ATTRS")
19-
load(":common.bzl", "check_native_allowed")
20-
load(":providers.bzl", "DEFAULT_BOOTSTRAP_TEMPLATE", "DEFAULT_STUB_SHEBANG", _PyRuntimeInfo = "PyRuntimeInfo")
21+
load(":providers.bzl", "DEFAULT_BOOTSTRAP_TEMPLATE", "DEFAULT_STUB_SHEBANG", "PyRuntimeInfo")
2122
load(":py_internal.bzl", "py_internal")
2223

2324
_py_builtins = py_internal
2425

2526
def _py_runtime_impl(ctx):
26-
check_native_allowed(ctx)
2727
interpreter_path = ctx.attr.interpreter_path or None # Convert empty string to None
2828
interpreter = ctx.file.interpreter
2929
if (interpreter_path and interpreter) or (not interpreter_path and not interpreter):
@@ -44,7 +44,7 @@ def _py_runtime_impl(ctx):
4444
if ctx.attr.coverage_tool:
4545
coverage_di = ctx.attr.coverage_tool[DefaultInfo]
4646

47-
if _py_builtins.is_singleton_depset(coverage_di.files):
47+
if _is_singleton_depset(coverage_di.files):
4848
coverage_tool = coverage_di.files.to_list()[0]
4949
elif coverage_di.files_to_run and coverage_di.files_to_run.executable:
5050
coverage_tool = coverage_di.files_to_run.executable
@@ -60,39 +60,45 @@ def _py_runtime_impl(ctx):
6060
coverage_files = None
6161

6262
python_version = ctx.attr.python_version
63-
if python_version == "_INTERNAL_SENTINEL":
64-
if ctx.fragments.py.use_toolchains:
65-
fail(
66-
"When using Python toolchains, this attribute must be set explicitly to either 'PY2' " +
67-
"or 'PY3'. See https://github.com/bazelbuild/bazel/issues/7899 for more " +
68-
"information. You can temporarily avoid this error by reverting to the legacy " +
69-
"Python runtime mechanism (`--incompatible_use_python_toolchains=false`).",
70-
)
71-
else:
72-
python_version = ctx.fragments.py.default_python_version
7363

7464
# TODO: Uncomment this after --incompatible_python_disable_py2 defaults to true
7565
# if ctx.fragments.py.disable_py2 and python_version == "PY2":
7666
# fail("Using Python 2 is not supported and disabled; see " +
7767
# "https://github.com/bazelbuild/bazel/issues/15684")
7868

69+
py_runtime_info_kwargs = dict(
70+
interpreter_path = interpreter_path or None,
71+
interpreter = interpreter,
72+
files = runtime_files if hermetic else None,
73+
coverage_tool = coverage_tool,
74+
coverage_files = coverage_files,
75+
python_version = python_version,
76+
stub_shebang = ctx.attr.stub_shebang,
77+
bootstrap_template = ctx.file.bootstrap_template,
78+
)
79+
builtin_py_runtime_info_kwargs = dict(py_runtime_info_kwargs)
80+
if not IS_BAZEL_7_OR_HIGHER:
81+
builtin_py_runtime_info_kwargs.pop("bootstrap_template")
7982
return [
80-
_PyRuntimeInfo(
81-
interpreter_path = interpreter_path or None,
82-
interpreter = interpreter,
83-
files = runtime_files if hermetic else None,
84-
coverage_tool = coverage_tool,
85-
coverage_files = coverage_files,
86-
python_version = python_version,
87-
stub_shebang = ctx.attr.stub_shebang,
88-
bootstrap_template = ctx.file.bootstrap_template,
89-
),
83+
PyRuntimeInfo(**py_runtime_info_kwargs),
84+
# Return the builtin provider for better compatibility.
85+
# 1. There is a legacy code path in py_binary that
86+
# checks for the provider when toolchains aren't used
87+
# 2. It makes it easier to transition from builtins to rules_python
88+
BuiltinPyRuntimeInfo(**builtin_py_runtime_info_kwargs),
9089
DefaultInfo(
9190
files = runtime_files,
9291
runfiles = ctx.runfiles(),
9392
),
9493
]
9594

95+
def _is_singleton_depset(files):
96+
# Bazel 6 doesn't have this helper to optimize detecting singleton depsets.
97+
if _py_builtins:
98+
return _py_builtins.is_singleton_depset(files)
99+
else:
100+
return len(files.to_list()) == 1
101+
96102
# Bind to the name "py_runtime" to preserve the kind/rule_class it shows up
97103
# as elsewhere.
98104
py_runtime = rule(
@@ -189,8 +195,8 @@ For a platform runtime, this is the absolute path of a Python interpreter on
189195
the target platform. For an in-build runtime this attribute must not be set.
190196
"""),
191197
"python_version": attr.string(
192-
default = "_INTERNAL_SENTINEL",
193-
values = ["PY2", "PY3", "_INTERNAL_SENTINEL"],
198+
default = "PY3",
199+
values = ["PY2", "PY3"],
194200
doc = """
195201
Whether this runtime is for Python major version 2 or 3. Valid values are `"PY2"`
196202
and `"PY3"`.

python/private/py_runtime_pair_rule.bzl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,19 @@
1515
"""Implementation of py_runtime_pair."""
1616

1717
load("//python:py_runtime_info.bzl", "PyRuntimeInfo")
18+
load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo")
1819

1920
def _py_runtime_pair_impl(ctx):
2021
if ctx.attr.py2_runtime != None:
21-
py2_runtime = ctx.attr.py2_runtime[PyRuntimeInfo]
22+
py2_runtime = _get_py_runtime_info(ctx.attr.py2_runtime)
2223
if py2_runtime.python_version != "PY2":
2324
fail("The Python runtime in the 'py2_runtime' attribute did not have " +
2425
"version 'PY2'")
2526
else:
2627
py2_runtime = None
2728

2829
if ctx.attr.py3_runtime != None:
29-
py3_runtime = ctx.attr.py3_runtime[PyRuntimeInfo]
30+
py3_runtime = _get_py_runtime_info(ctx.attr.py3_runtime)
3031
if py3_runtime.python_version != "PY3":
3132
fail("The Python runtime in the 'py3_runtime' attribute did not have " +
3233
"version 'PY3'")
@@ -43,6 +44,12 @@ def _py_runtime_pair_impl(ctx):
4344
py3_runtime = py3_runtime,
4445
)]
4546

47+
def _get_py_runtime_info(target):
48+
if PyRuntimeInfo in target:
49+
return target[PyRuntimeInfo]
50+
else:
51+
return target[BuiltinPyRuntimeInfo]
52+
4653
# buildifier: disable=unused-variable
4754
def _is_py2_disabled(ctx):
4855
# Because this file isn't bundled with Bazel, so we have to conditionally
@@ -58,15 +65,15 @@ py_runtime_pair = rule(
5865
# The two runtimes are used by the py_binary at runtime, and so need to
5966
# be built for the target platform.
6067
"py2_runtime": attr.label(
61-
providers = [PyRuntimeInfo],
68+
providers = [[PyRuntimeInfo], [BuiltinPyRuntimeInfo]],
6269
cfg = "target",
6370
doc = """\
6471
The runtime to use for Python 2 targets. Must have `python_version` set to
6572
`PY2`.
6673
""",
6774
),
6875
"py3_runtime": attr.label(
69-
providers = [PyRuntimeInfo],
76+
providers = [[PyRuntimeInfo], [BuiltinPyRuntimeInfo]],
7077
cfg = "target",
7178
doc = """\
7279
The runtime to use for Python 3 targets. Must have `python_version` set to

python/private/reexports.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ different name. Then we can load it from elsewhere.
3737
BuiltinPyInfo = PyInfo
3838

3939
# buildifier: disable=name-conventions
40-
internal_PyRuntimeInfo = PyRuntimeInfo
40+
BuiltinPyRuntimeInfo = PyRuntimeInfo

python/private/util.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,9 @@ def add_tag(attrs, tag):
8383
attrs["tags"] = tags + [tag]
8484
else:
8585
attrs["tags"] = [tag]
86+
87+
IS_BAZEL_7_OR_HIGHER = hasattr(native, "starlark_doc_extract")
88+
89+
# Bazel 5.4 has a bug where every access of testing.ExecutionInfo is a
90+
# different object that isn't equal to any other. This is fixed in bazel 6+.
91+
IS_BAZEL_6_OR_HIGHER = testing.ExecutionInfo == testing.ExecutionInfo

python/py_runtime.bzl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@
1414

1515
"""Public entry point for py_runtime."""
1616

17-
load("@rules_python_internal//:rules_python_config.bzl", "config")
18-
load("//python/private:util.bzl", "add_migration_tag")
17+
load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER", "add_migration_tag")
1918
load("//python/private/common:py_runtime_macro.bzl", _starlark_py_runtime = "py_runtime")
2019

2120
# buildifier: disable=native-python
22-
_py_runtime_impl = _starlark_py_runtime if config.enable_pystar else native.py_runtime
21+
_py_runtime_impl = _starlark_py_runtime if IS_BAZEL_6_OR_HIGHER else native.py_runtime
2322

2423
def py_runtime(**attrs):
2524
"""See the Bazel core [py_runtime](https://docs.bazel.build/versions/master/be/python.html#py_runtime) documentation.

python/py_runtime_info.bzl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414

1515
"""Public entry point for PyRuntimeInfo."""
1616

17-
load("@rules_python_internal//:rules_python_config.bzl", "config")
18-
load("//python/private:reexports.bzl", "internal_PyRuntimeInfo")
17+
load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo")
18+
load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER")
1919
load("//python/private/common:providers.bzl", _starlark_PyRuntimeInfo = "PyRuntimeInfo")
2020

21-
PyRuntimeInfo = _starlark_PyRuntimeInfo if config.enable_pystar else internal_PyRuntimeInfo
21+
PyRuntimeInfo = _starlark_PyRuntimeInfo if IS_BAZEL_6_OR_HIGHER else BuiltinPyRuntimeInfo

0 commit comments

Comments
 (0)
0