Skip to content

Commit 2b56f94

Browse files
committed
feat(pypi): incrementally build platform configuration
Before this PR the configuration for platforms would be built non-incrementally, making it harder for users to override particular attributes of the already configured ones. With this PR the new features introduced in bazel-contrib#3058 will be easier to override. Work towards bazel-contrib#2747
1 parent bc788d5 commit 2b56f94

File tree

2 files changed

+128
-36
lines changed

2 files changed

+128
-36
lines changed

python/private/pypi/extension.bzl

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -379,24 +379,90 @@ def _whl_repo(*, src, whl_library_args, is_multiple_versions, download_only, net
379379
def _configure(config, *, platform, os_name, arch_name, config_settings, env = {}, override = False):
380380
"""Set the value in the config if the value is provided"""
381381
config.setdefault("platforms", {})
382-
if platform:
382+
if platform and (os_name or arch_name or config_settings or env):
383383
if not override and config.get("platforms", {}).get(platform):
384384
return
385385

386386
for key in env:
387387
if key not in _SUPPORTED_PEP508_KEYS:
388388
fail("Unsupported key in the PEP508 environment: {}".format(key))
389389

390-
config["platforms"][platform] = struct(
391-
name = platform.replace("-", "_").lower(),
392-
os_name = os_name,
393-
arch_name = arch_name,
394-
config_settings = config_settings,
395-
env = env,
396-
)
390+
config["platforms"].setdefault(platform, {})
391+
for key, value in {
392+
"arch_name": arch_name,
393+
"config_settings": config_settings,
394+
"env": env,
395+
"name": platform.replace("-", "_").lower(),
396+
"os_name": os_name,
397+
}.items():
398+
if not value:
399+
continue
400+
401+
if not override and config.get(key):
402+
continue
403+
404+
config["platforms"][platform][key] = value
397405
else:
398406
config["platforms"].pop(platform)
399407

408+
def _plat(*, name, arch_name, os_name, config_settings = [], env = {}):
409+
return struct(
410+
name = name,
411+
arch_name = arch_name,
412+
os_name = os_name,
413+
config_settings = config_settings,
414+
env = env,
415+
)
416+
417+
def build_config(
418+
*,
419+
module_ctx,
420+
enable_pipstar):
421+
"""Parse 'configure' and 'default' extension tags
422+
423+
Args:
424+
module_ctx: {type}`module_ctx` module context.
425+
enable_pipstar: {type}`bool` a flag to enable dropping Python dependency for
426+
evaluation of the extension.
427+
428+
Returns:
429+
A struct with the configuration.
430+
"""
431+
defaults = {
432+
"platforms": {},
433+
}
434+
for mod in module_ctx.modules:
435+
if not (mod.is_root or mod.name == "rules_python"):
436+
continue
437+
438+
platform = None
439+
for tag in mod.tags.default:
440+
platform = tag.platform or platform
441+
_configure(
442+
defaults,
443+
arch_name = tag.arch_name,
444+
config_settings = tag.config_settings,
445+
env = tag.env,
446+
os_name = tag.os_name,
447+
platform = platform,
448+
override = mod.is_root,
449+
# TODO @aignas 2025-05-19: add more attr groups:
450+
# * for AUTH - the default `netrc` usage could be configured through a common
451+
# attribute.
452+
# * for index/downloader config. This includes all of those attributes for
453+
# overrides, etc. Index overrides per platform could be also used here.
454+
# * for whl selection - selecting preferences of which `platform_tag`s we should use
455+
# for what. We could also model the `cp313t` freethreaded as separate platforms.
456+
)
457+
458+
return struct(
459+
platforms = {
460+
name: _plat(**values)
461+
for name, values in defaults["platforms"].items()
462+
},
463+
enable_pipstar = enable_pipstar,
464+
)
465+
400466
def parse_modules(
401467
module_ctx,
402468
_fail = fail,
@@ -447,33 +513,7 @@ You cannot use both the additive_build_content and additive_build_content_file a
447513
srcs_exclude_glob = whl_mod.srcs_exclude_glob,
448514
)
449515

450-
defaults = {
451-
"enable_pipstar": enable_pipstar,
452-
"platforms": {},
453-
}
454-
for mod in module_ctx.modules:
455-
if not (mod.is_root or mod.name == "rules_python"):
456-
continue
457-
458-
for tag in mod.tags.default:
459-
_configure(
460-
defaults,
461-
arch_name = tag.arch_name,
462-
config_settings = tag.config_settings,
463-
env = tag.env,
464-
os_name = tag.os_name,
465-
platform = tag.platform,
466-
override = mod.is_root,
467-
# TODO @aignas 2025-05-19: add more attr groups:
468-
# * for AUTH - the default `netrc` usage could be configured through a common
469-
# attribute.
470-
# * for index/downloader config. This includes all of those attributes for
471-
# overrides, etc. Index overrides per platform could be also used here.
472-
# * for whl selection - selecting preferences of which `platform_tag`s we should use
473-
# for what. We could also model the `cp313t` freethreaded as separate platforms.
474-
)
475-
476-
config = struct(**defaults)
516+
config = build_config(module_ctx = module_ctx, enable_pipstar = enable_pipstar)
477517

478518
# TODO @aignas 2025-06-03: Merge override API with the builder?
479519
_overriden_whl_set = {}
@@ -658,6 +698,7 @@ You cannot use both the additive_build_content and additive_build_content_file a
658698
k: dict(sorted(args.items()))
659699
for k, args in sorted(whl_libraries.items())
660700
},
701+
config = config,
661702
)
662703

663704
def _pip_impl(module_ctx):

tests/pypi/extension/extension_tests.bzl

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
load("@rules_testing//lib:test_suite.bzl", "test_suite")
1818
load("@rules_testing//lib:truth.bzl", "subjects")
19-
load("//python/private/pypi:extension.bzl", "parse_modules") # buildifier: disable=bzl-visibility
19+
load("//python/private/pypi:extension.bzl", "build_config", "parse_modules") # buildifier: disable=bzl-visibility
2020
load("//python/private/pypi:parse_simpleapi_html.bzl", "parse_simpleapi_html") # buildifier: disable=bzl-visibility
2121
load("//python/private/pypi:whl_config_setting.bzl", "whl_config_setting") # buildifier: disable=bzl-visibility
2222

@@ -92,6 +92,18 @@ def _parse_modules(env, enable_pipstar = 0, **kwargs):
9292
),
9393
)
9494

95+
def _build_config(env, enable_pipstar = 0, **kwargs):
96+
return env.expect.that_struct(
97+
build_config(
98+
enable_pipstar = enable_pipstar,
99+
**kwargs
100+
),
101+
attrs = dict(
102+
platforms = subjects.dict,
103+
enable_pipstar = subjects.bool,
104+
),
105+
)
106+
95107
def _default(
96108
arch_name = None,
97109
config_settings = None,
@@ -1206,6 +1218,45 @@ optimum[onnxruntime-gpu]==1.17.1 ; sys_platform == 'linux'
12061218

12071219
_tests.append(_test_pipstar_platforms)
12081220

1221+
def _test_build_pipstar_platform(env):
1222+
config = _build_config(
1223+
env,
1224+
module_ctx = _mock_mctx(
1225+
_mod(
1226+
name = "rules_python",
1227+
default = [
1228+
_default(
1229+
platform = "myplat",
1230+
os_name = "linux",
1231+
arch_name = "x86_64",
1232+
),
1233+
_default(
1234+
config_settings = [
1235+
"@platforms//os:linux",
1236+
"@platforms//cpu:x86_64",
1237+
],
1238+
),
1239+
],
1240+
),
1241+
),
1242+
enable_pipstar = True,
1243+
)
1244+
config.enable_pipstar().equals(True)
1245+
config.platforms().contains_exactly({
1246+
"myplat": struct(
1247+
name = "myplat",
1248+
os_name = "linux",
1249+
arch_name = "x86_64",
1250+
config_settings = [
1251+
"@platforms//os:linux",
1252+
"@platforms//cpu:x86_64",
1253+
],
1254+
env = {},
1255+
),
1256+
})
1257+
1258+
_tests.append(_test_build_pipstar_platform)
1259+
12091260
def extension_test_suite(name):
12101261
"""Create the test suite.
12111262

0 commit comments

Comments
 (0)