feat(pypi): implement a new whl selection algorithm (#3111)

This PR only implements the selection algorithm where instead of
selecting all wheels that are compatible with the set of target
platforms, we select a single wheel that is most specialized for a
particular single target platform.

What is more, compared to the existing algorithm it does not assume
a particular list of supported platforms and just fully implements the
spec.

Work towards #2747
Work towards #2759
Work towards #2849
diff --git a/python/private/pypi/BUILD.bazel b/python/private/pypi/BUILD.bazel
index 3a66170..4b56b73 100644
--- a/python/private/pypi/BUILD.bazel
+++ b/python/private/pypi/BUILD.bazel
@@ -366,6 +366,16 @@
 )
 
 bzl_library(
+    name = "select_whl_bzl",
+    srcs = ["select_whl.bzl"],
+    deps = [
+        ":parse_whl_name_bzl",
+        ":python_tag_bzl",
+        "//python/private:version_bzl",
+    ],
+)
+
+bzl_library(
     name = "simpleapi_download_bzl",
     srcs = ["simpleapi_download.bzl"],
     deps = [
diff --git a/python/private/pypi/select_whl.bzl b/python/private/pypi/select_whl.bzl
new file mode 100644
index 0000000..e9db188
--- /dev/null
+++ b/python/private/pypi/select_whl.bzl
@@ -0,0 +1,237 @@
+"Select a single wheel that fits the parameters of a target platform."
+
+load("//python/private:version.bzl", "version")
+load(":parse_whl_name.bzl", "parse_whl_name")
+load(":python_tag.bzl", "PY_TAG_GENERIC", "python_tag")
+
+_ANDROID = "android"
+_IOS = "ios"
+_MANYLINUX = "manylinux"
+_MACOSX = "macosx"
+_MUSLLINUX = "musllinux"
+
+def _value_priority(*, tag, values):
+    keys = []
+    for priority, wp in enumerate(values):
+        if tag == wp:
+            keys.append(priority)
+
+    return max(keys) if keys else None
+
+def _platform_tag_priority(*, tag, values):
+    # Implements matching platform tag
+    # https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/
+
+    if not (
+        tag.startswith(_ANDROID) or
+        tag.startswith(_IOS) or
+        tag.startswith(_MACOSX) or
+        tag.startswith(_MANYLINUX) or
+        tag.startswith(_MUSLLINUX)
+    ):
+        res = _value_priority(tag = tag, values = values)
+        if res == None:
+            return res
+
+        return (res, (0, 0))
+
+    # Only android, ios, macosx, manylinux or musllinux platforms should be considered
+
+    os, _, tail = tag.partition("_")
+    major, _, tail = tail.partition("_")
+    if not os.startswith(_ANDROID):
+        minor, _, arch = tail.partition("_")
+    else:
+        minor = "0"
+        arch = tail
+    version = (int(major), int(minor))
+
+    keys = []
+    for priority, wp in enumerate(values):
+        want_os, sep, tail = wp.partition("_")
+        if not sep:
+            # if there is no `_` separator, then it means that we have something like `win32` or
+            # similar wheels that we are considering, this means that it should be discarded because
+            # we are dealing only with platforms that have `_`.
+            continue
+
+        if want_os != os:
+            # os should always match exactly for us to match and assign a priority
+            continue
+
+        want_major, _, tail = tail.partition("_")
+        if want_major == "*":
+            # the expected match is any version
+            want_major = ""
+            want_minor = ""
+            want_arch = tail
+        elif os.startswith(_ANDROID):
+            # we set it to `0` above, so setting the `want_minor` her to `0` will make things
+            # consistent.
+            want_minor = "0"
+            want_arch = tail
+        else:
+            # here we parse the values from the given platform
+            want_minor, _, want_arch = tail.partition("_")
+
+        if want_arch != arch:
+            # the arch should match exactly
+            continue
+
+        # if want_major is defined, then we know that we don't have a `*` in the matcher.
+        want_version = (int(want_major), int(want_minor)) if want_major else None
+        if not want_version or version <= want_version:
+            keys.append((priority, version))
+
+    return max(keys) if keys else None
+
+def _python_tag_priority(*, tag, implementation, py_version):
+    if tag.startswith(PY_TAG_GENERIC):
+        ver_str = tag[len(PY_TAG_GENERIC):]
+    elif tag.startswith(implementation):
+        ver_str = tag[len(implementation):]
+    else:
+        return None
+
+    # Add a 0 at the end in case it is a single digit
+    ver_str = "{}.{}".format(ver_str[0], ver_str[1:] or "0")
+
+    ver = version.parse(ver_str)
+    if not version.is_compatible(py_version, ver):
+        return None
+
+    return (
+        tag.startswith(implementation),
+        version.key(ver),
+    )
+
+def _candidates_by_priority(
+        *,
+        whls,
+        implementation_name,
+        python_version,
+        whl_abi_tags,
+        whl_platform_tags,
+        logger):
+    """Calculate the priority of each wheel
+
+    Returns:
+        A dictionary where keys are priority tuples which allows us to sort and pick the
+        last item.
+    """
+    py_version = version.parse(python_version, strict = True)
+    implementation = python_tag(implementation_name)
+
+    ret = {}
+    for whl in whls:
+        parsed = parse_whl_name(whl.filename)
+        priority = None
+
+        # See https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#compressed-tag-sets
+        for platform in parsed.platform_tag.split("."):
+            platform = _platform_tag_priority(tag = platform, values = whl_platform_tags)
+            if platform == None:
+                logger.debug(lambda: "The platform_tag in '{}' does not match given list: {}".format(
+                    whl.filename,
+                    whl_platform_tags,
+                ))
+                continue
+
+            for py in parsed.python_tag.split("."):
+                py = _python_tag_priority(
+                    tag = py,
+                    implementation = implementation,
+                    py_version = py_version,
+                )
+                if py == None:
+                    logger.debug(lambda: "The python_tag in '{}' does not match implementation or version: {} {}".format(
+                        whl.filename,
+                        implementation,
+                        py_version.string,
+                    ))
+                    continue
+
+                for abi in parsed.abi_tag.split("."):
+                    abi = _value_priority(
+                        tag = abi,
+                        values = whl_abi_tags,
+                    )
+                    if abi == None:
+                        logger.debug(lambda: "The abi_tag in '{}' does not match given list: {}".format(
+                            whl.filename,
+                            whl_abi_tags,
+                        ))
+                        continue
+
+                    # 1. Prefer platform wheels
+                    # 2. Then prefer implementation/python version
+                    # 3. Then prefer more specific ABI wheels
+                    candidate = (platform, py, abi)
+                    priority = priority or candidate
+                    if candidate > priority:
+                        priority = candidate
+
+        if priority == None:
+            logger.debug(lambda: "The whl '{}' is incompatible".format(
+                whl.filename,
+            ))
+            continue
+
+        ret[priority] = whl
+
+    return ret
+
+def select_whl(
+        *,
+        whls,
+        python_version,
+        whl_platform_tags,
+        whl_abi_tags,
+        implementation_name = "cpython",
+        limit = 1,
+        logger):
+    """Select a whl that is the most suitable for the given platform.
+
+    Args:
+        whls: {type}`list[struct]` a list of candidates which have a `filename`
+            attribute containing the `whl` filename.
+        python_version: {type}`str` the target python version.
+        implementation_name: {type}`str` the `implementation_name` from the target_platform env.
+        whl_abi_tags: {type}`list[str]` The whl abi tags to select from. The preference is
+            for wheels that have ABI values appearing later in the `whl_abi_tags` list.
+        whl_platform_tags: {type}`list[str]` The whl platform tags to select from.
+            The platform tag may contain `*` and this means that if the platform tag is
+            versioned (e.g. `manylinux`), then we will select the highest available
+            platform version, e.g. if `manylinux_2_17` and `manylinux_2_5` wheels are both
+            compatible, we will select `manylinux_2_17`. Otherwise for versioned platform
+            tags we select the highest *compatible* version, e.g. if `manylinux_2_6`
+            support is requested, then we would select `manylinux_2_5` in the previous
+            example. This allows us to pass the same filtering parameters when selecting
+            all of the whl dependencies irrespective of what actual platform tags they
+            contain.
+        limit: {type}`int` number of wheels to return. Defaults to 1.
+        logger: {type}`struct` the logger instance.
+
+    Returns:
+        {type}`list[struct] | struct | None`, a single struct from the `whls` input
+            argument or `None` if a match is not found. If the `limit` is greater than
+            one, then we will return a list.
+    """
+    candidates = _candidates_by_priority(
+        whls = whls,
+        implementation_name = implementation_name,
+        python_version = python_version,
+        whl_abi_tags = whl_abi_tags,
+        whl_platform_tags = whl_platform_tags,
+        logger = logger,
+    )
+
+    if not candidates:
+        return None
+
+    res = [i[1] for i in sorted(candidates.items())]
+    logger.debug(lambda: "Sorted candidates:\n{}".format(
+        "\n".join([c.filename for c in res]),
+    ))
+
+    return res[-1] if limit == 1 else res[-limit:]
diff --git a/tests/pypi/select_whl/BUILD.bazel b/tests/pypi/select_whl/BUILD.bazel
new file mode 100644
index 0000000..0ad8cba
--- /dev/null
+++ b/tests/pypi/select_whl/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":select_whl_tests.bzl", "select_whl_test_suite")
+
+select_whl_test_suite(name = "select_whl_tests")
diff --git a/tests/pypi/select_whl/select_whl_tests.bzl b/tests/pypi/select_whl/select_whl_tests.bzl
new file mode 100644
index 0000000..28e17ba
--- /dev/null
+++ b/tests/pypi/select_whl/select_whl_tests.bzl
@@ -0,0 +1,463 @@
+""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/private:repo_utils.bzl", "REPO_DEBUG_ENV_VAR", "REPO_VERBOSITY_ENV_VAR", "repo_utils")  # buildifier: disable=bzl-visibility
+load("//python/private/pypi:select_whl.bzl", "select_whl")  # buildifier: disable=bzl-visibility
+
+WHL_LIST = [
+    "pkg-0.0.1-cp311-cp311-macosx_10_9_universal2.whl",
+    "pkg-0.0.1-cp311-cp311-macosx_10_9_x86_64.whl",
+    "pkg-0.0.1-cp311-cp311-macosx_11_0_arm64.whl",
+    "pkg-0.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+    "pkg-0.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
+    "pkg-0.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl",
+    "pkg-0.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+    "pkg-0.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl",
+    "pkg-0.0.1-cp313-cp313t-musllinux_1_1_x86_64.whl",
+    "pkg-0.0.1-cp313-cp313-musllinux_1_1_x86_64.whl",
+    "pkg-0.0.1-cp313-abi3-musllinux_1_1_x86_64.whl",
+    "pkg-0.0.1-cp313-none-musllinux_1_1_x86_64.whl",
+    "pkg-0.0.1-cp311-cp311-musllinux_1_1_aarch64.whl",
+    "pkg-0.0.1-cp311-cp311-musllinux_1_1_i686.whl",
+    "pkg-0.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl",
+    "pkg-0.0.1-cp311-cp311-musllinux_1_1_s390x.whl",
+    "pkg-0.0.1-cp311-cp311-musllinux_1_1_x86_64.whl",
+    "pkg-0.0.1-cp311-cp311-win32.whl",
+    "pkg-0.0.1-cp311-cp311-win_amd64.whl",
+    "pkg-0.0.1-cp37-cp37m-macosx_10_9_x86_64.whl",
+    "pkg-0.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+    "pkg-0.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
+    "pkg-0.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl",
+    "pkg-0.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+    "pkg-0.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl",
+    "pkg-0.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl",
+    "pkg-0.0.1-cp37-cp37m-musllinux_1_1_i686.whl",
+    "pkg-0.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl",
+    "pkg-0.0.1-cp37-cp37m-musllinux_1_1_s390x.whl",
+    "pkg-0.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl",
+    "pkg-0.0.1-cp37-cp37m-win32.whl",
+    "pkg-0.0.1-cp37-cp37m-win_amd64.whl",
+    "pkg-0.0.1-cp39-cp39-macosx_10_9_universal2.whl",
+    "pkg-0.0.1-cp39-cp39-macosx_10_9_x86_64.whl",
+    "pkg-0.0.1-cp39-cp39-macosx_11_0_arm64.whl",
+    "pkg-0.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+    "pkg-0.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
+    "pkg-0.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl",
+    "pkg-0.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+    "pkg-0.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl",
+    "pkg-0.0.1-cp39-cp39-musllinux_1_1_aarch64.whl",
+    "pkg-0.0.1-cp39-cp39-musllinux_1_1_i686.whl",
+    "pkg-0.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl",
+    "pkg-0.0.1-cp39-cp39-musllinux_1_1_s390x.whl",
+    "pkg-0.0.1-cp39-cp39-musllinux_1_1_x86_64.whl",
+    "pkg-0.0.1-cp39-cp39-win32.whl",
+    "pkg-0.0.1-cp39-cp39-win_amd64.whl",
+    "pkg-0.0.1-cp39-abi3-any.whl",
+    "pkg-0.0.1-py310-abi3-any.whl",
+    "pkg-0.0.1-py3-abi3-any.whl",
+    "pkg-0.0.1-py3-none-any.whl",
+    # Extra examples that should be discarded
+    "pkg-0.0.1-py27-cp27mu-win_amd64.whl",
+    "pkg-0.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+]
+
+def _match(env, got, *want_filenames):
+    if not want_filenames:
+        env.expect.that_collection(got).has_size(len(want_filenames))
+        return
+
+    got = [g for g in got if g]
+    got_filenames = [g.filename for g in got]
+    env.expect.that_collection(got_filenames).contains_exactly(want_filenames).in_order()
+
+    if got:
+        # Check that we pass the original structs
+        env.expect.that_str(got[0].other).equals("dummy")
+
+def _select_whl(whls, debug = False, **kwargs):
+    return select_whl(
+        whls = [
+            struct(
+                filename = f,
+                other = "dummy",
+            )
+            for f in whls
+        ],
+        logger = repo_utils.logger(struct(
+            os = struct(
+                environ = {
+                    REPO_DEBUG_ENV_VAR: "1",
+                    REPO_VERBOSITY_ENV_VAR: "TRACE" if debug else "INFO",
+                },
+            ),
+        ), "unit-test"),
+        **kwargs
+    )
+
+_tests = []
+
+def _test_not_select_py2(env):
+    # Check we prefer platform specific wheels
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py2-none-any.whl",
+            "pkg-0.0.1-py3-none-any.whl",
+            "pkg-0.0.1-py312-none-any.whl",
+        ],
+        whl_platform_tags = ["any"],
+        whl_abi_tags = ["none"],
+        python_version = "3.13",
+        limit = 2,
+    )
+    _match(
+        env,
+        got,
+        "pkg-0.0.1-py3-none-any.whl",
+        "pkg-0.0.1-py312-none-any.whl",
+    )
+
+_tests.append(_test_not_select_py2)
+
+def _test_not_select_abi3(env):
+    # Check we prefer platform specific wheels
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py3-none-any.whl",
+            # the following should be ignored
+            "pkg-0.0.1-py3-abi3-any.whl",
+            "pkg-0.0.1-py3-abi3-p1.p2.p2.whl",
+        ],
+        whl_platform_tags = ["any", "p1"],
+        whl_abi_tags = ["none"],
+        python_version = "3.13",
+        limit = 2,
+        debug = True,
+    )
+    _match(
+        env,
+        got,
+        "pkg-0.0.1-py3-none-any.whl",
+    )
+
+_tests.append(_test_not_select_abi3)
+
+def _test_select_cp312(env):
+    # Check we prefer platform specific wheels
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py2-none-any.whl",
+            "pkg-0.0.1-py3-none-any.whl",
+            "pkg-0.0.1-py312-none-any.whl",
+            "pkg-0.0.1-cp39-none-any.whl",
+            "pkg-0.0.1-cp312-none-any.whl",
+            "pkg-0.0.1-cp314-none-any.whl",
+        ],
+        whl_platform_tags = ["any"],
+        whl_abi_tags = ["none"],
+        python_version = "3.13",
+        limit = 5,
+    )
+    _match(
+        env,
+        got,
+        "pkg-0.0.1-py3-none-any.whl",
+        "pkg-0.0.1-py312-none-any.whl",
+        "pkg-0.0.1-cp39-none-any.whl",
+        "pkg-0.0.1-cp312-none-any.whl",
+    )
+
+_tests.append(_test_select_cp312)
+
+def _test_simplest(env):
+    whls = [
+        "pkg-0.0.1-py2.py3-abi3-any.whl",
+        "pkg-0.0.1-py3-abi3-any.whl",
+        "pkg-0.0.1-py3-none-any.whl",
+    ]
+
+    got = _select_whl(
+        whls = whls,
+        whl_platform_tags = ["any"],
+        whl_abi_tags = ["abi3"],
+        python_version = "3.0",
+    )
+    _match(
+        env,
+        [got],
+        "pkg-0.0.1-py3-abi3-any.whl",
+    )
+
+_tests.append(_test_simplest)
+
+def _test_select_by_supported_py_version(env):
+    whls = [
+        "pkg-0.0.1-py2.py3-abi3-any.whl",
+        "pkg-0.0.1-py3-abi3-any.whl",
+        "pkg-0.0.1-py311-abi3-any.whl",
+    ]
+
+    for minor_version, match in {
+        8: "pkg-0.0.1-py3-abi3-any.whl",
+        11: "pkg-0.0.1-py311-abi3-any.whl",
+    }.items():
+        got = _select_whl(
+            whls = whls,
+            whl_platform_tags = ["any"],
+            whl_abi_tags = ["abi3"],
+            python_version = "3.{}".format(minor_version),
+        )
+        _match(env, [got], match)
+
+_tests.append(_test_select_by_supported_py_version)
+
+def _test_select_by_supported_cp_version(env):
+    whls = [
+        "pkg-0.0.1-py2.py3-abi3-any.whl",
+        "pkg-0.0.1-py3-abi3-any.whl",
+        "pkg-0.0.1-py311-abi3-any.whl",
+        "pkg-0.0.1-cp311-abi3-any.whl",
+    ]
+
+    for minor_version, match in {
+        11: "pkg-0.0.1-cp311-abi3-any.whl",
+        8: "pkg-0.0.1-py3-abi3-any.whl",
+    }.items():
+        got = _select_whl(
+            whls = whls,
+            whl_platform_tags = ["any"],
+            whl_abi_tags = ["abi3"],
+            python_version = "3.{}".format(minor_version),
+        )
+        _match(env, [got], match)
+
+_tests.append(_test_select_by_supported_cp_version)
+
+def _test_supported_cp_version_manylinux(env):
+    whls = [
+        "pkg-0.0.1-py2.py3-none-manylinux_1_1_x86_64.whl",
+        "pkg-0.0.1-py3-none-manylinux_1_1_x86_64.whl",
+        "pkg-0.0.1-py311-none-manylinux_1_1_x86_64.whl",
+        "pkg-0.0.1-cp311-none-manylinux_1_1_x86_64.whl",
+    ]
+
+    for minor_version, match in {
+        8: "pkg-0.0.1-py3-none-manylinux_1_1_x86_64.whl",
+        11: "pkg-0.0.1-cp311-none-manylinux_1_1_x86_64.whl",
+    }.items():
+        got = _select_whl(
+            whls = whls,
+            whl_platform_tags = ["manylinux_1_1_x86_64"],
+            whl_abi_tags = ["none"],
+            python_version = "3.{}".format(minor_version),
+        )
+        _match(env, [got], match)
+
+_tests.append(_test_supported_cp_version_manylinux)
+
+def _test_ignore_unsupported(env):
+    whls = ["pkg-0.0.1-xx3-abi3-any.whl"]
+    got = _select_whl(
+        whls = whls,
+        whl_platform_tags = ["any"],
+        whl_abi_tags = ["none"],
+        python_version = "3.0",
+    )
+    if got:
+        _match(env, [got], None)
+
+_tests.append(_test_ignore_unsupported)
+
+def _test_match_abi_and_not_py_version(env):
+    # Check we match the ABI and not the py version
+    whls = WHL_LIST
+    whl_platform_tags = [
+        "musllinux_*_x86_64",
+        "manylinux_*_x86_64",
+    ]
+    got = _select_whl(
+        whls = whls,
+        whl_platform_tags = whl_platform_tags,
+        whl_abi_tags = ["abi3", "cp37m"],
+        python_version = "3.7",
+    )
+    _match(
+        env,
+        [got],
+        "pkg-0.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+    )
+
+    got = _select_whl(
+        whls = whls,
+        whl_platform_tags = whl_platform_tags[::-1],
+        whl_abi_tags = ["abi3", "cp37m"],
+        python_version = "3.7",
+    )
+    _match(
+        env,
+        [got],
+        "pkg-0.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl",
+    )
+
+_tests.append(_test_match_abi_and_not_py_version)
+
+def _test_select_filename_with_many_tags(env):
+    # Check we can select a filename with many platform tags
+    got = _select_whl(
+        whls = WHL_LIST,
+        whl_platform_tags = [
+            "any",
+            "musllinux_*_i686",
+            "manylinux_*_i686",
+        ],
+        whl_abi_tags = ["none", "abi3", "cp39"],
+        python_version = "3.9",
+        limit = 5,
+    )
+    _match(
+        env,
+        got,
+        "pkg-0.0.1-py3-none-any.whl",
+        "pkg-0.0.1-py3-abi3-any.whl",
+        "pkg-0.0.1-cp39-abi3-any.whl",
+        "pkg-0.0.1-cp39-cp39-musllinux_1_1_i686.whl",
+        "pkg-0.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl",
+    )
+
+_tests.append(_test_select_filename_with_many_tags)
+
+def _test_freethreaded_wheels(env):
+    # Check we prefer platform specific wheels
+    got = _select_whl(
+        whls = WHL_LIST,
+        whl_platform_tags = [
+            "any",
+            "musllinux_*_x86_64",
+        ],
+        whl_abi_tags = ["none", "abi3", "cp313", "cp313t"],
+        python_version = "3.13",
+        limit = 8,
+    )
+    _match(
+        env,
+        got,
+        # The last item has the most priority
+        "pkg-0.0.1-py3-none-any.whl",
+        "pkg-0.0.1-py3-abi3-any.whl",
+        "pkg-0.0.1-py310-abi3-any.whl",
+        "pkg-0.0.1-cp39-abi3-any.whl",
+        "pkg-0.0.1-cp313-none-musllinux_1_1_x86_64.whl",
+        "pkg-0.0.1-cp313-abi3-musllinux_1_1_x86_64.whl",
+        "pkg-0.0.1-cp313-cp313-musllinux_1_1_x86_64.whl",
+        "pkg-0.0.1-cp313-cp313t-musllinux_1_1_x86_64.whl",
+    )
+
+_tests.append(_test_freethreaded_wheels)
+
+def _test_pytags_all_possible(env):
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313-none-win_amd64.whl",
+        ],
+        whl_platform_tags = ["win_amd64"],
+        whl_abi_tags = ["none"],
+        python_version = "3.12",
+    )
+    _match(
+        env,
+        [got],
+        "pkg-0.0.1-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313-none-win_amd64.whl",
+    )
+
+_tests.append(_test_pytags_all_possible)
+
+def _test_manylinx_musllinux_pref(env):
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py3-none-manylinux_2_31_x86_64.musllinux_1_1_x86_64.whl",
+        ],
+        whl_platform_tags = [
+            "manylinux_*_x86_64",
+            "musllinux_*_x86_64",
+        ],
+        whl_abi_tags = ["none"],
+        python_version = "3.12",
+        limit = 2,
+    )
+    _match(
+        env,
+        got,
+        # there is only one wheel, just select that
+        "pkg-0.0.1-py3-none-manylinux_2_31_x86_64.musllinux_1_1_x86_64.whl",
+    )
+
+_tests.append(_test_manylinx_musllinux_pref)
+
+def _test_multiple_musllinux(env):
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py3-none-musllinux_1_2_x86_64.whl",
+            "pkg-0.0.1-py3-none-musllinux_1_1_x86_64.whl",
+        ],
+        whl_platform_tags = ["musllinux_*_x86_64"],
+        whl_abi_tags = ["none"],
+        python_version = "3.12",
+        limit = 2,
+    )
+    _match(
+        env,
+        got,
+        # select the one with the highest version that is matching
+        "pkg-0.0.1-py3-none-musllinux_1_1_x86_64.whl",
+        "pkg-0.0.1-py3-none-musllinux_1_2_x86_64.whl",
+    )
+
+_tests.append(_test_multiple_musllinux)
+
+def _test_multiple_musllinux_exact_params(env):
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py3-none-musllinux_1_2_x86_64.whl",
+            "pkg-0.0.1-py3-none-musllinux_1_1_x86_64.whl",
+        ],
+        whl_platform_tags = ["musllinux_1_2_x86_64", "musllinux_1_1_x86_64"],
+        whl_abi_tags = ["none"],
+        python_version = "3.12",
+        limit = 2,
+    )
+    _match(
+        env,
+        got,
+        # select the one with the lowest version, because of the input to the function
+        "pkg-0.0.1-py3-none-musllinux_1_2_x86_64.whl",
+        "pkg-0.0.1-py3-none-musllinux_1_1_x86_64.whl",
+    )
+
+_tests.append(_test_multiple_musllinux_exact_params)
+
+def _test_android(env):
+    got = _select_whl(
+        whls = [
+            "pkg-0.0.1-py3-none-android_4_x86_64.whl",
+            "pkg-0.0.1-py3-none-android_8_x86_64.whl",
+        ],
+        whl_platform_tags = ["android_5_x86_64"],
+        whl_abi_tags = ["none"],
+        python_version = "3.12",
+        limit = 2,
+    )
+    _match(
+        env,
+        got,
+        # select the one with the highest version that is matching
+        "pkg-0.0.1-py3-none-android_4_x86_64.whl",
+    )
+
+_tests.append(_test_android)
+
+def select_whl_test_suite(name):
+    """Create the test suite.
+
+    Args:
+        name: the name of the test suite
+    """
+    test_suite(name = name, basic_tests = _tests)