Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
149a840
basic impl
rickeylev Dec 15, 2025
a95377e
Merge branch 'main' of https://github.com/bazel-contrib/rules_python …
rickeylev Jan 25, 2026
1f22bdc
disable test pre-bazel 8
rickeylev Jan 25, 2026
9328fbe
Merge branch 'main' of https://github.com/bazel-contrib/rules_python …
rickeylev Jan 25, 2026
adb589f
add bazel 7 support
rickeylev Jan 25, 2026
8ced1db
make test support workspace mode
rickeylev Jan 25, 2026
5dbfab4
cleanup
rickeylev Jan 25, 2026
89b438a
basic impl of config_settings attr
rickeylev Jan 25, 2026
5ae496e
add missing bzl deps
rickeylev Jan 26, 2026
3518a8b
format code
rickeylev Jan 26, 2026
b23f452
disable buildifier warning
rickeylev Jan 26, 2026
6528660
fix case when venv is none
rickeylev Jan 27, 2026
4046f98
add system_python test case
rickeylev Jan 27, 2026
a41b4fc
handle venv none in create_executable
rickeylev Jan 27, 2026
f6a3324
make zipapp transition set build zip to false
rickeylev Jan 27, 2026
e3b223d
try setting command_line_option:build_python_zip=false
rickeylev Jan 27, 2026
895d21b
add cli:build_python_zip to transition outputs
rickeylev Jan 27, 2026
678ea62
use correct type for cli:build_python_zip
rickeylev Jan 27, 2026
5cdfd85
disable windows for zipapp tests
rickeylev Jan 27, 2026
cf2daa5
trying to debug windows
rickeylev Jan 28, 2026
ce0bb07
run fewer presubmits
rickeylev Jan 28, 2026
f1dd5fc
fix missing symbol loads
rickeylev Jan 28, 2026
22387dc
add missing bzl dep, skip BCR test
rickeylev Jan 28, 2026
3274d73
undo anti-zipper debug logic
rickeylev Jan 28, 2026
9946c2e
improving test error reporting
rickeylev Jan 28, 2026
a7cca04
write bytes, not text, to avoid windows-specific line endings
rickeylev Jan 28, 2026
860f561
re enable all presubmits
rickeylev Jan 28, 2026
0df803f
Merge branch 'main' of https://github.com/bazel-contrib/rules_python …
rickeylev Jan 28, 2026
d9a0f5f
debug logic for RBE
rickeylev Jan 28, 2026
a8d9bd0
more rbe debugging
rickeylev Jan 28, 2026
0209bb8
make visible_for_testing a flag, more debug print
rickeylev Jan 28, 2026
716c45c
try declare_symlink instead of declare_file
rickeylev Jan 28, 2026
06af34a
undo declare_symlink; doesnt work with symlink(target_file)
rickeylev Jan 28, 2026
702794f
maybe found RBE solution?
rickeylev Jan 28, 2026
f62f485
undo more presubmit debug
rickeylev Jan 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ buildifier:
build_flags:
- "--keep_going"
- "--build_tag_filters=-integration-test"
- "--verbose_failures"
test_targets:
- "--"
- "..."
Expand Down Expand Up @@ -286,6 +287,7 @@ tasks:
test_flags:
- "--test_tag_filters=-integration-test,-acceptance-test"
- "--extra_toolchains=@buildkite_config//config:cc-toolchain"
- "--@rules_python//python/private:visible_for_testing=true"

integration_test_build_file_generation_ubuntu_minimum_supported_workspace:
<<: *minimum_supported_version
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ END_UNRELEASED_TEMPLATE
`true`, a `py_*` target's `pyi_srcs` attribute will be set if any `.pyi` files
that are associated with the target's `srcs` are present.
([#3354](https://github.com/bazel-contrib/rules_python/issues/3354)).
* (zipapp) {obj}`py_zipapp_binary` and {obj}`py_zipapp_test` rules added. These
will replace `--build_python_zip` and the zip output group of
`py_binary/py_test`. The zipapp rules support more functionality, correctness,
and have better build performance.

{#v1-8-3}
## [1.8.3] - 2026-01-27
Expand All @@ -106,6 +110,7 @@ END_UNRELEASED_TEMPLATE
### Fixed
* (pipstar) Extra resolution that refers back to the package being resolved works again.
Fixes [#3524](https://github.com/bazel-contrib/rules_python/issues/3524).
>>>>>>> b4ec825850fb27e5568165d0a388f5cc4b2b84a2

{#v1-8-0}
## [1.8.0] - 2025-12-19
Expand Down
3 changes: 3 additions & 0 deletions docs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,13 @@ sphinx_stardocs(
"//python/private/pypi:pkg_aliases_bzl",
"//python/private/pypi:whl_config_setting_bzl",
"//python/private/pypi:whl_library_bzl",
"//python/private/zipapp:py_zipapp_rule_bzl",
"//python/uv:lock_bzl",
"//python/uv:uv_bzl",
"//python/uv:uv_toolchain_bzl",
"//python/uv:uv_toolchain_info_bzl",
"//python/zipapp:py_zipapp_binary_bzl",
"//python/zipapp:py_zipapp_test_bzl",
] + ([
# This depends on @pythons_hub, which is only created under bzlmod,
"//python/extensions:pip_bzl",
Expand Down
1 change: 1 addition & 0 deletions python/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ filegroup(
"//python/runfiles:distribution",
"//python/runtime_env_toolchains:distribution",
"//python/uv:distribution",
"//python/zipapp:distribution",
],
visibility = ["//:__pkg__"],
)
Expand Down
26 changes: 12 additions & 14 deletions python/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@bazel_skylib//rules:common_settings.bzl", "bool_setting")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "bool_setting")
load("//python:py_binary.bzl", "py_binary")
load("//python:py_library.bzl", "py_library")
load(":bazel_config_mode.bzl", "bazel_config_mode")
Expand All @@ -38,6 +38,7 @@ filegroup(
"//python/private/cc:distribution",
"//python/private/pypi:distribution",
"//python/private/whl_filegroup:distribution",
"//python/private/zipapp:distribution",
"//tools/build_defs/python/private:distribution",
],
visibility = ["//python:__pkg__"],
Expand Down Expand Up @@ -77,7 +78,9 @@ bzl_library(
":py_info_bzl",
":py_internal_bzl",
":reexports_bzl",
":rule_builders_bzl",
":rules_cc_srcs_bzl",
"@bazel_skylib//lib:dicts",
"@bazel_skylib//rules:common_settings",
],
)
Expand Down Expand Up @@ -366,7 +369,7 @@ bzl_library(
name = "py_cc_toolchain_rule_bzl",
srcs = ["py_cc_toolchain_rule.bzl"],
deps = [
":common_labels.bzl",
":common_labels_bzl",
":py_cc_toolchain_info_bzl",
":rules_cc_srcs_bzl",
":sentinel_bzl",
Expand Down Expand Up @@ -460,7 +463,10 @@ bzl_library(
bzl_library(
name = "py_interpreter_program_bzl",
srcs = ["py_interpreter_program.bzl"],
deps = ["@bazel_skylib//rules:common_settings"],
deps = [
":sentinel_bzl",
"@bazel_skylib//rules:common_settings",
],
)

bzl_library(
Expand Down Expand Up @@ -740,8 +746,8 @@ bzl_library(
srcs = ["venv_runfiles.bzl"],
deps = [
":common_bzl",
":py_info.bzl",
":py_internal.bzl",
":py_info_bzl",
":py_internal_bzl",
"@bazel_skylib//lib:paths",
],
)
Expand Down Expand Up @@ -786,14 +792,6 @@ filegroup(
visibility = ["//visibility:public"],
)

filegroup(
name = "zip_main_template",
srcs = ["zip_main_template.py"],
# Not actually public. Only public because it's an implicit dependency of
# py_runtime.
visibility = ["//visibility:public"],
)

filegroup(
name = "site_init_template",
srcs = ["site_init_template.py"],
Expand Down Expand Up @@ -845,7 +843,7 @@ bazel_config_mode(name = "bazel_config_mode")

# This should only be set by analysis tests to expose additional metadata to
# aid testing, so a setting instead of a flag.
bool_setting(
bool_flag(
name = "visible_for_testing",
build_setting_default = False,
# This is only because it is an implicit dependency by the toolchains.
Expand Down
147 changes: 147 additions & 0 deletions python/private/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
load("@rules_python_internal//:rules_python_config.bzl", "config")
load("//python/private:py_interpreter_program.bzl", "PyInterpreterProgramInfo")
load("//python/private:toolchain_types.bzl", "EXEC_TOOLS_TOOLCHAIN_TYPE")
load(":cc_helper.bzl", "cc_helper")
load(":py_cc_link_params_info.bzl", "PyCcLinkParamsInfo")
load(":py_info.bzl", "PyInfo", "PyInfoBuilder")
Expand All @@ -41,6 +44,17 @@ PYTHON_FILE_EXTENSIONS = [
"so", # Python C modules, usually Linux
]

BUILTIN_BUILD_PYTHON_ZIP = [] if config.bazel_10_or_later else [
"//command_line_option:build_python_zip",
]

def maybe_builtin_build_python_zip(value, settings = None):
settings = settings or {}
if not config.bazel_10_or_later:
settings["//command_line_option:build_python_zip"] = value

return settings

def create_binary_semantics_struct(
*,
get_native_deps_dso_name,
Expand Down Expand Up @@ -463,3 +477,136 @@ def collect_deps(ctx, extra_deps = []):
deps = list(deps)
deps.extend(extra_deps)
return deps

def maybe_create_repo_mapping(ctx, *, runfiles):
"""Creates a repo mapping manifest if bzlmod is enabled.

There isn't a way to reference the repo mapping Bazel implicitly
creates, so we have to manually create it ourselves.

Args:
ctx: rule ctx.
runfiles: runfiles object to generate mapping for.

Returns:
File object if the repo mapping manifest was created, None otherwise.
"""
if not py_internal.is_bzlmod_enabled(ctx):
return None

# We have to add `.custom` because `{name}.repo_mapping` is used by Bazel
# internally.
repo_mapping_manifest = ctx.actions.declare_file(ctx.label.name + ".custom.repo_mapping")
py_internal.create_repo_mapping_manifest(
ctx = ctx,
runfiles = runfiles,
output = repo_mapping_manifest,
)
return repo_mapping_manifest

def actions_run(
ctx,
*,
executable,
toolchain = None,
**kwargs):
"""Runs a tool as an action, supporting py_interpreter_program targets.

This is wrapper around `ctx.actions.run()` that sets some useful defaults,
supports handling `py_interpreter_program` targets, and some other features
to let the target being run influence the action invocation.

Args:
ctx: The rule context. The rule must have the
`//python:exec_tools_toolchain_type` toolchain available.
executable: The executable to run. This can be a target that provides
`PyInterpreterProgramInfo` or a regular executable target. If it
provides `testing.ExecutionInfo`, the requirements will be added to
the execution requirements.
toolchain: The toolchain type to use. Must be None or
`//python:exec_tools_toolchain_type`.
**kwargs: Additional arguments to pass to `ctx.actions.run()`.
`mnemonic` and `progress_message` are required.
"""
mnemonic = kwargs.pop("mnemonic", None)
if not mnemonic:
fail("actions_run: missing required argument 'mnemonic'")

progress_message = kwargs.pop("progress_message", None)
if not progress_message:
fail("actions_run: missing required argument 'progress_message'")

tools = kwargs.pop("tools", None)
tools = list(tools) if tools else []
arguments = kwargs.pop("arguments", [])

action_arguments = []
action_env = {
"PYTHONHASHSEED": "0", # Helps avoid non-deterministic behavior
"PYTHONNOUSERSITE": "1", # Helps avoid non-deterministic behavior
"PYTHONSAFEPATH": "1", # Helps avoid incorrect import issues
}
default_info = executable[DefaultInfo]
inputs = []
if PyInterpreterProgramInfo in executable:
if toolchain and toolchain != EXEC_TOOLS_TOOLCHAIN_TYPE:
fail(("Action {}: tool {} provides PyInterpreterProgramInfo, which " +
"requires the `toolchain` arg be " +
"None or {}, got: {}").format(
mnemonic,
executable,
EXEC_TOOLS_TOOLCHAIN_TYPE,
toolchain,
))
tc = ctx.toolchains[EXEC_TOOLS_TOOLCHAIN_TYPE]
print("==== exec_tools tc:", tc)
exec_tools = ctx.toolchains[EXEC_TOOLS_TOOLCHAIN_TYPE].exec_tools

##action_exe = exec_tools.exec_interpreter[DefaultInfo].files_to_run
eitc = exec_tools.exec_interpreter[platform_common.ToolchainInfo]
print(dir(eitc.py3_runtime))
py3 = eitc.py3_runtime
action_exe = py3.interpreter
inputs.append(py3.files)

program_info = executable[PyInterpreterProgramInfo]

interpreter_args = ctx.actions.args()
interpreter_args.add_all(program_info.interpreter_args)
interpreter_args.add(default_info.files_to_run.executable)
action_arguments.append(interpreter_args)

action_env.update(program_info.env)

tools.append(default_info.files_to_run)
toolchain = EXEC_TOOLS_TOOLCHAIN_TYPE
else:
action_exe = executable[DefaultInfo].files_to_run

execution_requirements = {}
if testing.ExecutionInfo in executable:
execution_requirements.update(executable[testing.ExecutionInfo].requirements)

# Give precedence to caller's execution requirements.
execution_requirements.update(kwargs.pop("execution_requirements", None) or {})

# Give precedence to caller's env.
action_env.update(kwargs.pop("env", None) or {})
action_arguments.extend(arguments)
print("==== actions_run: exe:", action_exe)
kw_inputs = kwargs.pop("inputs")
print(type(kw_inputs))
inputs.append(kw_inputs)
action_inputs = depset(transitive = inputs)
ctx.actions.run(
executable = action_exe,
arguments = action_arguments,
tools = tools,
env = action_env,
execution_requirements = execution_requirements,
toolchain = toolchain,
mnemonic = mnemonic,
progress_message = progress_message,
inputs = action_inputs,
**kwargs
)
2 changes: 2 additions & 0 deletions python/private/py_exec_tools_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ def _current_interpreter_executable_impl(ctx):
# because of things like pyenv: they use $0 to determine what to
# re-exec. If it's not a recognized name, then they fail.
if runtime.interpreter:
print("==== current interpreter exe: symlink() to ", runtime.interpreter)
executable = ctx.actions.declare_file(runtime.interpreter.basename)
ctx.actions.symlink(output = executable, target_file = runtime.interpreter, is_executable = True)
else:
print("==== current interpreter exe: declare_symlink()")
executable = ctx.actions.declare_symlink(paths.basename(runtime.interpreter_path))
ctx.actions.symlink(output = executable, target_path = runtime.interpreter_path)
return [
Expand Down
Loading