refactor(internal): simplify and cleanup dependency resolution (#1691)
Summary:
- refactor: add an OS.interpreter constructor
- refactor: add an Arch.interpreter constructor
- test: add a specializations tests
- refactor: simplify sorting implementation
- refactor: introduce `__str__` to enums
Minor cleanup that will be useful to make this codebase
work for multiple Python versions.
Work towards #1643.
diff --git a/python/pip_install/tools/wheel_installer/wheel.py b/python/pip_install/tools/wheel_installer/wheel.py
index a67756e..2275f77 100644
--- a/python/pip_install/tools/wheel_installer/wheel.py
+++ b/python/pip_install/tools/wheel_installer/wheel.py
@@ -36,6 +36,14 @@
darwin = osx
win32 = windows
+ @classmethod
+ def interpreter(cls) -> "OS":
+ "Return the interpreter operating system."
+ return cls[sys.platform.lower()]
+
+ def __str__(self) -> str:
+ return self.name.lower()
+
class Arch(Enum):
x86_64 = 1
@@ -50,6 +58,31 @@
x86 = x86_32
ppc64le = ppc
+ @classmethod
+ def interpreter(cls) -> "OS":
+ "Return the currently running interpreter architecture."
+ # FIXME @aignas 2023-12-13: Hermetic toolchain on Windows 3.11.6
+ # is returning an empty string here, so lets default to x86_64
+ return cls[platform.machine().lower() or "x86_64"]
+
+ def __str__(self) -> str:
+ return self.name.lower()
+
+
+def _as_int(value: Optional[Union[OS, Arch]]) -> int:
+ """Convert one of the enums above to an int for easier sorting algorithms.
+
+ Args:
+ value: The value of an enum or None.
+
+ Returns:
+ -1 if we get None, otherwise, the numeric value of the given enum.
+ """
+ if value is None:
+ return -1
+
+ return int(value.value)
+
@dataclass(frozen=True)
class Platform:
@@ -77,14 +110,7 @@
A list of parsed values which makes the signature the same as
`Platform.all` and `Platform.from_string`.
"""
- return [
- cls(
- os=OS[sys.platform.lower()],
- # FIXME @aignas 2023-12-13: Hermetic toolchain on Windows 3.11.6
- # is returning an empty string here, so lets default to x86_64
- arch=Arch[platform.machine().lower() or "x86_64"],
- )
- ]
+ return [cls(os=OS.interpreter(), arch=Arch.interpreter())]
def all_specializations(self) -> Iterator["Platform"]:
"""Return the platform itself and all its unambiguous specializations.
@@ -102,30 +128,19 @@
if not isinstance(other, Platform) or other is None:
raise ValueError(f"cannot compare {other} with Platform")
- if self.arch is None and other.arch is not None:
- return True
+ self_arch, self_os = _as_int(self.arch), _as_int(self.os)
+ other_arch, other_os = _as_int(other.arch), _as_int(other.os)
- if self.arch is not None and other.arch is None:
- return True
-
- # Here we ensure that we sort by OS before sorting by arch
-
- if self.arch is None and other.arch is None:
- return self.os.value < other.os.value
-
- if self.os.value < other.os.value:
- return True
-
- if self.os.value == other.os.value:
- return self.arch.value < other.arch.value
-
- return False
+ if self_os == other_os:
+ return self_arch < other_arch
+ else:
+ return self_os < other_os
def __str__(self) -> str:
if self.arch is None:
- return f"@platforms//os:{self.os.name.lower()}"
+ return f"@platforms//os:{self.os}"
- return self.os.name.lower() + "_" + self.arch.name.lower()
+ return f"{self.os}_{self.arch}"
@classmethod
def from_string(cls, platform: Union[str, List[str]]) -> List["Platform"]:
diff --git a/python/pip_install/tools/wheel_installer/wheel_installer_test.py b/python/pip_install/tools/wheel_installer/wheel_installer_test.py
index 6eacd1f..74b9c30 100644
--- a/python/pip_install/tools/wheel_installer/wheel_installer_test.py
+++ b/python/pip_install/tools/wheel_installer/wheel_installer_test.py
@@ -101,28 +101,5 @@
self.assertEqual(want, metadata_file_content)
-class TestWheelPlatform(unittest.TestCase):
- def test_wheel_os_alias(self):
- self.assertEqual("OS.osx", str(wheel.OS.osx))
- self.assertEqual(str(wheel.OS.darwin), str(wheel.OS.osx))
-
- def test_wheel_arch_alias(self):
- self.assertEqual("Arch.x86_64", str(wheel.Arch.x86_64))
- self.assertEqual(str(wheel.Arch.amd64), str(wheel.Arch.x86_64))
-
- def test_wheel_platform_alias(self):
- give = wheel.Platform(
- os=wheel.OS.darwin,
- arch=wheel.Arch.amd64,
- )
- alias = wheel.Platform(
- os=wheel.OS.osx,
- arch=wheel.Arch.x86_64,
- )
-
- self.assertEqual("osx_x86_64", str(give))
- self.assertEqual(str(alias), str(give))
-
-
if __name__ == "__main__":
unittest.main()
diff --git a/python/pip_install/tools/wheel_installer/wheel_test.py b/python/pip_install/tools/wheel_installer/wheel_test.py
index 5f4b8c8..5e95ee3 100644
--- a/python/pip_install/tools/wheel_installer/wheel_test.py
+++ b/python/pip_install/tools/wheel_installer/wheel_test.py
@@ -1,4 +1,5 @@
import unittest
+from random import shuffle
from python.pip_install.tools.wheel_installer import wheel
@@ -169,6 +170,76 @@
self.assertEqual(5, len(linuxes))
self.assertEqual(linuxes, wheel.Platform.from_string("linux_*"))
+ def test_linux_specializations(self):
+ any_linux = wheel.Platform(os=wheel.OS.linux)
+ all_specializations = list(any_linux.all_specializations())
+ want = [
+ wheel.Platform(os=wheel.OS.linux, arch=None),
+ wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
+ wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_32),
+ wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.aarch64),
+ wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.ppc),
+ wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.s390x),
+ ]
+ self.assertEqual(want, all_specializations)
+
+ def test_osx_specializations(self):
+ any_osx = wheel.Platform(os=wheel.OS.osx)
+ all_specializations = list(any_osx.all_specializations())
+ # NOTE @aignas 2024-01-14: even though in practice we would only have
+ # Python on osx aarch64 and osx x86_64, we return all arch posibilities
+ # to make the code simpler.
+ want = [
+ wheel.Platform(os=wheel.OS.osx, arch=None),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_32),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.ppc),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.s390x),
+ ]
+ self.assertEqual(want, all_specializations)
+
+ def test_platform_sort(self):
+ platforms = [
+ wheel.Platform(os=wheel.OS.linux, arch=None),
+ wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
+ wheel.Platform(os=wheel.OS.osx, arch=None),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
+ ]
+ shuffle(platforms)
+ platforms.sort()
+ want = [
+ wheel.Platform(os=wheel.OS.linux, arch=None),
+ wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
+ wheel.Platform(os=wheel.OS.osx, arch=None),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
+ wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
+ ]
+
+ self.assertEqual(want, platforms)
+
+ def test_wheel_os_alias(self):
+ self.assertEqual("osx", str(wheel.OS.osx))
+ self.assertEqual(str(wheel.OS.darwin), str(wheel.OS.osx))
+
+ def test_wheel_arch_alias(self):
+ self.assertEqual("x86_64", str(wheel.Arch.x86_64))
+ self.assertEqual(str(wheel.Arch.amd64), str(wheel.Arch.x86_64))
+
+ def test_wheel_platform_alias(self):
+ give = wheel.Platform(
+ os=wheel.OS.darwin,
+ arch=wheel.Arch.amd64,
+ )
+ alias = wheel.Platform(
+ os=wheel.OS.osx,
+ arch=wheel.Arch.x86_64,
+ )
+
+ self.assertEqual("osx_x86_64", str(give))
+ self.assertEqual(str(alias), str(give))
+
if __name__ == "__main__":
unittest.main()