Skip to content

Commit 1f45950

Browse files
committed
POC for py_test toolchain
1 parent 63114a3 commit 1f45950

File tree

6 files changed

+111
-11
lines changed

6 files changed

+111
-11
lines changed

Diff for: examples/bzlmod/BUILD.bazel

+21
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ load("@pip//:requirements.bzl", "all_data_requirements", "all_requirements", "al
1010
load("@python_3_9//:defs.bzl", py_test_with_transition = "py_test")
1111
load("@python_versions//3.10:defs.bzl", compile_pip_requirements_3_10 = "compile_pip_requirements")
1212
load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
13+
load(":test_toolchain.bzl", "my_cool_toolchain")
1314

1415
# This stanza calls a rule that generates targets for managing pip dependencies
1516
# with pip-compile for a particular python version.
@@ -82,3 +83,23 @@ build_test(
8283
name = "all_requirements",
8384
targets = all_requirements,
8485
)
86+
# BUILD file
87+
88+
my_cool_toolchain(
89+
name = "cool_prod_linux_runner",
90+
)
91+
92+
toolchain(
93+
name = "prod_linux_toolchain",
94+
exec_compatible_with = [
95+
"@platforms//os:linux",
96+
"@platforms//cpu:x86_64",
97+
],
98+
target_compatible_with = [
99+
"@platforms//os:linux",
100+
"@platforms//cpu:x86_64",
101+
],
102+
toolchain = ":cool_prod_linux_runner",
103+
# TODO: Where are these for Bazel?
104+
toolchain_type = "@rules_python//python:test_runner_toolchain_type",
105+
)

Diff for: examples/bzlmod/test_toolchain.bzl

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
Simple toolchain which overrides env and exec requirements.
3+
"""
4+
5+
PytestProvider = provider(
6+
fields = [
7+
"get_runner",
8+
],
9+
)
10+
11+
def _get_runner(ctx, binary_info):
12+
executable = ctx.actions.declare_file("{}_cov".format(ctx.label.name))
13+
ctx.actions.write(
14+
output = executable,
15+
is_executable = True,
16+
content = """#!/bin/bash
17+
/home/ewianda/projects/rules_python/examples/bzlmod/.venv/bin/coverage run %s
18+
coverage_dir=$COVERAGE_DIR/pylcov.dat
19+
/home/ewianda/projects/rules_python/examples/bzlmod/.venv/bin/coverage lcov -o $coverage_dir
20+
""" % binary_info.executable.short_path,
21+
)
22+
default_runfiles = ctx.runfiles(
23+
files = [executable],
24+
).merge(binary_info.default_runfiles)
25+
return [
26+
DefaultInfo(
27+
files = depset(transitive = [binary_info.files, depset([executable])]),
28+
# Here is where we would return our own runner.
29+
executable = executable,
30+
default_runfiles = default_runfiles,
31+
data_runfiles = binary_info.data_runfiles,
32+
),
33+
]
34+
35+
def _my_cool_toolchain_impl(ctx):
36+
return [platform_common.ToolchainInfo(
37+
py_test_info = PytestProvider(
38+
get_runner = struct(
39+
func = _get_runner,
40+
args = {
41+
"execution_requirements": ctx.attr.execution_requirements,
42+
"test_environment": ctx.attr.test_environment,
43+
},
44+
),
45+
),
46+
)]
47+
48+
my_cool_toolchain = rule(
49+
implementation = _my_cool_toolchain_impl,
50+
attrs = {
51+
"execution_requirements": attr.string_dict(),
52+
"test_environment": attr.string_dict(),
53+
},
54+
)

Diff for: python/BUILD.bazel

+5
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,8 @@ exports_files([
340340
current_py_toolchain(
341341
name = "current_py_toolchain",
342342
)
343+
344+
toolchain_type(
345+
name = "test_runner_toolchain_type",
346+
visibility = ["//visibility:public"],
347+
)

Diff for: python/private/common/py_binary_rule_bazel.bzl

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

4141
def _py_binary_impl(ctx):
42-
return py_executable_bazel_impl(
42+
_, providers = py_executable_bazel_impl(
4343
ctx = ctx,
4444
is_test = False,
4545
inherited_environment = [],
4646
)
47+
return providers
4748

4849
py_binary = create_executable_rule(
4950
implementation = _py_binary_impl,

Diff for: python/private/common/py_executable.bzl

+17-9
Original file line numberDiff line numberDiff line change
@@ -816,18 +816,26 @@ def _create_providers(
816816
Returns:
817817
A list of modern providers.
818818
"""
819+
default_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
820+
ctx,
821+
runfiles_details.default_runfiles,
822+
)
823+
data_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
824+
ctx,
825+
runfiles_details.data_runfiles,
826+
)
827+
binary_info = struct(
828+
files = default_outputs,
829+
default_runfiles = default_runfiles,
830+
data_runfiles = data_runfiles,
831+
executable = executable,
832+
)
819833
providers = [
820834
DefaultInfo(
821835
executable = executable,
822836
files = default_outputs,
823-
default_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
824-
ctx,
825-
runfiles_details.default_runfiles,
826-
),
827-
data_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
828-
ctx,
829-
runfiles_details.data_runfiles,
830-
),
837+
default_runfiles = default_runfiles,
838+
data_runfiles = data_runfiles,
831839
),
832840
create_instrumented_files_info(ctx),
833841
_create_run_environment_info(ctx, inherited_environment),
@@ -897,7 +905,7 @@ def _create_providers(
897905
runtime_details = runtime_details,
898906
)
899907
providers.extend(extra_providers)
900-
return providers
908+
return binary_info, providers
901909

902910
def _create_run_environment_info(ctx, inherited_environment):
903911
expanded_env = {}

Diff for: python/private/common/py_test_rule_bazel.bzl

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
load("@bazel_skylib//lib:dicts.bzl", "dicts")
1717
load(":attributes.bzl", "AGNOSTIC_TEST_ATTRS")
1818
load(":common.bzl", "maybe_add_test_execution_info")
19+
load("//python/private:py_executable_info.bzl", "PyExecutableInfo")
1920
load(
2021
":py_executable_bazel.bzl",
2122
"create_executable_rule",
@@ -38,18 +39,28 @@ _BAZEL_PY_TEST_ATTRS = {
3839
executable = True,
3940
),
4041
}
42+
_PY_TEST_TOOLCHAIN_TYPE = "@rules_python//python:test_runner_toolchain_type"
4143

4244
def _py_test_impl(ctx):
43-
providers = py_executable_bazel_impl(
45+
binary_info, providers = py_executable_bazel_impl(
4446
ctx = ctx,
4547
is_test = True,
4648
inherited_environment = ctx.attr.env_inherit,
4749
)
4850
maybe_add_test_execution_info(providers, ctx)
51+
py_test_toolchain = ctx.exec_groups["test"].toolchains[_PY_TEST_TOOLCHAIN_TYPE]
52+
if not py_test_toolchain:
53+
return providers
54+
_ = providers.pop(0)
55+
test_providers = py_test_toolchain.py_test_info.get_runner.func(ctx, binary_info)
56+
providers.extend(test_providers)
4957
return providers
5058

5159
py_test = create_executable_rule(
5260
implementation = _py_test_impl,
5361
attrs = dicts.add(AGNOSTIC_TEST_ATTRS, _BAZEL_PY_TEST_ATTRS),
5462
test = True,
63+
exec_groups = {
64+
"test": exec_group(toolchains = [config_common.toolchain_type(_PY_TEST_TOOLCHAIN_TYPE, mandatory = False)]),
65+
},
5566
)

0 commit comments

Comments
 (0)