Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ Unreleased changes template.
* (pypi) The PyPI extension will no longer write the lock file entries as the
extension has been marked reproducible.
Fixes [#2434](https://github.com/bazel-contrib/rules_python/issues/2434).
* (rules) {attr}`py_binary.srcs` and {attr}`py_test.srcs` is no longer mandatory when
`main_module` is specified.

[20250317]: https://github.com/astral-sh/python-build-standalone/releases/tag/20250317

Expand Down
5 changes: 3 additions & 2 deletions python/private/py_executable.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ def _create_stage1_bootstrap(
)
template = runtime.bootstrap_template
subs["%shebang%"] = runtime.stub_shebang
else:
elif main_py:
if (ctx.configuration.coverage_enabled and
runtime and
runtime.coverage_tool):
Expand All @@ -807,6 +807,8 @@ def _create_stage1_bootstrap(
subs["%import_all%"] = ("True" if ctx.fragments.bazel_py.python_import_all_repositories else "False")
subs["%imports%"] = ":".join(imports.to_list())
subs["%main%"] = "{}/{}".format(ctx.workspace_name, main_py.short_path)
else:
fail("mandatory 'srcs' attribute has not been specified")

ctx.actions.expand_template(
template = template,
Expand Down Expand Up @@ -1888,7 +1890,6 @@ def create_executable_rule_builder(implementation, **kwargs):
),
**kwargs
)
builder.attrs.get("srcs").set_mandatory(True)
return builder

def cc_configure_features(
Expand Down
71 changes: 47 additions & 24 deletions tests/base_rules/py_executable_base_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER") # buildifier: disable
load("//tests/base_rules:base_tests.bzl", "create_base_tests")
load("//tests/base_rules:util.bzl", "WINDOWS_ATTR", pt_util = "util")
load("//tests/support:py_executable_info_subject.bzl", "PyExecutableInfoSubject")
load("//tests/support:support.bzl", "CC_TOOLCHAIN", "CROSSTOOL_TOP", "LINUX_X86_64", "WINDOWS_X86_64")
load("//tests/support:support.bzl", "BOOTSTRAP_IMPL", "CC_TOOLCHAIN", "CROSSTOOL_TOP", "LINUX_X86_64", "WINDOWS_X86_64")

_tests = []

Expand Down Expand Up @@ -342,6 +342,52 @@ def _test_name_cannot_end_in_py_impl(env, target):
matching.str_matches("name must not end in*.py"),
)

def _test_no_srcs(name, config):
rt_util.helper_target(
config.rule,
name = name + "_subject",
main_module = "dummy",
)
analysis_test(
name = name,
impl = _test_no_srcs_impl,
target = name + "_subject",
config_settings = {
"//command_line_option:platforms": [LINUX_X86_64],
},
expect_failure = True,
)

def _test_no_srcs_impl(env, target):
env.expect.that_target(target).failures().contains_predicate(
matching.str_matches("mandatory*srcs"),
)

_tests.append(_test_no_srcs)

def _test_no_srcs_script_bootstrap(name, config):
rt_util.helper_target(
config.rule,
name = name + "_subject",
main_module = "dummy",
)
analysis_test(
name = name,
impl = _test_no_srcs_script_bootstrap_impl,
target = name + "_subject",
config_settings = {
BOOTSTRAP_IMPL: "script",
"//command_line_option:platforms": [LINUX_X86_64],
},
)

def _test_no_srcs_script_bootstrap_impl(env, target):
env.expect.that_target(target).default_outputs().contains(
"{package}/{test_name}_subject",
)

_tests.append(_test_no_srcs_script_bootstrap)

def _test_py_runtime_info_provided(name, config):
rt_util.helper_target(
config.rule,
Expand All @@ -365,29 +411,6 @@ def _test_py_runtime_info_provided_impl(env, target):

_tests.append(_test_py_runtime_info_provided)

# Can't test this -- mandatory validation happens before analysis test
# can intercept it
# TODO(#1069): Once re-implemented in Starlark, modify rule logic to make this
# testable.
# def _test_srcs_is_mandatory(name, config):
# rt_util.helper_target(
# config.rule,
# name = name + "_subject",
# )
# analysis_test(
# name = name,
# impl = _test_srcs_is_mandatory,
# target = name + "_subject",
# expect_failure = True,
# )
#
# _tests.append(_test_srcs_is_mandatory)
#
# def _test_srcs_is_mandatory_impl(env, target):
# env.expect.that_target(target).failures().contains_predicate(
# matching.str_matches("mandatory*srcs"),
# )

# =====
# You were gonna add a test at the end, weren't you?
# Nope. Please keep them sorted; put it in its alphabetical location.
Expand Down
1 change: 1 addition & 0 deletions tests/support/support.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ CROSSTOOL_TOP = Label("//tests/support/cc_toolchains:cc_toolchain_suite")
# str() around Label() is necessary because rules_testing's config_settings
# doesn't accept yet Label objects.
ADD_SRCS_TO_RUNFILES = str(Label("//python/config_settings:add_srcs_to_runfiles"))
BOOTSTRAP_IMPL = str(Label("//python/config_settings:bootstrap_impl"))
EXEC_TOOLS_TOOLCHAIN = str(Label("//python/config_settings:exec_tools_toolchain"))
PRECOMPILE = str(Label("//python/config_settings:precompile"))
PRECOMPILE_SOURCE_RETENTION = str(Label("//python/config_settings:precompile_source_retention"))
Expand Down