Skip to content

Commit 0354257

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 9792058 commit 0354257

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
@@ -380,24 +380,90 @@ def _whl_repo(*, src, whl_library_args, is_multiple_versions, download_only, net
380380
def _configure(config, *, platform, os_name, arch_name, config_settings, env = {}, override = False):
381381
"""Set the value in the config if the value is provided"""
382382
config.setdefault("platforms", {})
383-
if platform:
383+
if platform and (os_name or arch_name or config_settings or env):
384384
if not override and config.get("platforms", {}).get(platform):
385385
return
386386

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

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

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

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

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

664705
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)