@@ -30,6 +30,7 @@ load(":hub_repository.bzl", "hub_repository", "whl_config_settings_to_json")
3030load (":parse_requirements.bzl" , "parse_requirements" )
3131load (":parse_whl_name.bzl" , "parse_whl_name" )
3232load (":pep508_env.bzl" , "env" )
33+ load (":pep508_evaluate.bzl" , "evaluate" )
3334load (":pip_repository_attrs.bzl" , "ATTRS" )
3435load (":python_tag.bzl" , "python_tag" )
3536load (":requirements_files_by_platform.bzl" , "requirements_files_by_platform" )
@@ -80,21 +81,27 @@ def _platforms(*, python_version, minor_mapping, config):
8081 for platform , values in config .platforms .items ():
8182 # TODO @aignas 2025-07-07: this is probably doing the parsing of the version too
8283 # many times.
83- key = "{}{}{}.{}_ {}" .format (
84+ abi = "{}{}{}.{}" .format (
8485 python_tag (values .env ["implementation_name" ]),
8586 python_version .release [0 ],
8687 python_version .release [1 ],
8788 python_version .release [2 ],
88- platform ,
8989 )
90+ key = "{}_{}" .format (abi , platform )
91+
92+ env_ = env (
93+ env = values .env ,
94+ os = values .os_name ,
95+ arch = values .arch_name ,
96+ python_version = python_version .string ,
97+ )
98+
99+ if values .marker and not evaluate (values .marker , env = env_ ):
100+ continue
90101
91102 platforms [key ] = struct (
92- env = env (
93- env = values .env ,
94- os = values .os_name ,
95- arch = values .arch_name ,
96- python_version = python_version .string ,
97- ),
103+ env = env_ ,
104+ triple = "{}_{}_{}" .format (abi , values .os_name , values .arch_name ),
98105 whl_abi_tags = [
99106 v .format (
100107 major = python_version .release [0 ],
@@ -203,17 +210,19 @@ def _create_whl_repos(
203210 whl_group_mapping = {}
204211 requirement_cycles = {}
205212
213+ platforms = _platforms (
214+ python_version = pip_attr .python_version ,
215+ minor_mapping = minor_mapping ,
216+ config = config ,
217+ )
218+
206219 if evaluate_markers :
207220 # This is most likely unit tests
208221 pass
209222 elif config .enable_pipstar :
210223 evaluate_markers = lambda _ , requirements : evaluate_markers_star (
211224 requirements = requirements ,
212- platforms = _platforms (
213- python_version = pip_attr .python_version ,
214- minor_mapping = minor_mapping ,
215- config = config ,
216- ),
225+ platforms = platforms ,
217226 )
218227 else :
219228 # NOTE @aignas 2024-08-02: , we will execute any interpreter that we find either
@@ -232,7 +241,14 @@ def _create_whl_repos(
232241 # spin up a Python interpreter.
233242 evaluate_markers = lambda module_ctx , requirements : evaluate_markers_py (
234243 module_ctx ,
235- requirements = requirements ,
244+ requirements = {
245+ k : {
246+ # TODO @aignas 2025-07-06: should we leave this as is?
247+ p : platforms [p ].triple
248+ for p in plats
249+ }
250+ for k , plats in requirements .items ()
251+ },
236252 python_interpreter = pip_attr .python_interpreter ,
237253 python_interpreter_target = python_interpreter_target ,
238254 srcs = pip_attr ._evaluate_markers_srcs ,
@@ -248,18 +264,14 @@ def _create_whl_repos(
248264 requirements_osx = pip_attr .requirements_darwin ,
249265 requirements_windows = pip_attr .requirements_windows ,
250266 extra_pip_args = pip_attr .extra_pip_args ,
251- platforms = sorted (config . platforms ), # here we only need keys
267+ platforms = sorted (platforms ), # here we only need keys
252268 python_version = full_version (
253269 version = pip_attr .python_version ,
254270 minor_mapping = minor_mapping ,
255271 ),
256272 logger = logger ,
257273 ),
258- platforms = _platforms (
259- python_version = pip_attr .python_version ,
260- minor_mapping = minor_mapping ,
261- config = config ,
262- ),
274+ platforms = platforms ,
263275 extra_pip_args = pip_attr .extra_pip_args ,
264276 get_index_urls = get_index_urls ,
265277 evaluate_markers = evaluate_markers ,
@@ -346,6 +358,16 @@ def _create_whl_repos(
346358 ))
347359
348360 whl_libraries [repo_name ] = repo .args
361+ if "experimental_target_platforms" in repo .args :
362+ whl_libraries [repo_name ] |= {
363+ "experimental_target_platforms" : sorted ({
364+ # TODO @aignas 2025-07-07: this should be solved in a better way
365+ platforms [candidate ].triple .partition ("_" )[- 1 ]: None
366+ for p in repo .args ["experimental_target_platforms" ]
367+ for candidate in platforms
368+ if candidate .endswith (p )
369+ }),
370+ }
349371 whl_map .setdefault (whl .name , {})[repo .config_setting ] = repo_name
350372
351373 return struct (
@@ -434,14 +456,15 @@ def _configure(
434456 arch_name ,
435457 config_settings ,
436458 env = {},
459+ marker ,
437460 whl_abi_tags ,
438461 whl_platform_tags ,
439462 override = False ):
440463 """Set the value in the config if the value is provided"""
441464 config .setdefault ("platforms" , {})
442465
443466 if platform and (
444- os_name or arch_name or config_settings or whl_abi_tags or whl_platform_tags or env
467+ os_name or arch_name or config_settings or whl_abi_tags or whl_platform_tags or env or marker
445468 ):
446469 if not override and config ["platforms" ].get (platform ):
447470 return
@@ -455,6 +478,7 @@ def _configure(
455478 "arch_name" : arch_name ,
456479 "config_settings" : config_settings ,
457480 "env" : env ,
481+ "marker" : marker ,
458482 "name" : platform .replace ("-" , "_" ).lower (),
459483 "os_name" : os_name ,
460484 "whl_abi_tags" : whl_abi_tags ,
@@ -470,7 +494,7 @@ def _configure(
470494 else :
471495 config ["platforms" ].pop (platform )
472496
473- def _plat (* , name , arch_name , os_name , config_settings = [], env = {}, whl_abi_tags = [], whl_platform_tags = []):
497+ def _plat (* , name , arch_name , os_name , config_settings = [], env = {}, marker = "" , whl_abi_tags = [], whl_platform_tags = []):
474498 # NOTE @aignas 2025-07-08: the least preferred is the first item in the list
475499 if "any" not in whl_platform_tags :
476500 # the lowest priority one needs to be the first one
@@ -490,6 +514,7 @@ def _plat(*, name, arch_name, os_name, config_settings = [], env = {}, whl_abi_t
490514 # defaults for env
491515 "implementation_name" : "cpython" ,
492516 } | env ,
517+ marker = marker ,
493518 whl_abi_tags = whl_abi_tags ,
494519 whl_platform_tags = whl_platform_tags ,
495520 )
@@ -524,6 +549,7 @@ def build_config(
524549 config_settings = tag .config_settings ,
525550 env = tag .env ,
526551 os_name = tag .os_name ,
552+ marker = tag .marker ,
527553 platform = platform ,
528554 override = mod .is_root ,
529555 whl_abi_tags = tag .whl_abi_tags ,
@@ -533,8 +559,6 @@ def build_config(
533559 # attribute.
534560 # * for index/downloader config. This includes all of those attributes for
535561 # overrides, etc. Index overrides per platform could be also used here.
536- # * for whl selection - selecting preferences of which `platform_tag`s we should use
537- # for what. We could also model the `cp313t` freethreaded as separate platforms.
538562 )
539563
540564 return struct (
@@ -918,6 +942,12 @@ Supported keys:
918942::::{note}
919943This is only used if the {envvar}`RULES_PYTHON_ENABLE_PIPSTAR` is enabled.
920944::::
945+ """ ,
946+ ),
947+ "marker" : attr .string (
948+ doc = """\
949+ A marker which will be evaluated to disable the target platform for certain python versions. This
950+ is especially useful when defining freethreaded platform variants.
921951""" ,
922952 ),
923953 # The values for PEP508 env marker evaluation during the lock file parsing
0 commit comments