From 729152b1dc93795b134b4daaee41a71223e1d213 Mon Sep 17 00:00:00 2001 From: Malcolm Smith Date: Wed, 26 Mar 2025 14:19:46 +0000 Subject: [PATCH] Add support for Android tags --- news/13299.feature.rst | 1 + src/pip/_internal/utils/compatibility_tags.py | 13 +++++ tests/unit/test_models_wheel.py | 50 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 news/13299.feature.rst diff --git a/news/13299.feature.rst b/news/13299.feature.rst new file mode 100644 index 00000000000..413901dae11 --- /dev/null +++ b/news/13299.feature.rst @@ -0,0 +1 @@ +Support for :pep:`738` Android wheels. diff --git a/src/pip/_internal/utils/compatibility_tags.py b/src/pip/_internal/utils/compatibility_tags.py index 43d6a4aa4bd..edbc7c37a7d 100644 --- a/src/pip/_internal/utils/compatibility_tags.py +++ b/src/pip/_internal/utils/compatibility_tags.py @@ -6,6 +6,7 @@ from pip._vendor.packaging.tags import ( PythonVersion, Tag, + android_platforms, compatible_tags, cpython_tags, generic_tags, @@ -63,6 +64,16 @@ def _ios_platforms(arch: str) -> List[str]: return arches +def _android_platforms(arch: str) -> List[str]: + match = re.fullmatch(r"android_(\d+)_(.+)", arch) + if match: + api_level, abi = match.groups() + return list(android_platforms(int(api_level), abi)) + else: + # arch pattern didn't match (?!) + return [arch] + + def _custom_manylinux_platforms(arch: str) -> List[str]: arches = [arch] arch_prefix, arch_sep, arch_suffix = arch.partition("_") @@ -90,6 +101,8 @@ def _get_custom_platforms(arch: str) -> List[str]: arches = _mac_platforms(arch) elif arch.startswith("ios"): arches = _ios_platforms(arch) + elif arch_prefix == "android": + arches = _android_platforms(arch) elif arch_prefix in ["manylinux2014", "manylinux2010"]: arches = _custom_manylinux_platforms(arch) else: diff --git a/tests/unit/test_models_wheel.py b/tests/unit/test_models_wheel.py index 46991e3487b..d9212ac8d67 100644 --- a/tests/unit/test_models_wheel.py +++ b/tests/unit/test_models_wheel.py @@ -180,6 +180,56 @@ def test_not_supported_ios_version(self) -> None: w = Wheel("simple-0.1-cp313-none-ios_15_1_arm64_iphoneos.whl") assert not w.supported(tags=tags) + def test_android(self) -> None: + arm_old = compatibility_tags.get_supported( + "313", platforms=["android_21_arm64_v8a"], impl="cp" + ) + arm_new = compatibility_tags.get_supported( + "313", platforms=["android_30_arm64_v8a"], impl="cp" + ) + x86_old = compatibility_tags.get_supported( + "313", platforms=["android_21_x86_64"], impl="cp" + ) + x86_new = compatibility_tags.get_supported( + "313", platforms=["android_30_x86_64"], impl="cp" + ) + + w = Wheel("simple-0.1-cp313-none-android_21_arm64_v8a.whl") + assert w.supported(arm_old) + assert w.supported(arm_new) + assert not w.supported(x86_old) + assert not w.supported(x86_new) + + w = Wheel("simple-0.1-cp313-none-android_22_arm64_v8a.whl") + assert not w.supported(arm_old) + assert w.supported(arm_new) + assert not w.supported(x86_old) + assert not w.supported(x86_new) + + w = Wheel("simple-0.1-cp313-none-android_31_arm64_v8a.whl") + assert not w.supported(arm_old) + assert not w.supported(arm_new) + assert not w.supported(x86_old) + assert not w.supported(x86_new) + + w = Wheel("simple-0.1-cp313-none-android_20_x86_64.whl") + assert not w.supported(arm_old) + assert not w.supported(arm_new) + assert w.supported(x86_old) + assert w.supported(x86_new) + + w = Wheel("simple-0.1-cp313-none-android_30_x86_64.whl") + assert not w.supported(arm_old) + assert not w.supported(arm_new) + assert not w.supported(x86_old) + assert w.supported(x86_new) + + w = Wheel("simple-0.1-cp313-none-android_31_x86_64.whl") + assert not w.supported(arm_old) + assert not w.supported(arm_new) + assert not w.supported(x86_old) + assert not w.supported(x86_new) + def test_support_index_min(self) -> None: """ Test results from `support_index_min`