1616
1717load ("@bazel_features//:features.bzl" , "bazel_features" )
1818load ("//python:repositories.bzl" , "python_register_toolchains" )
19+ load ("//python:versions.bzl" , "TOOL_VERSIONS" )
1920load (":pythons_hub.bzl" , "hub_repo" )
2021load (":text_util.bzl" , "render" )
2122load (":toolchains_repo.bzl" , "multi_toolchain_aliases" )
@@ -78,7 +79,9 @@ def _python_impl(module_ctx):
7879 for mod in module_ctx .modules :
7980 module_toolchain_versions = []
8081
81- for toolchain_attr in mod .tags .toolchain :
82+ toolchain_attr_structs = _create_toolchain_attr_structs (mod )
83+
84+ for toolchain_attr in toolchain_attr_structs :
8285 toolchain_version = toolchain_attr .python_version
8386 toolchain_name = "python_" + toolchain_version .replace ("." , "_" )
8487
@@ -95,9 +98,7 @@ def _python_impl(module_ctx):
9598 # * rules_python needs to set a soft default in case the root module doesn't,
9699 # e.g. if the root module doesn't use Python itself.
97100 # * The root module is allowed to override the rules_python default.
98-
99- # A single toolchain is treated as the default because it's unambiguous.
100- is_default = toolchain_attr .is_default or len (mod .tags .toolchain ) == 1
101+ is_default = toolchain_attr .is_default
101102
102103 # Also only the root module should be able to decide ignore_root_user_error.
103104 # Modules being depended upon don't know the final environment, so they aren't
@@ -251,6 +252,43 @@ def _fail_multiple_default_toolchains(first, second):
251252 second = second ,
252253 ))
253254
255+ def _create_toolchain_attr_structs (mod ):
256+ arg_structs = []
257+ seen_versions = {}
258+ for tag in mod .tags .toolchain :
259+ arg_structs .append (_create_toolchain_attrs_struct (tag = tag , toolchain_tag_count = len (mod .tags .toolchain )))
260+ seen_versions [tag .python_version ] = True
261+
262+ if mod .is_root :
263+ register_all = False
264+ for tag in mod .tags .rules_python_private_testing :
265+ if tag .register_all_versions :
266+ register_all = True
267+ break
268+ if register_all :
269+ arg_structs .extend ([
270+ _create_toolchain_attrs_struct (python_version = v )
271+ for v in TOOL_VERSIONS .keys ()
272+ if v not in seen_versions
273+ ])
274+ return arg_structs
275+
276+ def _create_toolchain_attrs_struct (* , tag = None , python_version = None , toolchain_tag_count = None ):
277+ if tag and python_version :
278+ fail ("Only one of tag and python version can be specified" )
279+ if tag :
280+ # A single toolchain is treated as the default because it's unambiguous.
281+ is_default = tag .is_default or toolchain_tag_count == 1
282+ else :
283+ is_default = False
284+
285+ return struct (
286+ is_default = is_default ,
287+ python_version = python_version if python_version else tag .python_version ,
288+ configure_coverage_tool = getattr (tag , "configure_coverage_tool" , False ),
289+ ignore_root_user_error = getattr (tag , "ignore_root_user_error" , False ),
290+ )
291+
254292def _get_bazel_version_specific_kwargs ():
255293 kwargs = {}
256294
@@ -264,6 +302,11 @@ python = module_extension(
264302""" ,
265303 implementation = _python_impl ,
266304 tag_classes = {
305+ "rules_python_private_testing" : tag_class (
306+ attrs = {
307+ "register_all_versions" : attr .bool (default = False ),
308+ },
309+ ),
267310 "toolchain" : tag_class (
268311 doc = """Tag class used to register Python toolchains.
269312Use this tag class to register one or more Python toolchains. This class
0 commit comments