@@ -72,15 +72,25 @@ def _platforms(*, python_version, minor_mapping, config):
72
72
version = python_version ,
73
73
minor_mapping = minor_mapping ,
74
74
)
75
- abi = "cp3{}" .format (python_version [2 :])
76
75
77
76
for platform , values in config .platforms .items ():
77
+ implementation = values .env ["implementation_name" ][:2 ].lower ()
78
+ abi = "{}3{}" .format (implementation , python_version [2 :])
78
79
key = "{}_{}" .format (abi , platform )
79
- platforms [key ] = env (struct (
80
+
81
+ env_ = env (struct (
80
82
abi = abi ,
81
83
os = values .os_name ,
82
84
arch = values .arch_name ,
83
85
)) | values .env
86
+ platforms [key ] = struct (
87
+ env = env_ ,
88
+ want_abis = [
89
+ v .format (* python_version .split ("." ))
90
+ for v in values .want_abis
91
+ ],
92
+ platform_tags = values .platform_tags ,
93
+ )
84
94
return platforms
85
95
86
96
def _create_whl_repos (
@@ -152,6 +162,8 @@ def _create_whl_repos(
152
162
))
153
163
python_interpreter_target = available_interpreters [python_name ]
154
164
165
+ # TODO @aignas 2025-06-29: we should not need the version in the pip_name if
166
+ # we are using pipstar and we are downloading the wheel using the downloader
155
167
pip_name = "{}_{}" .format (
156
168
hub_name ,
157
169
version_label (pip_attr .python_version ),
@@ -184,11 +196,15 @@ def _create_whl_repos(
184
196
elif config .enable_pipstar :
185
197
evaluate_markers = lambda _ , requirements : evaluate_markers_star (
186
198
requirements = requirements ,
187
- platforms = _platforms (
188
- python_version = pip_attr .python_version ,
189
- minor_mapping = minor_mapping ,
190
- config = config ,
191
- ),
199
+ platforms = {
200
+ k : p .env
201
+ # TODO @aignas 2025-07-05: update evaluate_markers_star
202
+ for k , p in _platforms (
203
+ python_version = pip_attr .python_version ,
204
+ minor_mapping = minor_mapping ,
205
+ config = config ,
206
+ ).items ()
207
+ },
192
208
)
193
209
else :
194
210
# NOTE @aignas 2024-08-02: , we will execute any interpreter that we find either
@@ -230,6 +246,11 @@ def _create_whl_repos(
230
246
),
231
247
logger = logger ,
232
248
),
249
+ platforms = _platforms (
250
+ python_version = pip_attr .python_version ,
251
+ minor_mapping = minor_mapping ,
252
+ config = config ,
253
+ ),
233
254
extra_pip_args = pip_attr .extra_pip_args ,
234
255
get_index_urls = get_index_urls ,
235
256
evaluate_markers = evaluate_markers ,
@@ -359,24 +380,16 @@ def _whl_repo(*, src, whl_library_args, is_multiple_versions, download_only, net
359
380
for p in src .target_platforms
360
381
]
361
382
362
- # Pure python wheels or sdists may need to have a platform here
363
- target_platforms = None
364
- if is_whl and not src .filename .endswith ("-any.whl" ):
365
- pass
366
- elif is_multiple_versions :
367
- target_platforms = src .target_platforms
368
-
369
383
return struct (
370
384
repo_name = whl_repo_name (src .filename , src .sha256 ),
371
385
args = args ,
372
386
config_setting = whl_config_setting (
373
387
version = python_version ,
374
- filename = src .filename ,
375
- target_platforms = target_platforms ,
388
+ target_platforms = src .target_platforms ,
376
389
),
377
390
)
378
391
379
- def _configure (config , * , platform , os_name , arch_name , config_settings , env = {}, override = False ):
392
+ def _configure (config , * , platform , os_name , arch_name , config_settings , env = {}, want_abis , platform_tags , override = False ):
380
393
"""Set the value in the config if the value is provided"""
381
394
config .setdefault ("platforms" , {})
382
395
if platform :
@@ -393,12 +406,25 @@ def _configure(config, *, platform, os_name, arch_name, config_settings, env = {
393
406
if not arch_name :
394
407
fail ("'arch_name' is required" )
395
408
409
+ if platform_tags and "any" not in platform_tags :
410
+ # the lowest priority one needs to be the first one
411
+ platform_tags = ["any" ] + platform_tags
412
+
396
413
config ["platforms" ][platform ] = struct (
397
414
name = platform .replace ("-" , "_" ).lower (),
398
415
os_name = os_name ,
399
416
arch_name = arch_name ,
400
417
config_settings = config_settings ,
401
- env = env ,
418
+ want_abis = want_abis or [
419
+ "cp{0}{1}" ,
420
+ "abi3" ,
421
+ "none" ,
422
+ ],
423
+ platform_tags = platform_tags ,
424
+ env = {
425
+ # default to this
426
+ "implementation_name" : "cpython" ,
427
+ } | env ,
402
428
)
403
429
else :
404
430
config ["platforms" ].pop (platform )
@@ -424,28 +450,44 @@ def _create_config(defaults):
424
450
arch_name = cpu ,
425
451
os_name = "linux" ,
426
452
platform = "linux_{}" .format (cpu ),
453
+ # TODO @aignas 2025-07-05: handle the freethreaded by having separate
454
+ # platforms
455
+ want_abis = [],
427
456
config_settings = [
428
457
"@platforms//os:linux" ,
429
458
"@platforms//cpu:{}" .format (cpu ),
430
459
],
431
- env = {"platform_version" : "0" },
460
+ platform_tags = [
461
+ "linux_*_{}" .format (cpu ),
462
+ "manylinux_*_{}" .format (cpu ),
463
+ ],
464
+ env = {
465
+ "platform_version" : "0" ,
466
+ },
432
467
)
433
- for cpu in [
434
- "aarch64" ,
435
- "x86_64" ,
436
- ] :
468
+ for cpu , platform_tag_cpus in {
469
+ "aarch64" : [ "universal2" , "arm64" ] ,
470
+ "x86_64" : [ "universal2" , "x86_64" ] ,
471
+ }. items () :
437
472
_configure (
438
473
defaults ,
439
474
arch_name = cpu ,
440
- # We choose the oldest non-EOL version at the time when we release `rules_python`.
441
- # See https://endoflife.date/macos
442
475
os_name = "osx" ,
443
476
platform = "osx_{}" .format (cpu ),
444
477
config_settings = [
445
478
"@platforms//os:osx" ,
446
479
"@platforms//cpu:{}" .format (cpu ),
447
480
],
448
- env = {"platform_version" : "14.0" },
481
+ want_abis = [],
482
+ platform_tags = [
483
+ "macosx_*_{}" .format (suffix )
484
+ for suffix in platform_tag_cpus
485
+ ],
486
+ # We choose the oldest non-EOL version at the time when we release `rules_python`.
487
+ # See https://endoflife.date/macos
488
+ env = {
489
+ "platform_version" : "14.0" ,
490
+ },
449
491
)
450
492
451
493
_configure (
@@ -457,7 +499,11 @@ def _create_config(defaults):
457
499
"@platforms//os:windows" ,
458
500
"@platforms//cpu:x86_64" ,
459
501
],
460
- env = {"platform_version" : "0" },
502
+ want_abis = [],
503
+ platform_tags = ["win_amd64" ],
504
+ env = {
505
+ "platform_version" : "0" ,
506
+ },
461
507
)
462
508
return struct (** defaults )
463
509
@@ -527,14 +573,15 @@ You cannot use both the additive_build_content and additive_build_content_file a
527
573
env = tag .env ,
528
574
os_name = tag .os_name ,
529
575
platform = tag .platform ,
576
+ platform_tags = tag .platform_tags ,
577
+ want_abis = tag .want_abis ,
530
578
override = mod .is_root ,
531
579
# TODO @aignas 2025-05-19: add more attr groups:
532
580
# * for AUTH - the default `netrc` usage could be configured through a common
533
581
# attribute.
534
582
# * for index/downloader config. This includes all of those attributes for
535
583
# 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.
584
+ # * for whl selection - We could also model the `cp313t` freethreaded as separate platforms.
538
585
)
539
586
540
587
config = _create_config (defaults )
@@ -666,7 +713,14 @@ You cannot use both the additive_build_content and additive_build_content_file a
666
713
for whl_name , aliases in out .extra_aliases .items ():
667
714
extra_aliases [hub_name ].setdefault (whl_name , {}).update (aliases )
668
715
exposed_packages .setdefault (hub_name , {}).update (out .exposed_packages )
669
- whl_libraries .update (out .whl_libraries )
716
+ for whl_name , lib in out .whl_libraries .items ():
717
+ if enable_pipstar :
718
+ whl_libraries .setdefault (whl_name , lib )
719
+ elif whl_name in lib :
720
+ fail ("'{}' already in created" .format (whl_name ))
721
+ else :
722
+ # replicate whl_libraries.update(out.whl_libraries)
723
+ whl_libraries [whl_name ] = lib
670
724
671
725
# TODO @aignas 2024-04-05: how do we support different requirement
672
726
# cycles for different abis/oses? For now we will need the users to
@@ -829,25 +883,6 @@ The list of labels to `config_setting` targets that need to be matched for the p
829
883
selected.
830
884
""" ,
831
885
),
832
- "os_name" : attr .string (
833
- doc = """\
834
- The OS name to be used.
835
-
836
- :::{note}
837
- Either this or the appropriate `env` keys should be specified.
838
- :::
839
- """ ,
840
- ),
841
- "platform" : attr .string (
842
- doc = """\
843
- A platform identifier which will be used as the unique identifier within the extension evaluation.
844
- If you are defining custom platforms in your project and don't want things to clash, use extension
845
- [isolation] feature.
846
-
847
- [isolation]: https://bazel.build/rules/lib/globals/module#use_extension.isolate
848
- """ ,
849
- ),
850
- } | {
851
886
"env" : attr .string_dict (
852
887
doc = """\
853
888
The values to use for environment markers when evaluating an expression.
@@ -873,6 +908,40 @@ This is only used if the {envvar}`RULES_PYTHON_ENABLE_PIPSTAR` is enabled.
873
908
""" ,
874
909
),
875
910
# The values for PEP508 env marker evaluation during the lock file parsing
911
+ "os_name" : attr .string (
912
+ doc = """\
913
+ The OS name to be used.
914
+
915
+ :::{note}
916
+ Either this or the appropriate `env` keys should be specified.
917
+ :::
918
+ """ ,
919
+ ),
920
+ "platform" : attr .string (
921
+ doc = """\
922
+ A platform identifier which will be used as the unique identifier within the extension evaluation.
923
+ If you are defining custom platforms in your project and don't want things to clash, use extension
924
+ [isolation] feature.
925
+
926
+ [isolation]: https://bazel.build/rules/lib/globals/module#use_extension.isolate
927
+ """ ,
928
+ ),
929
+ "platform_tags" : attr .string_list (
930
+ doc = """\
931
+ A list of `platform_tag` matchers so that we can select the best wheel based on the user
932
+ preference. Per platform we will select a single wheel and the last match from this list will
933
+ take precedence.
934
+
935
+ The items in this list can contain a single `*` character that is equivalent to `.*` regex match.
936
+ """ ,
937
+ ),
938
+ "want_abis" : attr .string_list (
939
+ doc = """\
940
+ A list of ABIs to select wheels for. The values can be either strings or include template
941
+ parameters like `{0}` which will be replaced with python version parts. e.g. `cp{0}{1}` will
942
+ result in `cp313` given the full python version is `3.13.5`.
943
+ """ ,
944
+ ),
876
945
}
877
946
878
947
_SUPPORTED_PEP508_KEYS = [
0 commit comments