From c027306c74f2db11fcfc5985db38198f032b1125 Mon Sep 17 00:00:00 2001 From: Thomas Desrosiers <681004+thomasdesr@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:18:10 -0800 Subject: [PATCH 1/6] fix: handle unsubstituted template placeholders for external native py_binary Problem: In rules_python 1.7.0, PR #3334 ("build: Starlarkify python flags") introduced new template placeholders in the bootstrap scripts: %stage2_bootstrap% and %interpreter_args%. These placeholders are expected to be substituted by rules_python's Starlark code when building py_binary targets. However, when external repositories (like gRPC's cython) define py_binary using the native rule, these placeholders are NOT substituted. In Bazel 7+, native py_binary is implemented by rules_python, but native py_binary doesn't expose attributes like `interpreter_args` that the substitution logic expects. The result is that literal placeholder text ends up in the generated bootstrap scripts, causing Python SyntaxError or file-not-found errors at runtime: File ".../cython_binary", line 39 %interpreter_args% ^ SyntaxError: invalid syntax Fix: Use a sentinel detection pattern directly in the templates. The key insight is that by splitting the sentinel string (e.g., "%stage2" + "_bootstrap%"), the substitution logic won't replace it since it looks for the exact contiguous string. At runtime, the concatenation produces the original placeholder text, which we compare against to detect if substitution occurred. For %stage2_bootstrap%, we fall back to %main% which IS substituted even for native py_binary. For %interpreter_args%, we wrap it in triple-quotes so it's always valid Python syntax, then detect the sentinel and default to an empty list. This is a template-side fix that is backwards compatible and doesn't require changes to Bazel or the substitution logic. Test: Add an integration test that creates an external repository with a native py_binary (exactly like gRPC and other external repos do) and verifies it can be built and executed successfully in WORKSPACE mode. --- .bazelignore | 1 + .bazelrc.deleted_packages | 1 + python/private/python_bootstrap_template.txt | 22 ++++++++++-- python/private/stage1_bootstrap_template.sh | 20 +++++++++++ tests/integration/BUILD.bazel | 6 ++++ .../external_native_py_binary/BUILD.bazel | 13 +++++++ .../external_native_py_binary/WORKSPACE | 35 +++++++++++++++++++ .../external_native_py_binary_test.sh | 17 +++++++++ .../external_repo/main.py | 1 + 9 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 tests/integration/external_native_py_binary/BUILD.bazel create mode 100644 tests/integration/external_native_py_binary/WORKSPACE create mode 100755 tests/integration/external_native_py_binary/external_native_py_binary_test.sh create mode 100644 tests/integration/external_native_py_binary/external_repo/main.py diff --git a/.bazelignore b/.bazelignore index 0384d0746e..913f1e419f 100644 --- a/.bazelignore +++ b/.bazelignore @@ -30,5 +30,6 @@ gazelle/examples/bzlmod_build_file_generation/bazel-bzlmod_build_file_generation gazelle/examples/bzlmod_build_file_generation/bazel-out gazelle/examples/bzlmod_build_file_generation/bazel-testlog tests/integration/compile_pip_requirements/bazel-compile_pip_requirements +tests/integration/external_native_py_binary/bazel-external_native_py_binary tests/integration/local_toolchains/bazel-local_toolchains tests/integration/py_cc_toolchain_registered/bazel-py_cc_toolchain_registered diff --git a/.bazelrc.deleted_packages b/.bazelrc.deleted_packages index d11f96d664..1c597ba4b4 100644 --- a/.bazelrc.deleted_packages +++ b/.bazelrc.deleted_packages @@ -40,6 +40,7 @@ common --deleted_packages=gazelle/python/private common --deleted_packages=tests/integration/compile_pip_requirements common --deleted_packages=tests/integration/compile_pip_requirements_test_from_external_repo common --deleted_packages=tests/integration/custom_commands +common --deleted_packages=tests/integration/external_native_py_binary common --deleted_packages=tests/integration/local_toolchains common --deleted_packages=tests/integration/pip_parse common --deleted_packages=tests/integration/pip_parse/empty diff --git a/python/private/python_bootstrap_template.txt b/python/private/python_bootstrap_template.txt index 9717756036..d825932a2c 100644 --- a/python/private/python_bootstrap_template.txt +++ b/python/private/python_bootstrap_template.txt @@ -10,9 +10,18 @@ import sys import os import subprocess import uuid +import ast # runfiles-relative path +_STAGE2_BOOTSTRAP_SENTINEL = "%stage2" + "_bootstrap%" STAGE2_BOOTSTRAP="%stage2_bootstrap%" +if STAGE2_BOOTSTRAP == _STAGE2_BOOTSTRAP_SENTINEL: + _MAIN_SENTINEL = "%main" + "%" + _main = "%main%" + if _main != _MAIN_SENTINEL and _main: + STAGE2_BOOTSTRAP = _main + else: + STAGE2_BOOTSTRAP = "" # runfiles-relative path to venv's python interpreter # Empty string if a venv is not setup. @@ -35,9 +44,16 @@ RECREATE_VENV_AT_RUNTIME="%recreate_venv_at_runtime%" WORKSPACE_NAME = "%workspace_name%" # Target-specific interpreter args. -INTERPRETER_ARGS = [ -%interpreter_args% -] +_INTERPRETER_ARGS_SENTINEL = "%interpreter" + "_args%" +_INTERPRETER_ARGS_RAW = """%interpreter_args%""".strip() +if _INTERPRETER_ARGS_RAW and _INTERPRETER_ARGS_RAW != _INTERPRETER_ARGS_SENTINEL: + INTERPRETER_ARGS = [ + ast.literal_eval(line.strip()) + for line in _INTERPRETER_ARGS_RAW.splitlines() + if line.strip() + ] +else: + INTERPRETER_ARGS = [] ADDITIONAL_INTERPRETER_ARGS = os.environ.get("RULES_PYTHON_ADDITIONAL_INTERPRETER_ARGS", "") diff --git a/python/private/stage1_bootstrap_template.sh b/python/private/stage1_bootstrap_template.sh index a984344647..2ef2b8ca31 100644 --- a/python/private/stage1_bootstrap_template.sh +++ b/python/private/stage1_bootstrap_template.sh @@ -7,7 +7,17 @@ if [[ -n "${RULES_PYTHON_BOOTSTRAP_VERBOSE:-}" ]]; then fi # runfiles-relative path +STAGE2_BOOTSTRAP_SENTINEL="%stage2""_bootstrap%" +MAIN_SENTINEL="%main""%" STAGE2_BOOTSTRAP="%stage2_bootstrap%" +MAIN="%main%" +if [[ "$STAGE2_BOOTSTRAP" == "$STAGE2_BOOTSTRAP_SENTINEL" ]]; then + if [[ "$MAIN" != "$MAIN_SENTINEL" && -n "$MAIN" ]]; then + STAGE2_BOOTSTRAP="$MAIN" + else + STAGE2_BOOTSTRAP="" + fi +fi # runfiles-relative path to python interpreter to use. # This is the `bin/python3` path in the binary's venv. @@ -35,6 +45,16 @@ VENV_REL_SITE_PACKAGES="%venv_rel_site_packages%" declare -a INTERPRETER_ARGS_FROM_TARGET=( %interpreter_args% ) +INTERPRETER_ARGS_SENTINEL="%interpreter""_args%" +if [[ "${#INTERPRETER_ARGS_FROM_TARGET[@]}" -eq 1 && + "${INTERPRETER_ARGS_FROM_TARGET[0]}" == "$INTERPRETER_ARGS_SENTINEL" ]]; then + INTERPRETER_ARGS_FROM_TARGET=() +fi + +if [[ -z "$STAGE2_BOOTSTRAP" ]]; then + echo >&2 "ERROR: %stage2_bootstrap% (or %main%) was not substituted." + exit 1 +fi if [[ "$IS_ZIPFILE" == "1" ]]; then # NOTE: Macs have an old version of mktemp, so we must use only the diff --git a/tests/integration/BUILD.bazel b/tests/integration/BUILD.bazel index f0f58daa3a..a020b07a8b 100644 --- a/tests/integration/BUILD.bazel +++ b/tests/integration/BUILD.bazel @@ -47,6 +47,12 @@ rules_python_integration_test( workspace_path = "compile_pip_requirements", ) +rules_python_integration_test( + name = "external_native_py_binary_workspace_test", + bzlmod = False, + workspace_path = "external_native_py_binary", +) + rules_python_integration_test( name = "local_toolchains_test", env = { diff --git a/tests/integration/external_native_py_binary/BUILD.bazel b/tests/integration/external_native_py_binary/BUILD.bazel new file mode 100644 index 0000000000..4aecf873fb --- /dev/null +++ b/tests/integration/external_native_py_binary/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +sh_test( + name = "external_native_py_binary_test", + srcs = ["external_native_py_binary_test.sh"], + data = [ + "@bazel_tools//tools/bash/runfiles", + "@native_py_binary_repo//:external_native_py_binary", + ], + env = { + "BIN_RLOCATION": "native_py_binary_repo/external_native_py_binary", + }, +) diff --git a/tests/integration/external_native_py_binary/WORKSPACE b/tests/integration/external_native_py_binary/WORKSPACE new file mode 100644 index 0000000000..2683e58bbb --- /dev/null +++ b/tests/integration/external_native_py_binary/WORKSPACE @@ -0,0 +1,35 @@ +workspace(name = "external_native_py_binary") + +load( + "@bazel_tools//tools/build_defs/repo:local.bzl", + "local_repository", + "new_local_repository", +) + +local_repository( + name = "rules_python", + path = "../../..", +) + +load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") + +py_repositories() + +python_register_toolchains( + name = "python_3_11", + python_version = "3.11", +) + +new_local_repository( + name = "native_py_binary_repo", + path = "external_repo", + build_file_content = """ +package(default_visibility = ["//visibility:public"]) + +py_binary( + name = "external_native_py_binary", + srcs = ["main.py"], + main = "main.py", +) +""", +) diff --git a/tests/integration/external_native_py_binary/external_native_py_binary_test.sh b/tests/integration/external_native_py_binary/external_native_py_binary_test.sh new file mode 100755 index 0000000000..d53bb38dc9 --- /dev/null +++ b/tests/integration/external_native_py_binary/external_native_py_binary_test.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +# --- begin runfiles.bash initialization v3 --- +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo >&2 "ERROR: cannot find $f"; exit 1; } +set -euo pipefail +# --- end runfiles.bash initialization v3 --- + +bin=$(rlocation "$BIN_RLOCATION") +output="$("$bin")" +[[ "$output" == "external-native-ok" ]] diff --git a/tests/integration/external_native_py_binary/external_repo/main.py b/tests/integration/external_native_py_binary/external_repo/main.py new file mode 100644 index 0000000000..50b3df29c9 --- /dev/null +++ b/tests/integration/external_native_py_binary/external_repo/main.py @@ -0,0 +1 @@ +print("external-native-ok") From 44b9e8ae86599d5dfe20def9d27f470c68647c9a Mon Sep 17 00:00:00 2001 From: Thomas Desrosiers Date: Mon, 5 Jan 2026 16:49:16 -0800 Subject: [PATCH 2/6] Fix some AI feedback - Add STAGE2_BOOTSTRAP validation to Python template (consistency with shell) - Add comments explaining sentinel pattern in both templates - Restore diagnostic output in test script --- python/private/python_bootstrap_template.txt | 10 ++++++++++ python/private/stage1_bootstrap_template.sh | 6 ++++++ .../external_native_py_binary_test.sh | 5 ++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/python/private/python_bootstrap_template.txt b/python/private/python_bootstrap_template.txt index d825932a2c..06fe8fe62b 100644 --- a/python/private/python_bootstrap_template.txt +++ b/python/private/python_bootstrap_template.txt @@ -13,6 +13,11 @@ import uuid import ast # runfiles-relative path +# NOTE: The sentinel strings are split (e.g., "%stage2" + "_bootstrap%") so that +# the substitution logic won't replace them. This allows runtime detection of +# unsubstituted placeholders, which occurs when native py_binary is used in +# external repositories. In that case, we fall back to %main% which Bazel's +# native rule does substitute. _STAGE2_BOOTSTRAP_SENTINEL = "%stage2" + "_bootstrap%" STAGE2_BOOTSTRAP="%stage2_bootstrap%" if STAGE2_BOOTSTRAP == _STAGE2_BOOTSTRAP_SENTINEL: @@ -23,6 +28,10 @@ if STAGE2_BOOTSTRAP == _STAGE2_BOOTSTRAP_SENTINEL: else: STAGE2_BOOTSTRAP = "" +if not STAGE2_BOOTSTRAP: + print("ERROR: %stage2_bootstrap% (or %main%) was not substituted.", file=sys.stderr) + sys.exit(1) + # runfiles-relative path to venv's python interpreter # Empty string if a venv is not setup. PYTHON_BINARY = '%python_binary%' @@ -44,6 +53,7 @@ RECREATE_VENV_AT_RUNTIME="%recreate_venv_at_runtime%" WORKSPACE_NAME = "%workspace_name%" # Target-specific interpreter args. +# Sentinel split to detect unsubstituted placeholder (see STAGE2_BOOTSTRAP above). _INTERPRETER_ARGS_SENTINEL = "%interpreter" + "_args%" _INTERPRETER_ARGS_RAW = """%interpreter_args%""".strip() if _INTERPRETER_ARGS_RAW and _INTERPRETER_ARGS_RAW != _INTERPRETER_ARGS_SENTINEL: diff --git a/python/private/stage1_bootstrap_template.sh b/python/private/stage1_bootstrap_template.sh index 2ef2b8ca31..cfc6f7e510 100644 --- a/python/private/stage1_bootstrap_template.sh +++ b/python/private/stage1_bootstrap_template.sh @@ -7,6 +7,11 @@ if [[ -n "${RULES_PYTHON_BOOTSTRAP_VERBOSE:-}" ]]; then fi # runfiles-relative path +# NOTE: The sentinel strings are split (e.g., "%stage2""_bootstrap%") so that +# the substitution logic won't replace them. This allows runtime detection of +# unsubstituted placeholders, which occurs when native py_binary is used in +# external repositories. In that case, we fall back to %main% which Bazel's +# native rule does substitute. STAGE2_BOOTSTRAP_SENTINEL="%stage2""_bootstrap%" MAIN_SENTINEL="%main""%" STAGE2_BOOTSTRAP="%stage2_bootstrap%" @@ -45,6 +50,7 @@ VENV_REL_SITE_PACKAGES="%venv_rel_site_packages%" declare -a INTERPRETER_ARGS_FROM_TARGET=( %interpreter_args% ) +# Sentinel split to detect unsubstituted placeholder (see STAGE2_BOOTSTRAP above). INTERPRETER_ARGS_SENTINEL="%interpreter""_args%" if [[ "${#INTERPRETER_ARGS_FROM_TARGET[@]}" -eq 1 && "${INTERPRETER_ARGS_FROM_TARGET[0]}" == "$INTERPRETER_ARGS_SENTINEL" ]]; then diff --git a/tests/integration/external_native_py_binary/external_native_py_binary_test.sh b/tests/integration/external_native_py_binary/external_native_py_binary_test.sh index d53bb38dc9..8cf91745de 100755 --- a/tests/integration/external_native_py_binary/external_native_py_binary_test.sh +++ b/tests/integration/external_native_py_binary/external_native_py_binary_test.sh @@ -14,4 +14,7 @@ set -euo pipefail bin=$(rlocation "$BIN_RLOCATION") output="$("$bin")" -[[ "$output" == "external-native-ok" ]] +if [[ "$output" != "external-native-ok" ]]; then + echo >&2 "Expected 'external-native-ok' but got: $output" + exit 1 +fi From dc68724d8197016121c274df9ceafac7de8635e0 Mon Sep 17 00:00:00 2001 From: Thomas Desrosiers Date: Mon, 5 Jan 2026 16:56:56 -0800 Subject: [PATCH 3/6] Finally got pre-commit working --- .bazelrc.deleted_packages | 2 +- tests/integration/external_native_py_binary/BUILD.bazel | 2 ++ tests/integration/external_native_py_binary/WORKSPACE | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.bazelrc.deleted_packages b/.bazelrc.deleted_packages index 1c597ba4b4..1eae6fbad3 100644 --- a/.bazelrc.deleted_packages +++ b/.bazelrc.deleted_packages @@ -35,8 +35,8 @@ common --deleted_packages=gazelle/manifest/hasher common --deleted_packages=gazelle/manifest/test common --deleted_packages=gazelle/modules_mapping common --deleted_packages=gazelle/python -common --deleted_packages=gazelle/pythonconfig common --deleted_packages=gazelle/python/private +common --deleted_packages=gazelle/pythonconfig common --deleted_packages=tests/integration/compile_pip_requirements common --deleted_packages=tests/integration/compile_pip_requirements_test_from_external_repo common --deleted_packages=tests/integration/custom_commands diff --git a/tests/integration/external_native_py_binary/BUILD.bazel b/tests/integration/external_native_py_binary/BUILD.bazel index 4aecf873fb..a7786f0679 100644 --- a/tests/integration/external_native_py_binary/BUILD.bazel +++ b/tests/integration/external_native_py_binary/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_shell//shell:sh_test.bzl", "sh_test") + package(default_visibility = ["//visibility:public"]) sh_test( diff --git a/tests/integration/external_native_py_binary/WORKSPACE b/tests/integration/external_native_py_binary/WORKSPACE index 2683e58bbb..28e391c497 100644 --- a/tests/integration/external_native_py_binary/WORKSPACE +++ b/tests/integration/external_native_py_binary/WORKSPACE @@ -22,7 +22,6 @@ python_register_toolchains( new_local_repository( name = "native_py_binary_repo", - path = "external_repo", build_file_content = """ package(default_visibility = ["//visibility:public"]) @@ -32,4 +31,5 @@ py_binary( main = "main.py", ) """, + path = "external_repo", ) From a91096d3b34f39e7f84f8a5f084ba54580adbccc Mon Sep 17 00:00:00 2001 From: Thomas Desrosiers Date: Mon, 5 Jan 2026 17:12:44 -0800 Subject: [PATCH 4/6] fix: add rules_shell dependency to integration test WORKSPACE The sh_test requires @rules_shell which isn't provided transitively. Buildifier auto-adds the load statement for rules_shell's sh_test, so we need the dependency in the standalone WORKSPACE. --- tests/integration/external_native_py_binary/BUILD.bazel | 8 ++++---- tests/integration/external_native_py_binary/WORKSPACE | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/integration/external_native_py_binary/BUILD.bazel b/tests/integration/external_native_py_binary/BUILD.bazel index a7786f0679..8e8e9c11c0 100644 --- a/tests/integration/external_native_py_binary/BUILD.bazel +++ b/tests/integration/external_native_py_binary/BUILD.bazel @@ -2,14 +2,14 @@ load("@rules_shell//shell:sh_test.bzl", "sh_test") package(default_visibility = ["//visibility:public"]) +# Test that a native py_binary from an external repo works. +# This exercises the bootstrap template's handling of unsubstituted placeholders. sh_test( name = "external_native_py_binary_test", srcs = ["external_native_py_binary_test.sh"], - data = [ - "@bazel_tools//tools/bash/runfiles", - "@native_py_binary_repo//:external_native_py_binary", - ], + data = ["@native_py_binary_repo//:external_native_py_binary"], env = { "BIN_RLOCATION": "native_py_binary_repo/external_native_py_binary", }, + deps = ["@bazel_tools//tools/bash/runfiles"], ) diff --git a/tests/integration/external_native_py_binary/WORKSPACE b/tests/integration/external_native_py_binary/WORKSPACE index 28e391c497..afd1a082c1 100644 --- a/tests/integration/external_native_py_binary/WORKSPACE +++ b/tests/integration/external_native_py_binary/WORKSPACE @@ -1,11 +1,19 @@ workspace(name = "external_native_py_binary") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load( "@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository", "new_local_repository", ) +http_archive( + name = "rules_shell", + sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043", + strip_prefix = "rules_shell-0.4.0", + url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz", +) + local_repository( name = "rules_python", path = "../../..", From ad6659f214e4b419a7e1ef0ee9b0f3a065d2e08d Mon Sep 17 00:00:00 2001 From: Thomas Desrosiers Date: Mon, 5 Jan 2026 17:46:34 -0800 Subject: [PATCH 5/6] fix: skip external_native_py_binary test on Bazel 9+ Bazel 9 removed native py_binary from the default namespace when using bzlmod, making this test incompatible. Restrict the test to Bazel 7.4.1, 8.0.0, and self (current Bazel) where native rules are still available. --- tests/integration/BUILD.bazel | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/integration/BUILD.bazel b/tests/integration/BUILD.bazel index a020b07a8b..38e3466249 100644 --- a/tests/integration/BUILD.bazel +++ b/tests/integration/BUILD.bazel @@ -49,6 +49,12 @@ rules_python_integration_test( rules_python_integration_test( name = "external_native_py_binary_workspace_test", + # Bazel 9+ removed native py_binary, so this test only works on older versions + bazel_versions = [ + "7.4.1", + "8.0.0", + "self", + ], bzlmod = False, workspace_path = "external_native_py_binary", ) From 3c559ad1c7c9d4b83cec92e8e4b649b093d02971 Mon Sep 17 00:00:00 2001 From: Thomas Desrosiers Date: Mon, 12 Jan 2026 09:32:22 -0800 Subject: [PATCH 6/6] refactor: simplify interpreter_args encoding to newline-delimited values Address review feedback to use simpler encoding for interpreter_args. Instead of encoding as quoted Python strings that require ast.literal_eval to parse, encode as plain newline-delimited values and parse with split(). This removes the ast import and simplifies the bootstrap template logic. --- python/private/py_executable.bzl | 5 +---- python/private/python_bootstrap_template.txt | 14 ++++---------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index 1b884e9b3b..87995a032d 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl @@ -726,10 +726,7 @@ def _create_stage1_bootstrap( resolve_python_binary_at_runtime = "1" subs = { - "%interpreter_args%": "\n".join([ - '"{}"'.format(v) - for v in ctx.attr.interpreter_args - ]), + "%interpreter_args%": "\n".join(ctx.attr.interpreter_args), "%is_zipfile%": "1" if is_for_zip else "0", "%python_binary%": python_binary_path, "%python_binary_actual%": python_binary_actual, diff --git a/python/private/python_bootstrap_template.txt b/python/private/python_bootstrap_template.txt index 06fe8fe62b..fe8f21dc6c 100644 --- a/python/private/python_bootstrap_template.txt +++ b/python/private/python_bootstrap_template.txt @@ -10,8 +10,6 @@ import sys import os import subprocess import uuid -import ast - # runfiles-relative path # NOTE: The sentinel strings are split (e.g., "%stage2" + "_bootstrap%") so that # the substitution logic won't replace them. This allows runtime detection of @@ -55,15 +53,11 @@ WORKSPACE_NAME = "%workspace_name%" # Target-specific interpreter args. # Sentinel split to detect unsubstituted placeholder (see STAGE2_BOOTSTRAP above). _INTERPRETER_ARGS_SENTINEL = "%interpreter" + "_args%" -_INTERPRETER_ARGS_RAW = """%interpreter_args%""".strip() -if _INTERPRETER_ARGS_RAW and _INTERPRETER_ARGS_RAW != _INTERPRETER_ARGS_SENTINEL: - INTERPRETER_ARGS = [ - ast.literal_eval(line.strip()) - for line in _INTERPRETER_ARGS_RAW.splitlines() - if line.strip() - ] -else: +_INTERPRETER_ARGS_RAW = "%interpreter_args%" +if _INTERPRETER_ARGS_RAW == _INTERPRETER_ARGS_SENTINEL: INTERPRETER_ARGS = [] +else: + INTERPRETER_ARGS = [arg for arg in _INTERPRETER_ARGS_RAW.split("\n") if arg] ADDITIONAL_INTERPRETER_ARGS = os.environ.get("RULES_PYTHON_ADDITIONAL_INTERPRETER_ARGS", "")