fix(pip): set better defaults for the new target_platforms attr (#3447)

Fixup the default values for the `target_platforms` so that the
users can actually switch it as per docs.

I have also taken the liberty to update all of the tests to better
reflect how we set things up for legacy and index-url setups. As
it is now, legacy `bzlmod` whl_library layout is much more similar
to WORKSPACE, which makes the transition easier.

Work towards #2949
diff --git a/MODULE.bazel b/MODULE.bazel
index b909124..ef7499e 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -305,6 +305,11 @@
         parallel_download = False,
         python_version = python_version,
         requirements_lock = "//docs:requirements.txt",
+        # Ensure that we are setting up the following platforms
+        target_platforms = [
+            "{os}_{arch}",
+            "{os}_{arch}_freethreaded",
+        ],
     )
     for python_version in [
         "3.9",
diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel
index d7748d3..55d8f75 100644
--- a/docs/BUILD.bazel
+++ b/docs/BUILD.bazel
@@ -165,6 +165,8 @@
     config_settings = {
         labels.BOOTSTRAP_IMPL: "script",
         labels.VENVS_SITE_PACKAGES: "yes",
+        labels.PY_FREETHREADED: "yes",
+        labels.PYTHON_VERSION: "3.14",
     },
     target_compatible_with = _TARGET_COMPATIBLE_WITH,
     deps = [
diff --git a/python/private/pypi/extension.bzl b/python/private/pypi/extension.bzl
index 2a6d43f..3d7985a 100644
--- a/python/private/pypi/extension.bzl
+++ b/python/private/pypi/extension.bzl
@@ -665,7 +665,7 @@
 """,
         ),
         "target_platforms": attr.string_list(
-            default = ["{os}_{arch}"],
+            default = [],
             doc = """\
 The list of platforms for which we would evaluate the requirements files. If you need to be able to
 only evaluate for a particular platform (e.g. "linux_x86_64"), then put it in here.
diff --git a/python/private/pypi/hub_builder.bzl b/python/private/pypi/hub_builder.bzl
index 3a1a3b0..97e0a11 100644
--- a/python/private/pypi/hub_builder.bzl
+++ b/python/private/pypi/hub_builder.bzl
@@ -141,9 +141,10 @@
         module_ctx,
         python_version = full_python_version,
         config = self._config,
-        # FIXME @aignas 2025-12-06: should we have this behaviour?
-        # TODO @aignas 2025-12-06: use target_platforms always even when the get_index_urls is set.
-        target_platforms = [] if default_cross_setup else pip_attr.target_platforms,
+        # TODO @aignas 2025-12-09: flip or part to default to 'os_arch' after
+        # VERSION_NEXT_FEATURE is released and set the default of the `target_platforms` attribute
+        # to `{os}_{arch}`.
+        target_platforms = pip_attr.target_platforms or ([] if default_cross_setup else ["{os}_{arch}"]),
     )
     _add_group_map(self, pip_attr.experimental_requirement_cycles)
     _add_extra_aliases(self, pip_attr.extra_hub_aliases)
diff --git a/python/private/pypi/requirements_files_by_platform.bzl b/python/private/pypi/requirements_files_by_platform.bzl
index 2027b41..c0fc93a 100644
--- a/python/private/pypi/requirements_files_by_platform.bzl
+++ b/python/private/pypi/requirements_files_by_platform.bzl
@@ -144,6 +144,8 @@
 
     input_platforms = platforms
     default_platforms = [_platform(p, python_version) for p in platforms]
+    if logger:
+        logger.debug(lambda: "Input platforms: {}".format(input_platforms))
 
     if platforms_from_args:
         lock_files = [
diff --git a/tests/pypi/extension/extension_tests.bzl b/tests/pypi/extension/extension_tests.bzl
index b1e363b..924796c 100644
--- a/tests/pypi/extension/extension_tests.bzl
+++ b/tests/pypi/extension/extension_tests.bzl
@@ -22,12 +22,12 @@
 
 _tests = []
 
-def _mock_mctx(*modules, environ = {}, read = None):
+def _mock_mctx(*modules, os_name = "unittest", arch_name = "exotic", environ = {}, read = None):
     return struct(
         os = struct(
             environ = environ,
-            name = "unittest",
-            arch = "exotic",
+            name = os_name,
+            arch = arch_name,
         ),
         read = read or (lambda _: """\
 simple==0.0.1 \
@@ -148,6 +148,8 @@
                     ),
                 ],
             ),
+            os_name = "linux",
+            arch_name = "x86_64",
         ),
         available_interpreters = {
             "python_3_15_host": "unit_test_interpreter_target",
diff --git a/tests/pypi/hub_builder/hub_builder_tests.bzl b/tests/pypi/hub_builder/hub_builder_tests.bzl
index e267f4c..bf21dca 100644
--- a/tests/pypi/hub_builder/hub_builder_tests.bzl
+++ b/tests/pypi/hub_builder/hub_builder_tests.bzl
@@ -25,12 +25,12 @@
 
 _tests = []
 
-def _mock_mctx(os = "unittest", arch = "exotic", environ = {}, read = None):
+def _mock_mctx(os_name = "unittest", arch_name = "exotic", environ = {}, read = None):
     return struct(
         os = struct(
             environ = environ,
-            name = os,
-            arch = arch,
+            name = os_name,
+            arch = arch_name,
         ),
         read = read or (lambda _: """\
 simple==0.0.1 \
@@ -114,7 +114,10 @@
 def _test_simple(env):
     builder = hub_builder(env)
     builder.pip_parse(
-        _mock_mctx(),
+        _mock_mctx(
+            os_name = "osx",
+            arch_name = "aarch64",
+        ),
         _parse(
             hub_name = "pypi",
             python_version = "3.15",
@@ -147,118 +150,94 @@
 _tests.append(_test_simple)
 
 def _test_simple_multiple_requirements(env):
-    builder = hub_builder(env)
-    builder.pip_parse(
-        _mock_mctx(
-            read = lambda x: {
-                "darwin.txt": "simple==0.0.2 --hash=sha256:deadb00f",
-                "win.txt": "simple==0.0.1 --hash=sha256:deadbeef",
-            }[x],
-        ),
-        _parse(
-            hub_name = "pypi",
-            python_version = "3.15",
-            requirements_darwin = "darwin.txt",
-            requirements_windows = "win.txt",
-        ),
-    )
-    pypi = builder.build()
+    sub_tests = {
+        ("osx", "aarch64"): "simple==0.0.2 --hash=sha256:deadb00f",
+        ("windows", "aarch64"): "simple==0.0.1 --hash=sha256:deadbeef",
+    }
+    for (host_os, host_arch), want_requirement in sub_tests.items():
+        builder = hub_builder(env)
+        builder.pip_parse(
+            _mock_mctx(
+                read = lambda x: {
+                    "darwin.txt": "simple==0.0.2 --hash=sha256:deadb00f",
+                    "win.txt": "simple==0.0.1 --hash=sha256:deadbeef",
+                }[x],
+                os_name = host_os,
+                arch_name = host_arch,
+            ),
+            _parse(
+                hub_name = "pypi",
+                python_version = "3.15",
+                requirements_darwin = "darwin.txt",
+                requirements_windows = "win.txt",
+            ),
+        )
+        pypi = builder.build()
 
-    pypi.exposed_packages().contains_exactly(["simple"])
-    pypi.group_map().contains_exactly({})
-    pypi.whl_map().contains_exactly({
-        "simple": {
-            "pypi_315_simple_osx_aarch64": [
-                whl_config_setting(
-                    target_platforms = [
-                        "cp315_osx_aarch64",
-                    ],
-                    version = "3.15",
-                ),
-            ],
-            "pypi_315_simple_windows_aarch64": [
-                whl_config_setting(
-                    target_platforms = [
-                        "cp315_windows_aarch64",
-                    ],
-                    version = "3.15",
-                ),
-            ],
-        },
-    })
-    pypi.whl_libraries().contains_exactly({
-        "pypi_315_simple_osx_aarch64": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "simple==0.0.2 --hash=sha256:deadb00f",
-        },
-        "pypi_315_simple_windows_aarch64": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "simple==0.0.1 --hash=sha256:deadbeef",
-        },
-    })
-    pypi.extra_aliases().contains_exactly({})
+        pypi.exposed_packages().contains_exactly(["simple"])
+        pypi.group_map().contains_exactly({})
+        pypi.whl_map().contains_exactly({
+            "simple": {
+                "pypi_315_simple": [
+                    whl_config_setting(version = "3.15"),
+                ],
+            },
+        })
+        pypi.whl_libraries().contains_exactly({
+            "pypi_315_simple": {
+                "config_load": "@pypi//:config.bzl",
+                "dep_template": "@pypi//{name}:{target}",
+                "python_interpreter_target": "unit_test_interpreter_target",
+                "requirement": want_requirement,
+            },
+        })
+        pypi.extra_aliases().contains_exactly({})
 
 _tests.append(_test_simple_multiple_requirements)
 
 def _test_simple_extras_vs_no_extras(env):
-    builder = hub_builder(env)
-    builder.pip_parse(
-        _mock_mctx(
-            read = lambda x: {
-                "darwin.txt": "simple[foo]==0.0.1 --hash=sha256:deadbeef",
-                "win.txt": "simple==0.0.1 --hash=sha256:deadbeef",
-            }[x],
-        ),
-        _parse(
-            hub_name = "pypi",
-            python_version = "3.15",
-            requirements_darwin = "darwin.txt",
-            requirements_windows = "win.txt",
-        ),
-    )
-    pypi = builder.build()
+    sub_tests = {
+        ("osx", "aarch64"): "simple[foo]==0.0.1 --hash=sha256:deadbeef",
+        ("windows", "aarch64"): "simple==0.0.1 --hash=sha256:deadbeef",
+    }
+    for (host_os, host_arch), want_requirement in sub_tests.items():
+        builder = hub_builder(env)
+        builder.pip_parse(
+            _mock_mctx(
+                read = lambda x: {
+                    "darwin.txt": "simple[foo]==0.0.1 --hash=sha256:deadbeef",
+                    "win.txt": "simple==0.0.1 --hash=sha256:deadbeef",
+                }[x],
+                os_name = host_os,
+                arch_name = host_arch,
+            ),
+            _parse(
+                hub_name = "pypi",
+                python_version = "3.15",
+                requirements_darwin = "darwin.txt",
+                requirements_windows = "win.txt",
+            ),
+        )
+        pypi = builder.build()
 
-    pypi.exposed_packages().contains_exactly(["simple"])
-    pypi.group_map().contains_exactly({})
-    pypi.whl_map().contains_exactly({
-        "simple": {
-            "pypi_315_simple_osx_aarch64": [
-                whl_config_setting(
-                    target_platforms = [
-                        "cp315_osx_aarch64",
-                    ],
-                    version = "3.15",
-                ),
-            ],
-            "pypi_315_simple_windows_aarch64": [
-                whl_config_setting(
-                    target_platforms = [
-                        "cp315_windows_aarch64",
-                    ],
-                    version = "3.15",
-                ),
-            ],
-        },
-    })
-    pypi.whl_libraries().contains_exactly({
-        "pypi_315_simple_osx_aarch64": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "simple[foo]==0.0.1 --hash=sha256:deadbeef",
-        },
-        "pypi_315_simple_windows_aarch64": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "simple==0.0.1 --hash=sha256:deadbeef",
-        },
-    })
-    pypi.extra_aliases().contains_exactly({})
+        pypi.exposed_packages().contains_exactly(["simple"])
+        pypi.group_map().contains_exactly({})
+        pypi.whl_map().contains_exactly({
+            "simple": {
+                "pypi_315_simple": [
+                    whl_config_setting(version = "3.15"),
+                ],
+            },
+        })
+        pypi.whl_libraries().contains_exactly({
+            "pypi_315_simple": {
+                "config_load": "@pypi//:config.bzl",
+                "dep_template": "@pypi//{name}:{target}",
+                "python_interpreter_target": "unit_test_interpreter_target",
+                "requirement": want_requirement,
+            },
+        })
+        pypi.extra_aliases().contains_exactly({})
 
 _tests.append(_test_simple_extras_vs_no_extras)
 
@@ -358,6 +337,8 @@
 old-package==0.0.1 --hash=sha256:deadbaaf
 """,
             }[x],
+            os_name = "linux",
+            arch_name = "amd64",
         ),
         _parse(
             hub_name = "pypi",
@@ -373,6 +354,8 @@
 new-package==0.0.1 --hash=sha256:deadb00f2
 """,
             }[x],
+            os_name = "linux",
+            arch_name = "amd64",
         ),
         _parse(
             hub_name = "pypi",
@@ -387,28 +370,20 @@
     pypi.whl_map().contains_exactly({
         "new_package": {
             "pypi_316_new_package": [
-                whl_config_setting(
-                    version = "3.16",
-                ),
+                whl_config_setting(version = "3.16"),
             ],
         },
         "old_package": {
             "pypi_315_old_package": [
-                whl_config_setting(
-                    version = "3.15",
-                ),
+                whl_config_setting(version = "3.15"),
             ],
         },
         "simple": {
             "pypi_315_simple": [
-                whl_config_setting(
-                    version = "3.15",
-                ),
+                whl_config_setting(version = "3.15"),
             ],
             "pypi_316_simple": [
-                whl_config_setting(
-                    version = "3.16",
-                ),
+                whl_config_setting(version = "3.16"),
             ],
         },
     })
@@ -443,75 +418,62 @@
 _tests.append(_test_simple_multiple_python_versions)
 
 def _test_simple_with_markers(env):
-    builder = hub_builder(
-        env,
-        evaluate_markers_fn = lambda _, requirements, **__: {
-            key: [
-                platform
-                for platform in platforms
-                if ("x86_64" in platform and "platform_machine ==" in key) or ("x86_64" not in platform and "platform_machine !=" in key)
-            ]
-            for key, platforms in requirements.items()
-        },
-    )
-    builder.pip_parse(
-        _mock_mctx(
-            read = lambda x: {
-                "universal.txt": """\
-torch==2.4.1+cpu ; platform_machine == 'x86_64'
-torch==2.4.1 ; platform_machine != 'x86_64' \
-    --hash=sha256:deadbeef
-""",
-            }[x],
-        ),
-        _parse(
-            hub_name = "pypi",
-            python_version = "3.15",
-            requirements_lock = "universal.txt",
-        ),
-    )
-    pypi = builder.build()
+    sub_tests = {
+        ("osx", "aarch64"): "torch==2.4.1 --hash=sha256:deadbeef",
+        ("linux", "x86_64"): "torch==2.4.1+cpu",
+    }
+    for (host_os, host_arch), want_requirement in sub_tests.items():
+        builder = hub_builder(
+            env,
+            evaluate_markers_fn = lambda _, requirements, **__: {
+                key: [
+                    platform
+                    for platform in platforms
+                    if ("x86_64" in platform and "platform_machine ==" in key) or ("x86_64" not in platform and "platform_machine !=" in key)
+                ]
+                for key, platforms in requirements.items()
+            },
+        )
+        builder.pip_parse(
+            _mock_mctx(
+                read = lambda x: {
+                    "universal.txt": """\
+    torch==2.4.1+cpu ; platform_machine == 'x86_64'
+    torch==2.4.1 ; platform_machine != 'x86_64' \
+        --hash=sha256:deadbeef
+    """,
+                }[x],
+                os_name = host_os,
+                arch_name = host_arch,
+            ),
+            _parse(
+                hub_name = "pypi",
+                python_version = "3.15",
+                requirements_lock = "universal.txt",
+            ),
+        )
+        pypi = builder.build()
 
-    pypi.exposed_packages().contains_exactly(["torch"])
-    pypi.group_map().contains_exactly({})
-    pypi.whl_map().contains_exactly({
-        "torch": {
-            "pypi_315_torch_linux_aarch64_osx_aarch64_windows_aarch64": [
-                whl_config_setting(
-                    target_platforms = [
-                        "cp315_linux_aarch64",
-                        "cp315_osx_aarch64",
-                        "cp315_windows_aarch64",
-                    ],
-                    version = "3.15",
-                ),
-            ],
-            "pypi_315_torch_linux_x86_64_linux_x86_64_freethreaded": [
-                whl_config_setting(
-                    target_platforms = [
-                        "cp315_linux_x86_64",
-                        "cp315_linux_x86_64_freethreaded",
-                    ],
-                    version = "3.15",
-                ),
-            ],
-        },
-    })
-    pypi.whl_libraries().contains_exactly({
-        "pypi_315_torch_linux_aarch64_osx_aarch64_windows_aarch64": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "torch==2.4.1 --hash=sha256:deadbeef",
-        },
-        "pypi_315_torch_linux_x86_64_linux_x86_64_freethreaded": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "torch==2.4.1+cpu",
-        },
-    })
-    pypi.extra_aliases().contains_exactly({})
+        pypi.exposed_packages().contains_exactly(["torch"])
+        pypi.group_map().contains_exactly({})
+        pypi.whl_map().contains_exactly({
+            "torch": {
+                "pypi_315_torch": [
+                    whl_config_setting(
+                        version = "3.15",
+                    ),
+                ],
+            },
+        })
+        pypi.whl_libraries().contains_exactly({
+            "pypi_315_torch": {
+                "config_load": "@pypi//:config.bzl",
+                "dep_template": "@pypi//{name}:{target}",
+                "python_interpreter_target": "unit_test_interpreter_target",
+                "requirement": want_requirement,
+            },
+        })
+        pypi.extra_aliases().contains_exactly({})
 
 _tests.append(_test_simple_with_markers)
 
@@ -1079,66 +1041,51 @@
 _tests.append(_test_simple_get_index)
 
 def _test_optimum_sys_platform_extra(env):
-    builder = hub_builder(
-        env,
-    )
-    builder.pip_parse(
-        _mock_mctx(
-            read = lambda x: {
-                "universal.txt": """\
+    sub_tests = {
+        ("osx", "aarch64"): "optimum[onnxruntime]==1.17.1",
+        ("linux", "aarch64"): "optimum[onnxruntime-gpu]==1.17.1",
+    }
+    for (host_os, host_arch), want_requirement in sub_tests.items():
+        builder = hub_builder(
+            env,
+        )
+        builder.pip_parse(
+            _mock_mctx(
+                read = lambda x: {
+                    "universal.txt": """\
 optimum[onnxruntime]==1.17.1 ; sys_platform == 'darwin'
 optimum[onnxruntime-gpu]==1.17.1 ; sys_platform == 'linux'
 """,
-            }[x],
-        ),
-        _parse(
-            hub_name = "pypi",
-            python_version = "3.15",
-            requirements_lock = "universal.txt",
-        ),
-    )
-    pypi = builder.build()
+                }[x],
+                os_name = host_os,
+                arch_name = host_arch,
+            ),
+            _parse(
+                hub_name = "pypi",
+                python_version = "3.15",
+                requirements_lock = "universal.txt",
+            ),
+        )
+        pypi = builder.build()
 
-    # FIXME @aignas 2025-09-07: we should expose the `optimum` package
-    pypi.exposed_packages().contains_exactly([])
-    pypi.group_map().contains_exactly({})
-    pypi.whl_map().contains_exactly({
-        "optimum": {
-            "pypi_315_optimum_linux_aarch64_linux_x86_64_linux_x86_64_freethreaded": [
-                whl_config_setting(
-                    version = "3.15",
-                    target_platforms = [
-                        "cp315_linux_aarch64",
-                        "cp315_linux_x86_64",
-                        "cp315_linux_x86_64_freethreaded",
-                    ],
-                ),
-            ],
-            "pypi_315_optimum_osx_aarch64": [
-                whl_config_setting(
-                    version = "3.15",
-                    target_platforms = [
-                        "cp315_osx_aarch64",
-                    ],
-                ),
-            ],
-        },
-    })
-    pypi.whl_libraries().contains_exactly({
-        "pypi_315_optimum_linux_aarch64_linux_x86_64_linux_x86_64_freethreaded": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "optimum[onnxruntime-gpu]==1.17.1",
-        },
-        "pypi_315_optimum_osx_aarch64": {
-            "config_load": "@pypi//:config.bzl",
-            "dep_template": "@pypi//{name}:{target}",
-            "python_interpreter_target": "unit_test_interpreter_target",
-            "requirement": "optimum[onnxruntime]==1.17.1",
-        },
-    })
-    pypi.extra_aliases().contains_exactly({})
+        pypi.exposed_packages().contains_exactly(["optimum"])
+        pypi.group_map().contains_exactly({})
+        pypi.whl_map().contains_exactly({
+            "optimum": {
+                "pypi_315_optimum": [
+                    whl_config_setting(version = "3.15"),
+                ],
+            },
+        })
+        pypi.whl_libraries().contains_exactly({
+            "pypi_315_optimum": {
+                "config_load": "@pypi//:config.bzl",
+                "dep_template": "@pypi//{name}:{target}",
+                "python_interpreter_target": "unit_test_interpreter_target",
+                "requirement": want_requirement,
+            },
+        })
+        pypi.extra_aliases().contains_exactly({})
 
 _tests.append(_test_optimum_sys_platform_extra)
 
@@ -1181,6 +1128,7 @@
             hub_name = "pypi",
             python_version = "3.15",
             requirements_lock = "universal.txt",
+            target_platforms = ["mylinuxx86_64", "myosxaarch64"],
         ),
     )
     pypi = builder.build()
@@ -1253,8 +1201,8 @@
     )
     builder.pip_parse(
         _mock_mctx(
-            os = "linux",
-            arch = "amd64",
+            os_name = "linux",
+            arch_name = "amd64",
             read = lambda x: {
                 "universal.txt": """\
 optimum[onnxruntime]==1.17.1 ; sys_platform == 'darwin'