@@ -43,31 +43,33 @@ def _left_pad_zero(index, length):
4343def _print_warn (msg ):
4444 print ("WARNING:" , msg )
4545
46- def _python_register_toolchains (name , toolchain_attr , version_constraint ):
46+ def _python_register_toolchains (name , toolchain_attr , module ):
4747 """Calls python_register_toolchains and returns a struct used to collect the toolchains.
4848 """
4949 python_register_toolchains (
5050 name = name ,
5151 python_version = toolchain_attr .python_version ,
5252 register_coverage_tool = toolchain_attr .configure_coverage_tool ,
5353 ignore_root_user_error = toolchain_attr .ignore_root_user_error ,
54- set_python_version_constraint = version_constraint ,
5554 )
5655 return struct (
5756 python_version = toolchain_attr .python_version ,
58- set_python_version_constraint = str (version_constraint ),
5957 name = name ,
58+ module = struct (name = module .name , is_root = module .is_root ),
6059 )
6160
6261def _python_impl (module_ctx ):
63- # The toolchain info structs to register, in the order to register them in.
62+ # The toolchain_info structs to register, in the order to register them in.
63+ # NOTE: The last element is special: it is treated as the default toolchain,
64+ # so there is special handling to ensure the last entry is the correct one.
6465 toolchains = []
6566
6667 # We store the default toolchain separately to ensure it is the last
6768 # toolchain added to toolchains.
69+ # This is a toolchain_info struct.
6870 default_toolchain = None
6971
70- # Map of string Major.Minor to the toolchain name and module name
72+ # Map of string Major.Minor to the toolchain_info struct
7173 global_toolchain_versions = {}
7274
7375 for mod in module_ctx .modules :
@@ -82,28 +84,6 @@ def _python_impl(module_ctx):
8284 _fail_duplicate_module_toolchain_version (toolchain_version , mod .name )
8385 module_toolchain_versions .append (toolchain_version )
8486
85- # Ignore version collisions in the global scope because there isn't
86- # much else that can be done. Modules don't know and can't control
87- # what other modules do, so the first in the dependency graph wins.
88- if toolchain_version in global_toolchain_versions :
89- # If the python version is explicitly provided by the root
90- # module, they should not be warned for choosing the same
91- # version that rules_python provides as default.
92- first = global_toolchain_versions [toolchain_version ]
93- if mod .name != "rules_python" or not first .is_root :
94- _warn_duplicate_global_toolchain_version (
95- toolchain_version ,
96- first = first ,
97- second_toolchain_name = toolchain_name ,
98- second_module_name = mod .name ,
99- )
100- continue
101- global_toolchain_versions [toolchain_version ] = struct (
102- toolchain_name = toolchain_name ,
103- module_name = mod .name ,
104- is_root = mod .is_root ,
105- )
106-
10787 # Only the root module and rules_python are allowed to specify the default
10888 # toolchain for a couple reasons:
10989 # * It prevents submodules from specifying different defaults and only
@@ -121,29 +101,60 @@ def _python_impl(module_ctx):
121101 else :
122102 is_default = False
123103
124- # We have already found one default toolchain, and we can only have
125- # one.
126104 if is_default and default_toolchain != None :
127105 _fail_multiple_default_toolchains (
128106 first = default_toolchain .name ,
129107 second = toolchain_name ,
130108 )
131109
132- toolchain_info = _python_register_toolchains (
133- toolchain_name ,
134- toolchain_attr ,
135- version_constraint = not is_default ,
136- )
110+ # Ignore version collisions in the global scope because there isn't
111+ # much else that can be done. Modules don't know and can't control
112+ # what other modules do, so the first in the dependency graph wins.
113+ if toolchain_version in global_toolchain_versions :
114+ # If the python version is explicitly provided by the root
115+ # module, they should not be warned for choosing the same
116+ # version that rules_python provides as default.
117+ first = global_toolchain_versions [toolchain_version ]
118+ if mod .name != "rules_python" or not first .module .is_root :
119+ _warn_duplicate_global_toolchain_version (
120+ toolchain_version ,
121+ first = first ,
122+ second_toolchain_name = toolchain_name ,
123+ second_module_name = mod .name ,
124+ )
125+ toolchain_info = None
126+ else :
127+ toolchain_info = _python_register_toolchains (
128+ toolchain_name ,
129+ toolchain_attr ,
130+ module = mod ,
131+ )
132+ global_toolchain_versions [toolchain_version ] = toolchain_info
137133
138134 if is_default :
139- default_toolchain = toolchain_info
140- else :
135+ # This toolchain is setting the default, but the actual
136+ # registration was performed previously, by a different module.
137+ if toolchain_info == None :
138+ default_toolchain = global_toolchain_versions [toolchain_version ]
139+
140+ # Remove it because later code will add it at the end to
141+ # ensure it is last in the list.
142+ toolchains .remove (default_toolchain )
143+ else :
144+ default_toolchain = toolchain_info
145+ elif toolchain_info :
141146 toolchains .append (toolchain_info )
142147
143148 # A default toolchain is required so that the non-version-specific rules
144149 # are able to match a toolchain.
145150 if default_toolchain == None :
146151 fail ("No default Python toolchain configured. Is rules_python missing `is_default=True`?" )
152+ elif default_toolchain .python_version not in global_toolchain_versions :
153+ fail ('Default version "{python_version}" selected by module ' +
154+ '"{module_name}", but no toolchain with that version registered' .format (
155+ python_version = default_toolchain .python_version ,
156+ module_name = default_toolchain .module .name ,
157+ ))
147158
148159 # The last toolchain in the BUILD file is set as the default
149160 # toolchain. We need the default last.
@@ -162,7 +173,12 @@ def _python_impl(module_ctx):
162173 for index , toolchain in enumerate (toolchains )
163174 ],
164175 toolchain_python_versions = [t .python_version for t in toolchains ],
165- toolchain_set_python_version_constraints = [t .set_python_version_constraint for t in toolchains ],
176+ # The last toolchain is the default; it can't have version constraints
177+ # Despite the implication of the arg name, the values are strs, not bools
178+ toolchain_set_python_version_constraints = [
179+ "True" if i != len (toolchains ) - 1 else "False"
180+ for i in range (len (toolchains ))
181+ ],
166182 toolchain_user_repository_names = [t .name for t in toolchains ],
167183 )
168184
@@ -171,8 +187,8 @@ def _python_impl(module_ctx):
171187 multi_toolchain_aliases (
172188 name = "python_versions" ,
173189 python_versions = {
174- version : entry . toolchain_name
175- for version , entry in global_toolchain_versions .items ()
190+ version : toolchain . name
191+ for version , toolchain in global_toolchain_versions .items ()
176192 },
177193 )
178194
@@ -189,8 +205,8 @@ def _warn_duplicate_global_toolchain_version(version, first, second_toolchain_na
189205 "Toolchain '{first_toolchain}' from module '{first_module}' " +
190206 "already registered Python version {version} and has precedence"
191207 ).format (
192- first_toolchain = first .toolchain_name ,
193- first_module = first .module_name ,
208+ first_toolchain = first .name ,
209+ first_module = first .module . name ,
194210 second_module = second_module_name ,
195211 second_toolchain = second_toolchain_name ,
196212 version = version ,
0 commit comments