fix: handle unsubstituted template placeholders for external native py_binary by thomasdesr · Pull Request #3495 · bazel-contrib/rules_python
and others added 2 commits
January 5, 2026 16:27…y_binary Problem: In rules_python 1.7.0, PR bazel-contrib#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.
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.
thomasdesr added a commit to thomasdesr/rules_python_3495_repro that referenced this pull request
Jan 9, 2026This demonstrates the regression in rules_python 1.7.0 where
%interpreter_args% template placeholders are not substituted for
external py_binary targets.
Building the same target now fails:
bazel build @com_github_grpc_grpc//src/python/grpcio/grpc/_cython:cygrpc.pyx_cython_translation
Error:
File ".../cython_binary", line 39
%interpreter_args%
^
SyntaxError: invalid syntax
Root cause: PR #3242 introduced new template variables that native
py_binary doesn't substitute.
Fix: bazel-contrib/rules_python#3495
thomasdesr added a commit to thomasdesr/rules_python_3495_repro that referenced this pull request
Jan 9, 2026This demonstrates the regression in rules_python 1.7.0 where
%interpreter_args% template placeholders are not substituted for
external py_binary targets.
Building the same target now fails:
bazel build @com_github_grpc_grpc//src/python/grpcio/grpc/_cython:cygrpc.pyx_cython_translation
Error:
File ".../cython_binary", line 39
%interpreter_args%
^
SyntaxError: invalid syntax
Root cause: PR #3242 introduced new template variables that native
py_binary doesn't substitute.
Fix: bazel-contrib/rules_python#3495
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters