Skip to content

Commit acbd8c7

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

File tree

4 files changed

+110
-41
lines changed

4 files changed

+110
-41
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_bazel_impl(
42+
providers, binary_info, environment_info = py_executable_bazel_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-32
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ load(
5959
load(
6060
":toolchain_types.bzl",
6161
"EXEC_TOOLS_TOOLCHAIN_TYPE",
62-
"PY_TEST_TOOLCHAIN_TYPE",
6362
TOOLCHAIN_TYPE = "TARGET_TOOLCHAIN_TYPE",
6463
)
6564

@@ -179,7 +178,7 @@ def py_executable_base_impl(ctx, *, semantics, is_test, inherited_environment =
179178

180179
imports = collect_imports(ctx, semantics)
181180

182-
runtime_details = _get_runtime_details(ctx, semantics, is_test)
181+
runtime_details = _get_runtime_details(ctx, semantics)
183182
if ctx.configuration.coverage_enabled:
184183
extra_deps = semantics.get_coverage_deps(ctx, runtime_details)
185184
else:
@@ -278,7 +277,7 @@ def _declare_executable_file(ctx):
278277

279278
return executable
280279

281-
def _get_runtime_details(ctx, semantics, is_test):
280+
def _get_runtime_details(ctx, semantics):
282281
"""Gets various information about the Python runtime to use.
283282
284283
While most information comes from the toolchain, various legacy and
@@ -287,7 +286,6 @@ def _get_runtime_details(ctx, semantics, is_test):
287286
Args:
288287
ctx: Rule ctx
289288
semantics: A `BinarySemantics` struct; see `create_binary_semantics_struct`
290-
is_test: bool; True if the rule is a test rule (has `test=True`), False if not
291289
292290
Returns:
293291
A struct; see inline-field comments of the return value for details.
@@ -316,7 +314,6 @@ def _get_runtime_details(ctx, semantics, is_test):
316314
if not effective_runtime:
317315
fail("Unable to find Python runtime")
318316

319-
extra_test_env = {}
320317
if effective_runtime:
321318
direct = [] # List of files
322319
transitive = [] # List of depsets
@@ -329,12 +326,6 @@ def _get_runtime_details(ctx, semantics, is_test):
329326
direct.append(effective_runtime.coverage_tool)
330327
if effective_runtime.coverage_files:
331328
transitive.append(effective_runtime.coverage_files)
332-
if is_test:
333-
py_test_toolchain = ctx.exec_groups["test"].toolchains[PY_TEST_TOOLCHAIN_TYPE]
334-
if py_test_toolchain:
335-
coverage_rc = py_test_toolchain.py_test_info.coverage_rc
336-
extra_test_env = {"COVERAGE_RC": coverage_rc.files.to_list()[0].short_path}
337-
direct.extend(coverage_rc.files.to_list())
338329
runtime_files = depset(direct = direct, transitive = transitive)
339330
else:
340331
runtime_files = depset()
@@ -366,9 +357,6 @@ def _get_runtime_details(ctx, semantics, is_test):
366357
# be included. For in-build runtimes, this shold include the interpreter
367358
# and any supporting files.
368359
runfiles = ctx.runfiles(transitive_files = runtime_files),
369-
# extra_test_env: dict[str, str]; Additional environment variables to
370-
# set when running the test.
371-
extra_test_env = extra_test_env,
372360
)
373361

374362
def _maybe_get_runtime_from_ctx(ctx):
@@ -861,22 +849,8 @@ def _create_providers(
861849
Returns:
862850
A list of modern providers.
863851
"""
864-
865852
providers = [
866-
DefaultInfo(
867-
executable = executable,
868-
files = default_outputs,
869-
default_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
870-
ctx,
871-
runfiles_details.default_runfiles,
872-
),
873-
data_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
874-
ctx,
875-
runfiles_details.data_runfiles,
876-
),
877-
),
878853
create_instrumented_files_info(ctx),
879-
_create_run_environment_info(ctx, inherited_environment, runtime_details.extra_test_env),
880854
PyExecutableInfo(
881855
main = main_py,
882856
runfiles_without_exe = runfiles_details.runfiles_without_exe,
@@ -946,9 +920,22 @@ def _create_providers(
946920
runtime_details = runtime_details,
947921
)
948922
providers.extend(extra_providers)
949-
return providers
923+
environemnt_info = _create_run_environment_info(ctx, inherited_environment)
924+
binary_info = struct(
925+
executable = executable,
926+
files = default_outputs,
927+
default_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
928+
ctx,
929+
runfiles_details.default_runfiles,
930+
),
931+
data_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
932+
ctx,
933+
runfiles_details.data_runfiles,
934+
),
935+
)
936+
return providers, binary_info, environemnt_info
950937

951-
def _create_run_environment_info(ctx, inherited_environment, extra_test_env):
938+
def _create_run_environment_info(ctx, inherited_environment):
952939
expanded_env = {}
953940
for key, value in ctx.attr.env.items():
954941
expanded_env[key] = _py_builtins.expand_location_and_make_variables(
@@ -957,8 +944,7 @@ def _create_run_environment_info(ctx, inherited_environment, extra_test_env):
957944
expression = value,
958945
targets = ctx.attr.data,
959946
)
960-
expanded_env.update(extra_test_env)
961-
return RunEnvironmentInfo(
947+
return struct(
962948
environment = expanded_env,
963949
inherited_environment = inherited_environment,
964950
)

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_bazel_impl(
44+
providers, binary_info, environment_info = py_executable_bazel_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)