feat(pypi): pip.defaults API for customizing pipstar 1/n (#2987)

Parse env markers in pip.parse using starlark

Summary:
- Allow switching to the Starlark implementation of the marker
  evaluation function.
- Add a way for users to modify the `env` for the marker evaluation when
  parsing the requirements. This can only be done by `rules_python` or
  the root module.
- Limit the platform selection when parsing the requirements files.

Work towards #2747
Work towards #2949
Split out from #2909

---------

Co-authored-by: Richard Levasseur <richardlev@gmail.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf3d25c..9897dc9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -62,7 +62,9 @@
 
 {#v0-0-0-added}
 ### Added
-* Nothing added.
+* (pypi) To configure the environment for `requirements.txt` evaluation, use the newly added
+  developer preview of the `pip.default` tag class. Only `rules_python` and root modules can use
+  this feature.
 
 {#v0-0-0-removed}
 ### Removed
diff --git a/python/private/pypi/BUILD.bazel b/python/private/pypi/BUILD.bazel
index d89dc6c..b569b22 100644
--- a/python/private/pypi/BUILD.bazel
+++ b/python/private/pypi/BUILD.bazel
@@ -97,10 +97,10 @@
     name = "evaluate_markers_bzl",
     srcs = ["evaluate_markers.bzl"],
     deps = [
-        ":pep508_env_bzl",
+        ":deps_bzl",
         ":pep508_evaluate_bzl",
-        ":pep508_platform_bzl",
         ":pep508_requirement_bzl",
+        ":pypi_repo_utils_bzl",
     ],
 )
 
@@ -113,6 +113,7 @@
         ":hub_repository_bzl",
         ":parse_requirements_bzl",
         ":parse_whl_name_bzl",
+        ":pep508_env_bzl",
         ":pip_repository_attrs_bzl",
         ":simpleapi_download_bzl",
         ":whl_config_setting_bzl",
diff --git a/python/private/pypi/env_marker_info.bzl b/python/private/pypi/env_marker_info.bzl
index c3c5ec6..37eefb2 100644
--- a/python/private/pypi/env_marker_info.bzl
+++ b/python/private/pypi/env_marker_info.bzl
@@ -17,7 +17,7 @@
 The values to use for environment markers when evaluating an expression.
 
 The keys and values should be compatible with the [PyPA dependency specifiers
-specification](https://packaging.python.org/en/latest/specifications/dependency-specifiers/)
+specification](https://packaging.python.org/en/latest/specifications/dependency-specifiers/).
 
 Missing values will be set to the specification's defaults or computed using
 available toolchain information.
diff --git a/python/private/pypi/evaluate_markers.bzl b/python/private/pypi/evaluate_markers.bzl
index 1919335..58a29a9 100644
--- a/python/private/pypi/evaluate_markers.bzl
+++ b/python/private/pypi/evaluate_markers.bzl
@@ -15,9 +15,7 @@
 """A simple function that evaluates markers using a python interpreter."""
 
 load(":deps.bzl", "record_files")
-load(":pep508_env.bzl", "env")
 load(":pep508_evaluate.bzl", "evaluate")
-load(":pep508_platform.bzl", "platform_from_str")
 load(":pep508_requirement.bzl", "requirement")
 load(":pypi_repo_utils.bzl", "pypi_repo_utils")
 
@@ -30,22 +28,27 @@
     Label("//python/private/pypi/whl_installer:platform.py"),
 ]
 
-def evaluate_markers(requirements, python_version = None):
+def evaluate_markers(*, requirements, platforms):
     """Return the list of supported platforms per requirements line.
 
     Args:
         requirements: {type}`dict[str, list[str]]` of the requirement file lines to evaluate.
-        python_version: {type}`str | None` the version that can be used when evaluating the markers.
+        platforms: {type}`dict[str, dict[str, str]]` The environments that we for each requirement
+            file to evaluate. The keys between the platforms and requirements should be shared.
 
     Returns:
         dict of string lists with target platforms
     """
     ret = {}
-    for req_string, platforms in requirements.items():
+    for req_string, platform_strings in requirements.items():
         req = requirement(req_string)
-        for platform in platforms:
-            if evaluate(req.marker, env = env(platform_from_str(platform, python_version))):
-                ret.setdefault(req_string, []).append(platform)
+        for platform_str in platform_strings:
+            env = platforms.get(platform_str)
+            if not env:
+                fail("Please define platform: '{}'".format(platform_str))
+
+            if evaluate(req.marker, env = env):
+                ret.setdefault(req_string, []).append(platform_str)
 
     return ret
 
diff --git a/python/private/pypi/extension.bzl b/python/private/pypi/extension.bzl
index 867abe0..97b6825 100644
--- a/python/private/pypi/extension.bzl
+++ b/python/private/pypi/extension.bzl
@@ -25,10 +25,11 @@
 load("//python/private:version.bzl", "version")
 load("//python/private:version_label.bzl", "version_label")
 load(":attrs.bzl", "use_isolated")
-load(":evaluate_markers.bzl", "evaluate_markers_py", EVALUATE_MARKERS_SRCS = "SRCS")
+load(":evaluate_markers.bzl", "evaluate_markers_py", EVALUATE_MARKERS_SRCS = "SRCS", evaluate_markers_star = "evaluate_markers")
 load(":hub_repository.bzl", "hub_repository", "whl_config_settings_to_json")
 load(":parse_requirements.bzl", "parse_requirements")
 load(":parse_whl_name.bzl", "parse_whl_name")
+load(":pep508_env.bzl", "env")
 load(":pip_repository_attrs.bzl", "ATTRS")
 load(":requirements_files_by_platform.bzl", "requirements_files_by_platform")
 load(":simpleapi_download.bzl", "simpleapi_download")
@@ -65,22 +66,36 @@
             whl_mods = whl_mods,
         )
 
+def _platforms(*, python_version, minor_mapping, config):
+    platforms = {}
+    python_version = full_version(
+        version = python_version,
+        minor_mapping = minor_mapping,
+    )
+    abi = "cp3{}".format(python_version[2:])
+
+    for platform, values in config.platforms.items():
+        key = "{}_{}".format(abi, platform)
+        platforms[key] = env(key) | values.env
+    return platforms
+
 def _create_whl_repos(
         module_ctx,
         *,
         pip_attr,
         whl_overrides,
+        config,
         available_interpreters = INTERPRETER_LABELS,
         minor_mapping = MINOR_MAPPING,
-        evaluate_markers = evaluate_markers_py,
-        get_index_urls = None,
-        enable_pipstar = False):
+        evaluate_markers = None,
+        get_index_urls = None):
     """create all of the whl repositories
 
     Args:
         module_ctx: {type}`module_ctx`.
         pip_attr: {type}`struct` - the struct that comes from the tag class iteration.
         whl_overrides: {type}`dict[str, struct]` - per-wheel overrides.
+        config: The platform configuration.
         get_index_urls: A function used to get the index URLs
         available_interpreters: {type}`dict[str, Label]` The dictionary of available
             interpreters that have been registered using the `python` bzlmod extension.
@@ -89,7 +104,6 @@
         minor_mapping: {type}`dict[str, str]` The dictionary needed to resolve the full
             python version used to parse package METADATA files.
         evaluate_markers: the function used to evaluate the markers.
-        enable_pipstar: enable the pipstar feature.
 
     Returns a {type}`struct` with the following attributes:
         whl_map: {type}`dict[str, list[struct]]` the output is keyed by the
@@ -160,23 +174,19 @@
         whl_group_mapping = {}
         requirement_cycles = {}
 
-    requirements_by_platform = parse_requirements(
-        module_ctx,
-        requirements_by_platform = requirements_files_by_platform(
-            requirements_by_platform = pip_attr.requirements_by_platform,
-            requirements_linux = pip_attr.requirements_linux,
-            requirements_lock = pip_attr.requirements_lock,
-            requirements_osx = pip_attr.requirements_darwin,
-            requirements_windows = pip_attr.requirements_windows,
-            extra_pip_args = pip_attr.extra_pip_args,
-            python_version = full_version(
-                version = pip_attr.python_version,
+    if evaluate_markers:
+        # This is most likely unit tests
+        pass
+    elif config.enable_pipstar:
+        evaluate_markers = lambda _, requirements: evaluate_markers_star(
+            requirements = requirements,
+            platforms = _platforms(
+                python_version = pip_attr.python_version,
                 minor_mapping = minor_mapping,
+                config = config,
             ),
-            logger = logger,
-        ),
-        extra_pip_args = pip_attr.extra_pip_args,
-        get_index_urls = get_index_urls,
+        )
+    else:
         # NOTE @aignas 2024-08-02: , we will execute any interpreter that we find either
         # in the PATH or if specified as a label. We will configure the env
         # markers when evaluating the requirement lines based on the output
@@ -191,14 +201,34 @@
         # instances to perform this manipulation. This function should be executed
         # only once by the underlying code to minimize the overhead needed to
         # spin up a Python interpreter.
-        evaluate_markers = lambda module_ctx, requirements: evaluate_markers(
+        evaluate_markers = lambda module_ctx, requirements: evaluate_markers_py(
             module_ctx,
             requirements = requirements,
             python_interpreter = pip_attr.python_interpreter,
             python_interpreter_target = python_interpreter_target,
             srcs = pip_attr._evaluate_markers_srcs,
             logger = logger,
+        )
+
+    requirements_by_platform = parse_requirements(
+        module_ctx,
+        requirements_by_platform = requirements_files_by_platform(
+            requirements_by_platform = pip_attr.requirements_by_platform,
+            requirements_linux = pip_attr.requirements_linux,
+            requirements_lock = pip_attr.requirements_lock,
+            requirements_osx = pip_attr.requirements_darwin,
+            requirements_windows = pip_attr.requirements_windows,
+            extra_pip_args = pip_attr.extra_pip_args,
+            platforms = sorted(config.platforms),  # here we only need keys
+            python_version = full_version(
+                version = pip_attr.python_version,
+                minor_mapping = minor_mapping,
+            ),
+            logger = logger,
         ),
+        extra_pip_args = pip_attr.extra_pip_args,
+        get_index_urls = get_index_urls,
+        evaluate_markers = evaluate_markers,
         logger = logger,
     )
 
@@ -233,7 +263,7 @@
                 for p, args in whl_overrides.get(whl.name, {}).items()
             },
         )
-        if not enable_pipstar:
+        if not config.enable_pipstar:
             maybe_args["experimental_target_platforms"] = pip_attr.experimental_target_platforms
 
         whl_library_args.update({k: v for k, v in maybe_args.items() if v})
@@ -258,7 +288,7 @@
                 auth_patterns = pip_attr.auth_patterns,
                 python_version = major_minor,
                 is_multiple_versions = whl.is_multiple_versions,
-                enable_pipstar = enable_pipstar,
+                enable_pipstar = config.enable_pipstar,
             )
 
             repo_name = "{}_{}".format(pip_name, repo.repo_name)
@@ -342,16 +372,85 @@
         ),
     )
 
+def _configure(config, *, platform, os_name, arch_name, override = False, env = {}):
+    """Set the value in the config if the value is provided"""
+    config.setdefault("platforms", {})
+    if platform:
+        if not override and config.get("platforms", {}).get(platform):
+            return
+
+        for key in env:
+            if key not in _SUPPORTED_PEP508_KEYS:
+                fail("Unsupported key in the PEP508 environment: {}".format(key))
+
+        config["platforms"][platform] = struct(
+            name = platform.replace("-", "_").lower(),
+            os_name = os_name,
+            arch_name = arch_name,
+            env = env,
+        )
+    else:
+        config["platforms"].pop(platform)
+
+def _create_config(defaults):
+    if defaults["platforms"]:
+        return struct(**defaults)
+
+    # NOTE: We have this so that it is easier to maintain unit tests assuming certain
+    # defaults
+    for cpu in [
+        "x86_64",
+        "aarch64",
+        # TODO @aignas 2025-05-19: only leave tier 0-1 cpus when stabilizing the
+        # `pip.default` extension. i.e. drop the below values - users will have to
+        # define themselves if they need them.
+        "arm",
+        "ppc",
+        "s390x",
+    ]:
+        _configure(
+            defaults,
+            arch_name = cpu,
+            os_name = "linux",
+            platform = "linux_{}".format(cpu),
+            env = {"platform_version": "0"},
+        )
+    for cpu in [
+        "aarch64",
+        "x86_64",
+    ]:
+        _configure(
+            defaults,
+            arch_name = cpu,
+            # We choose the oldest non-EOL version at the time when we release `rules_python`.
+            # See https://endoflife.date/macos
+            env = {"platform_version": "14.0"},
+            os_name = "osx",
+            platform = "osx_{}".format(cpu),
+        )
+
+    _configure(
+        defaults,
+        arch_name = "x86_64",
+        env = {"platform_version": "0"},
+        os_name = "windows",
+        platform = "windows_x86_64",
+    )
+    return struct(**defaults)
+
 def parse_modules(
         module_ctx,
         _fail = fail,
         simpleapi_download = simpleapi_download,
+        enable_pipstar = False,
         **kwargs):
     """Implementation of parsing the tag classes for the extension and return a struct for registering repositories.
 
     Args:
         module_ctx: {type}`module_ctx` module context.
         simpleapi_download: Used for testing overrides
+        enable_pipstar: {type}`bool` a flag to enable dropping Python dependency for
+            evaluation of the extension.
         _fail: {type}`function` the failure function, mainly for testing.
         **kwargs: Extra arguments passed to the layers below.
 
@@ -389,6 +488,34 @@
                 srcs_exclude_glob = whl_mod.srcs_exclude_glob,
             )
 
+    defaults = {
+        "enable_pipstar": enable_pipstar,
+        "platforms": {},
+    }
+    for mod in module_ctx.modules:
+        if not (mod.is_root or mod.name == "rules_python"):
+            continue
+
+        for tag in mod.tags.default:
+            _configure(
+                defaults,
+                arch_name = tag.arch_name,
+                env = tag.env,
+                os_name = tag.os_name,
+                platform = tag.platform,
+                override = mod.is_root,
+                # TODO @aignas 2025-05-19: add more attr groups:
+                # * for AUTH - the default `netrc` usage could be configured through a common
+                # attribute.
+                # * for index/downloader config. This includes all of those attributes for
+                # overrides, etc. Index overrides per platform could be also used here.
+                # * for whl selection - selecting preferences of which `platform_tag`s we should use
+                # for what. We could also model the `cp313t` freethreaded as separate platforms.
+            )
+
+    config = _create_config(defaults)
+
+    # TODO @aignas 2025-06-03: Merge override API with the builder?
     _overriden_whl_set = {}
     whl_overrides = {}
     for module in module_ctx.modules:
@@ -498,11 +625,13 @@
             elif pip_attr.experimental_index_url_overrides:
                 fail("'experimental_index_url_overrides' is a no-op unless 'experimental_index_url' is set")
 
+            # TODO @aignas 2025-05-19: express pip.parse as a series of configure calls
             out = _create_whl_repos(
                 module_ctx,
                 pip_attr = pip_attr,
                 get_index_urls = get_index_urls,
                 whl_overrides = whl_overrides,
+                config = config,
                 **kwargs
             )
             hub_whl_map.setdefault(hub_name, {})
@@ -651,6 +780,72 @@
     else:
         return None
 
+_default_attrs = {
+    "arch_name": attr.string(
+        doc = """\
+The CPU architecture name to be used.
+
+:::{note}
+Either this or {attr}`env` `platform_machine` key should be specified.
+:::
+""",
+    ),
+    "os_name": attr.string(
+        doc = """\
+The OS name to be used.
+
+:::{note}
+Either this or the appropriate `env` keys should be specified.
+:::
+""",
+    ),
+    "platform": attr.string(
+        doc = """\
+A platform identifier which will be used as the unique identifier within the extension evaluation.
+If you are defining custom platforms in your project and don't want things to clash, use extension
+[isolation] feature.
+
+[isolation]: https://bazel.build/rules/lib/globals/module#use_extension.isolate
+""",
+    ),
+} | {
+    "env": attr.string_dict(
+        doc = """\
+The values to use for environment markers when evaluating an expression.
+
+The keys and values should be compatible with the [PyPA dependency specifiers
+specification](https://packaging.python.org/en/latest/specifications/dependency-specifiers/).
+
+Missing values will be set to the specification's defaults or computed using
+available toolchain information.
+
+Supported keys:
+* `implementation_name`, defaults to `cpython`.
+* `os_name`, defaults to a value inferred from the {attr}`os_name`.
+* `platform_machine`, defaults to a value inferred from the {attr}`arch_name`.
+* `platform_release`, defaults to an empty value.
+* `platform_system`, defaults to a value inferred from the {attr}`os_name`.
+* `platform_version`, defaults to `0`.
+* `sys_platform`, defaults to a value inferred from the {attr}`os_name`.
+
+::::{note}
+This is only used if the {envvar}`RULES_PYTHON_ENABLE_PIPSTAR` is enabled.
+::::
+""",
+    ),
+    # The values for PEP508 env marker evaluation during the lock file parsing
+}
+
+_SUPPORTED_PEP508_KEYS = [
+    "implementation_name",
+    "os_name",
+    "platform_machine",
+    "platform_release",
+    "platform_system",
+    "platform_version",
+    "sys_platform",
+]
+
 def _pip_parse_ext_attrs(**kwargs):
     """Get the attributes for the pip extension.
 
@@ -907,6 +1102,23 @@
 """,
     implementation = _pip_impl,
     tag_classes = {
+        "default": tag_class(
+            attrs = _default_attrs,
+            doc = """\
+This tag class allows for more customization of how the configuration for the hub repositories is built.
+
+
+:::{include} /_includes/experimtal_api.md
+:::
+
+:::{seealso}
+The [environment markers][environment_markers] specification for the explanation of the
+terms used in this extension.
+
+[environment_markers]: https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers
+:::
+""",
+        ),
         "override": _override_tag,
         "parse": tag_class(
             attrs = _pip_parse_ext_attrs(),
diff --git a/python/private/pypi/pep508_evaluate.bzl b/python/private/pypi/pep508_evaluate.bzl
index d4492a7..fe2cac9 100644
--- a/python/private/pypi/pep508_evaluate.bzl
+++ b/python/private/pypi/pep508_evaluate.bzl
@@ -117,7 +117,7 @@
 
     Args:
         marker: {type}`str` The string marker to evaluate.
-        env: {type}`dict` The environment to evaluate the marker against.
+        env: {type}`dict[str, str]` The environment to evaluate the marker against.
         strict: {type}`bool` A setting to not fail on missing values in the env.
         **kwargs: Extra kwargs to be passed to the expression evaluator.
 
diff --git a/python/private/pypi/pip_repository.bzl b/python/private/pypi/pip_repository.bzl
index 724fb6d..e63bd6c 100644
--- a/python/private/pypi/pip_repository.bzl
+++ b/python/private/pypi/pip_repository.bzl
@@ -80,6 +80,16 @@
             requirements_osx = rctx.attr.requirements_darwin,
             requirements_windows = rctx.attr.requirements_windows,
             extra_pip_args = rctx.attr.extra_pip_args,
+            platforms = [
+                "linux_aarch64",
+                "linux_arm",
+                "linux_ppc",
+                "linux_s390x",
+                "linux_x86_64",
+                "osx_aarch64",
+                "osx_x86_64",
+                "windows_x86_64",
+            ],
         ),
         extra_pip_args = rctx.attr.extra_pip_args,
         evaluate_markers = lambda rctx, requirements: evaluate_markers_py(
diff --git a/python/private/pypi/requirements_files_by_platform.bzl b/python/private/pypi/requirements_files_by_platform.bzl
index 9165c05..d8d3651 100644
--- a/python/private/pypi/requirements_files_by_platform.bzl
+++ b/python/private/pypi/requirements_files_by_platform.bzl
@@ -16,20 +16,7 @@
 
 load(":whl_target_platforms.bzl", "whl_target_platforms")
 
-# TODO @aignas 2024-05-13: consider using the same platform tags as are used in
-# the //python:versions.bzl
-DEFAULT_PLATFORMS = [
-    "linux_aarch64",
-    "linux_arm",
-    "linux_ppc",
-    "linux_s390x",
-    "linux_x86_64",
-    "osx_aarch64",
-    "osx_x86_64",
-    "windows_x86_64",
-]
-
-def _default_platforms(*, filter):
+def _default_platforms(*, filter, platforms):
     if not filter:
         fail("Must specific a filter string, got: {}".format(filter))
 
@@ -48,11 +35,13 @@
             fail("The filter can only contain '*' at the end of it")
 
         if not prefix:
-            return DEFAULT_PLATFORMS
+            return platforms
 
-        return [p for p in DEFAULT_PLATFORMS if p.startswith(prefix)]
+        match = [p for p in platforms if p.startswith(prefix)]
     else:
-        return [p for p in DEFAULT_PLATFORMS if filter in p]
+        match = [p for p in platforms if filter in p]
+
+    return match
 
 def _platforms_from_args(extra_pip_args):
     platform_values = []
@@ -105,6 +94,7 @@
         requirements_linux = None,
         requirements_lock = None,
         requirements_windows = None,
+        platforms,
         extra_pip_args = None,
         python_version = None,
         logger = None,
@@ -123,6 +113,8 @@
             be joined with args fined in files.
         python_version: str or None. This is needed when the get_index_urls is
             specified. It should be of the form "3.x.x",
+        platforms: {type}`list[str]` the list of human-friendly platform labels that should
+            be used for the evaluation.
         logger: repo_utils.logger or None, a simple struct to log diagnostic messages.
         fail_fn (Callable[[str], None]): A failure function used in testing failure cases.
 
@@ -144,11 +136,13 @@
         )
         return None
 
-    platforms = _platforms_from_args(extra_pip_args)
+    platforms_from_args = _platforms_from_args(extra_pip_args)
     if logger:
-        logger.debug(lambda: "Platforms from pip args: {}".format(platforms))
+        logger.debug(lambda: "Platforms from pip args: {}".format(platforms_from_args))
 
-    if platforms:
+    default_platforms = [_platform(p, python_version) for p in platforms]
+
+    if platforms_from_args:
         lock_files = [
             f
             for f in [
@@ -168,7 +162,7 @@
             return None
 
         files_by_platform = [
-            (lock_files[0], platforms),
+            (lock_files[0], platforms_from_args),
         ]
         if logger:
             logger.debug(lambda: "Files by platform with the platform set in the args: {}".format(files_by_platform))
@@ -177,7 +171,7 @@
             file: [
                 platform
                 for filter_or_platform in specifier.split(",")
-                for platform in (_default_platforms(filter = filter_or_platform) if filter_or_platform.endswith("*") else [filter_or_platform])
+                for platform in (_default_platforms(filter = filter_or_platform, platforms = platforms) if filter_or_platform.endswith("*") else [filter_or_platform])
             ]
             for file, specifier in requirements_by_platform.items()
         }.items()
@@ -188,9 +182,9 @@
         for f in [
             # If the users need a greater span of the platforms, they should consider
             # using the 'requirements_by_platform' attribute.
-            (requirements_linux, _default_platforms(filter = "linux_*")),
-            (requirements_osx, _default_platforms(filter = "osx_*")),
-            (requirements_windows, _default_platforms(filter = "windows_*")),
+            (requirements_linux, _default_platforms(filter = "linux_*", platforms = platforms)),
+            (requirements_osx, _default_platforms(filter = "osx_*", platforms = platforms)),
+            (requirements_windows, _default_platforms(filter = "windows_*", platforms = platforms)),
             (requirements_lock, None),
         ]:
             if f[0]:
@@ -215,8 +209,7 @@
                     return None
 
                 configured_platforms[p] = file
-        else:
-            default_platforms = [_platform(p, python_version) for p in DEFAULT_PLATFORMS]
+        elif plats == None:
             plats = [
                 p
                 for p in default_platforms
@@ -231,6 +224,13 @@
             for p in plats:
                 configured_platforms[p] = file
 
+        elif logger:
+            logger.warn(lambda: "File {} will be ignored because there are no configured platforms: {}".format(
+                file,
+                default_platforms,
+            ))
+            continue
+
         if logger:
             logger.debug(lambda: "Configured platforms for file {} are {}".format(file, plats))
 
diff --git a/tests/pypi/extension/extension_tests.bzl b/tests/pypi/extension/extension_tests.bzl
index 8e32572..3d205a2 100644
--- a/tests/pypi/extension/extension_tests.bzl
+++ b/tests/pypi/extension/extension_tests.bzl
@@ -49,23 +49,22 @@
         ],
     )
 
-def _mod(*, name, parse = [], override = [], whl_mods = [], is_root = True):
+def _mod(*, name, default = [], parse = [], override = [], whl_mods = [], is_root = True):
     return struct(
         name = name,
         tags = struct(
             parse = parse,
             override = override,
             whl_mods = whl_mods,
+            default = default,
         ),
         is_root = is_root,
     )
 
-def _parse_modules(env, **kwargs):
+def _parse_modules(env, enable_pipstar = 0, **kwargs):
     return env.expect.that_struct(
         parse_modules(
-            # TODO @aignas 2025-05-11: start integration testing the branch which
-            # includes this.
-            enable_pipstar = 0,
+            enable_pipstar = enable_pipstar,
             **kwargs
         ),
         attrs = dict(
@@ -77,6 +76,26 @@
         ),
     )
 
+def _default(
+        arch_name = None,
+        constraint_values = None,
+        os_name = None,
+        platform = None,
+        target_settings = None,
+        env = None,
+        whl_limit = None,
+        whl_platforms = None):
+    return struct(
+        arch_name = arch_name,
+        constraint_values = constraint_values,
+        os_name = os_name,
+        platform = platform,
+        target_settings = target_settings,
+        env = env or {},
+        whl_platforms = whl_platforms,
+        whl_limit = whl_limit,
+    )
+
 def _parse(
         *,
         hub_name,
@@ -1023,6 +1042,88 @@
 
 _tests.append(_test_optimum_sys_platform_extra)
 
+def _test_pipstar_platforms(env):
+    pypi = _parse_modules(
+        env,
+        module_ctx = _mock_mctx(
+            _mod(
+                name = "rules_python",
+                default = [
+                    _default(
+                        platform = "{}_{}".format(os, cpu),
+                    )
+                    for os, cpu in [
+                        ("linux", "x86_64"),
+                        ("osx", "aarch64"),
+                    ]
+                ],
+                parse = [
+                    _parse(
+                        hub_name = "pypi",
+                        python_version = "3.15",
+                        requirements_lock = "universal.txt",
+                    ),
+                ],
+            ),
+            read = lambda x: {
+                "universal.txt": """\
+optimum[onnxruntime]==1.17.1 ; sys_platform == 'darwin'
+optimum[onnxruntime-gpu]==1.17.1 ; sys_platform == 'linux'
+""",
+            }[x],
+        ),
+        enable_pipstar = True,
+        available_interpreters = {
+            "python_3_15_host": "unit_test_interpreter_target",
+        },
+        minor_mapping = {"3.15": "3.15.19"},
+    )
+
+    pypi.exposed_packages().contains_exactly({"pypi": ["optimum"]})
+    pypi.hub_group_map().contains_exactly({"pypi": {}})
+    pypi.hub_whl_map().contains_exactly({
+        "pypi": {
+            "optimum": {
+                "pypi_315_optimum_linux_x86_64": [
+                    whl_config_setting(
+                        version = "3.15",
+                        target_platforms = [
+                            "cp315_linux_x86_64",
+                        ],
+                        config_setting = None,
+                        filename = None,
+                    ),
+                ],
+                "pypi_315_optimum_osx_aarch64": [
+                    whl_config_setting(
+                        version = "3.15",
+                        target_platforms = [
+                            "cp315_osx_aarch64",
+                        ],
+                        config_setting = None,
+                        filename = None,
+                    ),
+                ],
+            },
+        },
+    })
+
+    pypi.whl_libraries().contains_exactly({
+        "pypi_315_optimum_linux_x86_64": {
+            "dep_template": "@pypi//{name}:{target}",
+            "python_interpreter_target": "unit_test_interpreter_target",
+            "requirement": "optimum[onnxruntime-gpu]==1.17.1",
+        },
+        "pypi_315_optimum_osx_aarch64": {
+            "dep_template": "@pypi//{name}:{target}",
+            "python_interpreter_target": "unit_test_interpreter_target",
+            "requirement": "optimum[onnxruntime]==1.17.1",
+        },
+    })
+    pypi.whl_mods().contains_exactly({})
+
+_tests.append(_test_pipstar_platforms)
+
 def extension_test_suite(name):
     """Create the test suite.
 
diff --git a/tests/pypi/requirements_files_by_platform/requirements_files_by_platform_tests.bzl b/tests/pypi/requirements_files_by_platform/requirements_files_by_platform_tests.bzl
index b729b0e..6688d72 100644
--- a/tests/pypi/requirements_files_by_platform/requirements_files_by_platform_tests.bzl
+++ b/tests/pypi/requirements_files_by_platform/requirements_files_by_platform_tests.bzl
@@ -15,10 +15,27 @@
 ""
 
 load("@rules_testing//lib:test_suite.bzl", "test_suite")
-load("//python/private/pypi:requirements_files_by_platform.bzl", "requirements_files_by_platform")  # buildifier: disable=bzl-visibility
+load("//python/private/pypi:requirements_files_by_platform.bzl", _sut = "requirements_files_by_platform")  # buildifier: disable=bzl-visibility
 
 _tests = []
 
+requirements_files_by_platform = lambda **kwargs: _sut(
+    platforms = kwargs.pop(
+        "platforms",
+        [
+            "linux_aarch64",
+            "linux_arm",
+            "linux_ppc",
+            "linux_s390x",
+            "linux_x86_64",
+            "osx_aarch64",
+            "osx_x86_64",
+            "windows_x86_64",
+        ],
+    ),
+    **kwargs
+)
+
 def _test_fail_no_requirements(env):
     errors = []
     requirements_files_by_platform(
@@ -86,6 +103,28 @@
 
 _tests.append(_test_simple)
 
+def _test_simple_limited(env):
+    for got in [
+        requirements_files_by_platform(
+            requirements_lock = "requirements_lock",
+            platforms = ["linux_x86_64", "osx_x86_64"],
+        ),
+        requirements_files_by_platform(
+            requirements_by_platform = {
+                "requirements_lock": "*",
+            },
+            platforms = ["linux_x86_64", "osx_x86_64"],
+        ),
+    ]:
+        env.expect.that_dict(got).contains_exactly({
+            "requirements_lock": [
+                "linux_x86_64",
+                "osx_x86_64",
+            ],
+        })
+
+_tests.append(_test_simple_limited)
+
 def _test_simple_with_python_version(env):
     for got in [
         requirements_files_by_platform(