@@ -30,6 +30,7 @@ load(":hub_repository.bzl", "hub_repository", "whl_config_settings_to_json")
30
30
load (":parse_requirements.bzl" , "parse_requirements" )
31
31
load (":parse_whl_name.bzl" , "parse_whl_name" )
32
32
load (":pep508_env.bzl" , "env" )
33
+ load (":pep508_evaluate.bzl" , "evaluate" )
33
34
load (":pip_repository_attrs.bzl" , "ATTRS" )
34
35
load (":requirements_files_by_platform.bzl" , "requirements_files_by_platform" )
35
36
load (":simpleapi_download.bzl" , "simpleapi_download" )
@@ -83,6 +84,10 @@ def _platforms(*, python_version, minor_mapping, config):
83
84
os = values .os_name ,
84
85
arch = values .arch_name ,
85
86
)) | values .env
87
+
88
+ if values .marker and not evaluate (values .marker , env = env_ ):
89
+ continue
90
+
86
91
platforms [key ] = struct (
87
92
env = env_ ,
88
93
want_abis = [
@@ -190,17 +195,19 @@ def _create_whl_repos(
190
195
whl_group_mapping = {}
191
196
requirement_cycles = {}
192
197
198
+ platforms = _platforms (
199
+ python_version = pip_attr .python_version ,
200
+ minor_mapping = minor_mapping ,
201
+ config = config ,
202
+ )
203
+
193
204
if evaluate_markers :
194
205
# This is most likely unit tests
195
206
pass
196
207
elif config .enable_pipstar :
197
208
evaluate_markers = lambda _ , requirements : evaluate_markers_star (
198
209
requirements = requirements ,
199
- platforms = _platforms (
200
- python_version = pip_attr .python_version ,
201
- minor_mapping = minor_mapping ,
202
- config = config ,
203
- ),
210
+ platforms = platforms ,
204
211
)
205
212
else :
206
213
# NOTE @aignas 2024-08-02: , we will execute any interpreter that we find either
@@ -235,18 +242,14 @@ def _create_whl_repos(
235
242
requirements_osx = pip_attr .requirements_darwin ,
236
243
requirements_windows = pip_attr .requirements_windows ,
237
244
extra_pip_args = pip_attr .extra_pip_args ,
238
- platforms = sorted (config . platforms ), # here we only need keys
245
+ platforms = sorted (platforms ), # here we only need keys
239
246
python_version = full_version (
240
247
version = pip_attr .python_version ,
241
248
minor_mapping = minor_mapping ,
242
249
),
243
250
logger = logger ,
244
251
),
245
- platforms = _platforms (
246
- python_version = pip_attr .python_version ,
247
- minor_mapping = minor_mapping ,
248
- config = config ,
249
- ),
252
+ platforms = platforms ,
250
253
extra_pip_args = pip_attr .extra_pip_args ,
251
254
get_index_urls = get_index_urls ,
252
255
evaluate_markers = evaluate_markers ,
@@ -385,7 +388,7 @@ def _whl_repo(*, src, whl_library_args, is_multiple_versions, download_only, net
385
388
),
386
389
)
387
390
388
- def _configure (config , * , platform , os_name , arch_name , config_settings , env = {}, want_abis , platform_tags , override = False ):
391
+ def _configure (config , * , platform , os_name , arch_name , config_settings , env = {}, want_abis , platform_tags , marker , override = False ):
389
392
"""Set the value in the config if the value is provided"""
390
393
config .setdefault ("platforms" , {})
391
394
if platform and (os_name or arch_name or config_settings or platform_tags or env ):
@@ -406,21 +409,25 @@ def _configure(config, *, platform, os_name, arch_name, config_settings, env = {
406
409
# the lowest priority one needs to be the first one
407
410
platform_tags = ["any" ] + platform_tags
408
411
412
+ want_abis = want_abis or [
413
+ "cp{0}{1}" ,
414
+ "abi3" ,
415
+ "none" ,
416
+ ]
417
+ env = {
418
+ # default to this
419
+ "implementation_name" : "cpython" ,
420
+ } | env
421
+
409
422
config ["platforms" ][platform ] = struct (
410
423
name = platform .replace ("-" , "_" ).lower (),
411
- os_name = os_name ,
412
424
arch_name = arch_name ,
413
425
config_settings = config_settings ,
414
- want_abis = want_abis or [
415
- "cp{0}{1}" ,
416
- "abi3" ,
417
- "none" ,
418
- ],
426
+ env = env ,
427
+ marker = marker ,
428
+ os_name = os_name ,
419
429
platform_tags = platform_tags ,
420
- env = {
421
- # default to this
422
- "implementation_name" : "cpython" ,
423
- } | env ,
430
+ want_abis = want_abis ,
424
431
)
425
432
else :
426
433
config ["platforms" ].pop (platform )
@@ -432,79 +439,106 @@ def _set_defaults(defaults):
432
439
a little problematic.
433
440
"""
434
441
435
- # NOTE: We have this so that it is easier to maintain unit tests assuming certain
436
- # defaults
437
- for cpu in [
438
- "x86_64" ,
439
- "aarch64" ,
440
- # TODO @aignas 2025-05-19: only leave tier 0-1 cpus when stabilizing the
441
- # `pip.default` extension. i.e. drop the below values - users will have to
442
- # define themselves if they need them.
443
- "arm" ,
444
- "ppc" ,
445
- "s390x" ,
446
- ]:
447
- _configure (
448
- defaults ,
449
- arch_name = cpu ,
450
- os_name = "linux" ,
451
- platform = "linux_{}" .format (cpu ),
452
- want_abis = [],
453
- config_settings = [
454
- "@platforms//os:linux" ,
455
- "@platforms//cpu:{}" .format (cpu ),
442
+ for suffix , config in {
443
+ "" : struct (
444
+ want_abis = [
445
+ "cp{0}{1}" ,
446
+ "abi3" ,
447
+ "none" ,
456
448
],
457
- platform_tags = [
458
- "linux_*_{}" .format (cpu ),
459
- "manylinux_*_{}" .format (cpu ),
449
+ freethreaded = "no" ,
450
+ marker = "" ,
451
+ ),
452
+ "_freethreaded" : struct (
453
+ want_abis = [
454
+ "cp{0}{1}t" ,
455
+ "none" ,
460
456
],
461
- env = {
462
- "platform_version" : "0" ,
463
- },
464
- )
465
- for cpu , platform_tag_cpus in {
466
- "aarch64" : ["universal2" , "arm64" ],
467
- "x86_64" : ["universal2" , "x86_64" ],
457
+ freethreaded = "yes" ,
458
+ marker = "python_version ~= \" 3.13\" " ,
459
+ ),
468
460
}.items ():
469
- _configure (
470
- defaults ,
471
- arch_name = cpu ,
472
- os_name = "osx" ,
473
- platform = "osx_{}" .format (cpu ),
474
- config_settings = [
475
- "@platforms//os:osx" ,
476
- "@platforms//cpu:{}" .format (cpu ),
477
- ],
478
- want_abis = [],
479
- platform_tags = [
480
- "macosx_*_{}" .format (suffix )
481
- for suffix in platform_tag_cpus
482
- ],
483
- # We choose the oldest non-EOL version at the time when we release `rules_python`.
484
- # See https://endoflife.date/macos
485
- env = {
486
- "platform_version" : "14.0" ,
487
- },
488
- )
461
+ freethreaded_flag = Label ("//python/config_settings:_is_py_freethreaded_{}" .format (config .freethreaded ))
462
+
463
+ # NOTE: We have this so that it is easier to maintain unit tests assuming certain
464
+ # defaults
465
+ for cpu in [
466
+ "x86_64" ,
467
+ "aarch64" ,
468
+ # TODO @aignas 2025-05-19: only leave tier 0-1 cpus when stabilizing the
469
+ # `pip.default` extension. i.e. drop the below values - users will have to
470
+ # define themselves if they need them.
471
+ "arm" ,
472
+ "ppc" ,
473
+ "s390x" ,
474
+ ]:
475
+ _configure (
476
+ defaults ,
477
+ arch_name = cpu ,
478
+ os_name = "linux" ,
479
+ platform = "linux_{}{}" .format (cpu , suffix ),
480
+ want_abis = config .want_abis ,
481
+ marker = config .marker ,
482
+ config_settings = [
483
+ "@platforms//os:linux" ,
484
+ "@platforms//cpu:{}" .format (cpu ),
485
+ freethreaded_flag ,
486
+ ],
487
+ platform_tags = [
488
+ "linux_*_{}" .format (cpu ),
489
+ "manylinux_*_{}" .format (cpu ),
490
+ ],
491
+ env = {
492
+ "platform_version" : "0" ,
493
+ },
494
+ )
495
+ for cpu , platform_tag_cpus in {
496
+ "aarch64" : ["universal2" , "arm64" ],
497
+ "x86_64" : ["universal2" , "x86_64" ],
498
+ }.items ():
499
+ _configure (
500
+ defaults ,
501
+ arch_name = cpu ,
502
+ os_name = "osx" ,
503
+ platform = "osx_{}{}" .format (cpu , suffix ),
504
+ config_settings = [
505
+ "@platforms//os:osx" ,
506
+ "@platforms//cpu:{}" .format (cpu ),
507
+ freethreaded_flag ,
508
+ ],
509
+ want_abis = config .want_abis ,
510
+ marker = config .marker ,
511
+ platform_tags = [
512
+ "macosx_*_{}" .format (suffix )
513
+ for suffix in platform_tag_cpus
514
+ ],
515
+ # We choose the oldest non-EOL version at the time when we release `rules_python`.
516
+ # See https://endoflife.date/macos
517
+ env = {
518
+ "platform_version" : "14.0" ,
519
+ },
520
+ )
489
521
490
- for cpu , platform_tags in {
491
- "x86_64" : ["win_amd64" ],
492
- }.items ():
493
- _configure (
494
- defaults ,
495
- arch_name = cpu ,
496
- os_name = "windows" ,
497
- platform = "windows_{}" .format (cpu ),
498
- config_settings = [
499
- "@platforms//os:windows" ,
500
- "@platforms//cpu:{}" .format (cpu ),
501
- ],
502
- want_abis = [],
503
- platform_tags = platform_tags ,
504
- env = {
505
- "platform_version" : "0" ,
506
- },
507
- )
522
+ for cpu , platform_tags in {
523
+ "x86_64" : ["win_amd64" ],
524
+ }.items ():
525
+ _configure (
526
+ defaults ,
527
+ arch_name = cpu ,
528
+ os_name = "windows" ,
529
+ platform = "windows_{}{}" .format (cpu , suffix ),
530
+ config_settings = [
531
+ "@platforms//os:windows" ,
532
+ "@platforms//cpu:{}" .format (cpu ),
533
+ freethreaded_flag ,
534
+ ],
535
+ want_abis = config .want_abis ,
536
+ marker = config .marker ,
537
+ platform_tags = platform_tags ,
538
+ env = {
539
+ "platform_version" : "0" ,
540
+ },
541
+ )
508
542
509
543
def parse_modules (
510
544
module_ctx ,
@@ -573,6 +607,7 @@ You cannot use both the additive_build_content and additive_build_content_file a
573
607
env = tag .env ,
574
608
os_name = tag .os_name ,
575
609
platform = tag .platform ,
610
+ marker = tag .marker ,
576
611
platform_tags = tag .platform_tags ,
577
612
want_abis = tag .want_abis ,
578
613
override = mod .is_root ,
@@ -905,6 +940,12 @@ Supported keys:
905
940
::::{note}
906
941
This is only used if the {envvar}`RULES_PYTHON_ENABLE_PIPSTAR` is enabled.
907
942
::::
943
+ """ ,
944
+ ),
945
+ "marker" : attr .string (
946
+ doc = """\
947
+ A marker which will be evaluated to disable the target platform for certain python versions. This
948
+ is especially useful when defining freethreaded platform variants.
908
949
""" ,
909
950
),
910
951
# The values for PEP508 env marker evaluation during the lock file parsing
0 commit comments