Skip to content

Commit 23011c4

Browse files
committed
Factor out Default and RuntimeInfo providers
Create partially-bound function for configuring py_test
1 parent c111829 commit 23011c4

File tree

4 files changed

+110
-40
lines changed

4 files changed

+110
-40
lines changed

python/private/py_binary_rule.bzl

+18-1
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,28 @@ _PY_TEST_ATTRS = {
3939
}
4040

4141
def _py_binary_impl(ctx):
42-
return py_executable_impl(
42+
providers, binary_info, environment_info = py_executable_impl(
4343
ctx = ctx,
4444
is_test = False,
4545
inherited_environment = [],
4646
)
47+
providers.extend(
48+
[
49+
# We construct DefaultInfo and RunEnvironmentInfo here, as other py_binary-like
50+
# rules (py_test) need a different DefaultInfo and RunEnvironmentInfo.
51+
DefaultInfo(
52+
executable = binary_info.executable,
53+
files = binary_info.files,
54+
default_runfiles = binary_info.default_runfiles,
55+
data_runfiles = binary_info.data_runfiles,
56+
),
57+
RunEnvironmentInfo(
58+
environment = environment_info.environment,
59+
inherited_environment = environment_info.inherited_environment,
60+
),
61+
],
62+
)
63+
return providers
4764

4865
py_binary = create_executable_rule(
4966
implementation = _py_binary_impl,

python/private/py_executable.bzl

+18-31
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ def py_executable_base_impl(ctx, *, semantics, is_test, inherited_environment =
940940

941941
imports = collect_imports(ctx, semantics)
942942

943-
runtime_details = _get_runtime_details(ctx, semantics, is_test)
943+
runtime_details = _get_runtime_details(ctx, semantics)
944944
if ctx.configuration.coverage_enabled:
945945
extra_deps = semantics.get_coverage_deps(ctx, runtime_details)
946946
else:
@@ -1040,7 +1040,7 @@ def _declare_executable_file(ctx):
10401040

10411041
return executable
10421042

1043-
def _get_runtime_details(ctx, semantics, is_test):
1043+
def _get_runtime_details(ctx, semantics):
10441044
"""Gets various information about the Python runtime to use.
10451045
10461046
While most information comes from the toolchain, various legacy and
@@ -1049,7 +1049,6 @@ def _get_runtime_details(ctx, semantics, is_test):
10491049
Args:
10501050
ctx: Rule ctx
10511051
semantics: A `BinarySemantics` struct; see `create_binary_semantics_struct`
1052-
is_test: bool; True if the rule is a test rule (has `test=True`), False if not
10531052
10541053
Returns:
10551054
A struct; see inline-field comments of the return value for details.
@@ -1078,7 +1077,6 @@ def _get_runtime_details(ctx, semantics, is_test):
10781077
if not effective_runtime:
10791078
fail("Unable to find Python runtime")
10801079

1081-
extra_test_env = {}
10821080
if effective_runtime:
10831081
direct = [] # List of files
10841082
transitive = [] # List of depsets
@@ -1091,12 +1089,6 @@ def _get_runtime_details(ctx, semantics, is_test):
10911089
direct.append(effective_runtime.coverage_tool)
10921090
if effective_runtime.coverage_files:
10931091
transitive.append(effective_runtime.coverage_files)
1094-
if is_test:
1095-
py_test_toolchain = ctx.exec_groups["test"].toolchains[PY_TEST_TOOLCHAIN_TYPE]
1096-
if py_test_toolchain:
1097-
coverage_rc = py_test_toolchain.py_test_info.coverage_rc
1098-
extra_test_env = {"COVERAGE_RC": coverage_rc.files.to_list()[0].short_path}
1099-
direct.extend(coverage_rc.files.to_list())
11001092
runtime_files = depset(direct = direct, transitive = transitive)
11011093
else:
11021094
runtime_files = depset()
@@ -1128,9 +1120,6 @@ def _get_runtime_details(ctx, semantics, is_test):
11281120
# be included. For in-build runtimes, this shold include the interpreter
11291121
# and any supporting files.
11301122
runfiles = ctx.runfiles(transitive_files = runtime_files),
1131-
# extra_test_env: dict[str, str]; Additional environment variables to
1132-
# set when running the test.
1133-
extra_test_env = extra_test_env,
11341123
)
11351124

11361125
def _maybe_get_runtime_from_ctx(ctx):
@@ -1626,22 +1615,8 @@ def _create_providers(
16261615
Returns:
16271616
A list of modern providers.
16281617
"""
1629-
16301618
providers = [
1631-
DefaultInfo(
1632-
executable = executable,
1633-
files = default_outputs,
1634-
default_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
1635-
ctx,
1636-
runfiles_details.default_runfiles,
1637-
),
1638-
data_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
1639-
ctx,
1640-
runfiles_details.data_runfiles,
1641-
),
1642-
),
16431619
create_instrumented_files_info(ctx),
1644-
_create_run_environment_info(ctx, inherited_environment, runtime_details.extra_test_env),
16451620
PyExecutableInfo(
16461621
main = main_py,
16471622
runfiles_without_exe = runfiles_details.runfiles_without_exe,
@@ -1712,9 +1687,22 @@ def _create_providers(
17121687
runtime_details = runtime_details,
17131688
)
17141689
providers.extend(extra_providers)
1715-
return providers
1690+
environemnt_info = _create_run_environment_info(ctx, inherited_environment)
1691+
binary_info = struct(
1692+
executable = executable,
1693+
files = default_outputs,
1694+
default_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
1695+
ctx,
1696+
runfiles_details.default_runfiles,
1697+
),
1698+
data_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
1699+
ctx,
1700+
runfiles_details.data_runfiles,
1701+
),
1702+
)
1703+
return providers, binary_info, environemnt_info
17161704

1717-
def _create_run_environment_info(ctx, inherited_environment, extra_test_env):
1705+
def _create_run_environment_info(ctx, inherited_environment):
17181706
expanded_env = {}
17191707
for key, value in ctx.attr.env.items():
17201708
expanded_env[key] = _py_builtins.expand_location_and_make_variables(
@@ -1723,8 +1711,7 @@ def _create_run_environment_info(ctx, inherited_environment, extra_test_env):
17231711
expression = value,
17241712
targets = ctx.attr.data,
17251713
)
1726-
expanded_env.update(extra_test_env)
1727-
return RunEnvironmentInfo(
1714+
return struct(
17281715
environment = expanded_env,
17291716
inherited_environment = inherited_environment,
17301717
)

python/private/py_test_rule.bzl

+27-2
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,38 @@ _BAZEL_PY_TEST_ATTRS = {
4141
}
4242

4343
def _py_test_impl(ctx):
44-
providers = py_executable_impl(
44+
providers, binary_info, environment_info = py_executable_impl(
4545
ctx = ctx,
4646
is_test = True,
4747
inherited_environment = ctx.attr.env_inherit,
4848
)
4949
maybe_add_test_execution_info(providers, ctx)
50-
return providers
50+
py_test_toolchain = ctx.exec_groups["test"].toolchains[PY_TEST_TOOLCHAIN_TYPE]
51+
if py_test_toolchain:
52+
py_test_info = py_test_toolchain.py_test_info
53+
else:
54+
providers.extend(
55+
[
56+
DefaultInfo(
57+
executable = binary_info.executable,
58+
files = binary_info.files,
59+
default_runfiles = binary_info.default_runfiles,
60+
data_runfiles = binary_info.data_runfiles,
61+
),
62+
RunEnvironmentInfo(
63+
environment = environment_info.environment,
64+
inherited_environment = environment_info.inherited_environment,
65+
),
66+
],
67+
)
68+
return providers
69+
test_providers = py_test_info.get_runner.func(
70+
ctx,
71+
binary_info,
72+
environment_info,
73+
**py_test_info.get_runner.args
74+
)
75+
return test_providers + providers
5176

5277
py_test = create_executable_rule(
5378
implementation = _py_test_impl,

python/private/py_test_toolchain.bzl

+47-6
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,66 @@ load(
2525
PyTestProviderInfo = provider(
2626
doc = "Information about the pytest toolchain",
2727
fields = [
28-
"coverage_rc",
28+
"get_runner",
2929
],
3030
)
3131

32+
def _get_runner(ctx, binary_info, environment_info, coverage_rc):
33+
"""
34+
Constructs and returns a list containing `DefaultInfo` and `RunEnvironmentInfo` for a test runner setup.
35+
36+
Args:
37+
ctx: The rule context, providing access to actions, inputs, outputs, and more.
38+
binary_info: A `struct` with defaultinfo details.
39+
- `executable`: The executable binary.
40+
- `files`: The files associated with the binary.
41+
- `default_runfiles`: The default runfiles of the binary.
42+
- `data_runfiles`: Additional runfiles for data dependencies.
43+
environment_info: A `struct` with environment details.
44+
- `environment`: A dictionary of key-value pairs for the test environment.
45+
- `inherited_environment`: A list of environment variables inherited from the host.
46+
coverage_rc: A `File` or `File`-like target containing coverage configuration files.
47+
"""
48+
49+
test_env = {"COVERAGE_RC": coverage_rc.files.to_list()[0].short_path}
50+
test_env.update(environment_info.environment)
51+
52+
return [
53+
DefaultInfo(
54+
# Opportunity to override the executable in the binary_info with a new testrunner.
55+
executable = binary_info.executable,
56+
files = binary_info.files,
57+
default_runfiles = binary_info.default_runfiles.merge(
58+
ctx.runfiles(
59+
transitive_files = coverage_rc.files,
60+
),
61+
),
62+
data_runfiles = binary_info.data_runfiles,
63+
),
64+
RunEnvironmentInfo(
65+
environment = test_env,
66+
inherited_environment = environment_info.inherited_environment,
67+
),
68+
]
69+
3270
def _py_test_toolchain_impl(ctx):
3371
return [
3472
platform_common.ToolchainInfo(
3573
py_test_info = PyTestProviderInfo(
36-
coverage_rc = ctx.attr.coverage_rc,
74+
get_runner = struct(
75+
func = _get_runner,
76+
args = {
77+
"coverage_rc": ctx.attr.coverage_rc,
78+
},
79+
),
3780
),
3881
),
3982
]
4083

4184
py_test_toolchain = rule(
4285
implementation = _py_test_toolchain_impl,
4386
attrs = {
44-
"coverage_rc": attr.label(
45-
allow_single_file = True,
46-
),
87+
"coverage_rc": attr.label(allow_single_file = True),
4788
},
4889
)
4990

@@ -94,9 +135,9 @@ py_test_toolchain_repo = repository_rule(
94135
doc = "Generates a toolchain hub repository",
95136
attrs = {
96137
"coverage_rc": attr.label(
97-
allow_single_file = True,
98138
doc = "The coverage rc file",
99139
mandatory = True,
140+
allow_single_file = True,
100141
),
101142
"toolchain_type": attr.label(doc = "Toolchain type", mandatory = True),
102143
},

0 commit comments

Comments
 (0)