Skip to content

Commit 4079953

Browse files
authored
feat(binary/test): add interpreter_args attribute (#2669)
Today, there's way to control what startup args are used for the interpreter. To fix, add an `interpreter_args` attribute. These are written into the bootstrap. This is only implemented for the bootstrap=script method Fixes #2668
1 parent 20ac9bc commit 4079953

File tree

5 files changed

+61
-0
lines changed

5 files changed

+61
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ Unreleased changes template.
9494
* (rules) APIs for creating custom rules based on the core py_binary, py_test,
9595
and py_library rules
9696
([#1647](https://github.com/bazelbuild/rules_python/issues/1647))
97+
* (rules) Added {obj}`interpreter_args` attribute to `py_binary` and `py_test`,
98+
which allows pass arguments to the interpreter before the regular args.
9799

98100
{#v0-0-0-removed}
99101
### Removed

python/private/py_executable.bzl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ EXECUTABLE_ATTRS = dicts.add(
8787
IMPORTS_ATTRS,
8888
COVERAGE_ATTRS,
8989
{
90+
"interpreter_args": lambda: attrb.StringList(
91+
doc = """
92+
Arguments that are only applicable to the interpreter.
93+
94+
The args an interpreter supports are specific to the interpreter. For
95+
CPython, see https://docs.python.org/3/using/cmdline.html.
96+
97+
:::{note}
98+
Only supported for {obj}`--bootstrap_impl=script`. Ignored otherwise.
99+
:::
100+
101+
:::{versionadded} VERSION_NEXT_FEATURE
102+
:::
103+
""",
104+
),
90105
"legacy_create_init": lambda: attrb.Int(
91106
default = -1,
92107
values = [-1, 0, 1],
@@ -658,6 +673,10 @@ def _create_stage1_bootstrap(
658673
python_binary_actual = venv.interpreter_actual_path if venv else ""
659674

660675
subs = {
676+
"%interpreter_args%": "\n".join([
677+
'"{}"'.format(v)
678+
for v in ctx.attr.interpreter_args
679+
]),
661680
"%is_zipfile%": "1" if is_for_zip else "0",
662681
"%python_binary%": python_binary_path,
663682
"%python_binary_actual%": python_binary_actual,

python/private/stage1_bootstrap_template.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ IS_ZIPFILE="%is_zipfile%"
2121
# 0 or 1
2222
RECREATE_VENV_AT_RUNTIME="%recreate_venv_at_runtime%"
2323

24+
# array of strings
25+
declare -a INTERPRETER_ARGS_FROM_TARGET=(
26+
%interpreter_args%
27+
)
28+
2429
if [[ "$IS_ZIPFILE" == "1" ]]; then
2530
# NOTE: Macs have an old version of mktemp, so we must use only the
2631
# minimal functionality of it.
@@ -222,6 +227,7 @@ command=(
222227
"${interpreter_env[@]}"
223228
"$python_exe"
224229
"${interpreter_args[@]}"
230+
"${INTERPRETER_ARGS_FROM_TARGET[@]}"
225231
"$stage2_bootstrap"
226232
"$@"
227233
)

tests/bootstrap_impls/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,13 @@ sh_py_run_test(
124124
target_compatible_with = SUPPORTS_BOOTSTRAP_SCRIPT,
125125
)
126126

127+
py_reconfig_test(
128+
name = "interpreter_args_test",
129+
srcs = ["interpreter_args_test.py"],
130+
bootstrap_impl = "script",
131+
interpreter_args = ["-XSPECIAL=1"],
132+
main = "interpreter_args_test.py",
133+
target_compatible_with = SUPPORTS_BOOTSTRAP_SCRIPT,
134+
)
135+
127136
relative_path_test_suite(name = "relative_path_tests")
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2025 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import sys
16+
import unittest
17+
18+
19+
class InterpreterArgsTest(unittest.TestCase):
20+
def test_interpreter_args(self):
21+
self.assertEqual(sys._xoptions, {"SPECIAL": "1"})
22+
23+
24+
if __name__ == "__main__":
25+
unittest.main()

0 commit comments

Comments
 (0)