diff --git a/okonomiyaki/platforms/_arch.py b/okonomiyaki/platforms/_arch.py index 26f5bc0..8123c72 100644 --- a/okonomiyaki/platforms/_arch.py +++ b/okonomiyaki/platforms/_arch.py @@ -119,3 +119,4 @@ def __str__(self): X86 = Arch(ArchitectureKind.x86) X86_64 = Arch(ArchitectureKind.x86_64) +ARM64 = Arch(ArchitectureKind.arm64) diff --git a/okonomiyaki/platforms/epd_platform.py b/okonomiyaki/platforms/epd_platform.py index 64a5651..634f56c 100644 --- a/okonomiyaki/platforms/epd_platform.py +++ b/okonomiyaki/platforms/epd_platform.py @@ -10,7 +10,7 @@ from okonomiyaki.versions import RuntimeVersion from okonomiyaki.errors import OkonomiyakiError, InvalidPEP440Version -from ._arch import Arch, ArchitectureKind, X86, X86_64 +from ._arch import Arch, ArchitectureKind, X86, X86_64, ARM64 from ._platform import OSKind, FamilyKind, NameKind, Platform # the string used in EGG-INFO/spec/depend. Only used during normalization @@ -269,6 +269,8 @@ def pep425_tag(self): return u"macosx_{}_i386".format(release) elif platform.arch == X86_64: return u"macosx_{}_x86_64".format(release) + elif platform.arch == ARM64: + return u"macosx_{}_arm64".format(release) else: raise OkonomiyakiError(msg.format(platform)) elif platform.os_kind == OSKind.linux: @@ -276,6 +278,8 @@ def pep425_tag(self): return u"linux_i686" elif platform.arch == X86_64: return u"linux_x86_64" + elif platform.arch == ARM64: + return u"linux_aarch64" else: raise OkonomiyakiError(msg.format(platform)) elif platform.os_kind == OSKind.windows: @@ -283,6 +287,8 @@ def pep425_tag(self): return u"win32" elif platform.arch == X86_64: return u"win_amd64" + elif platform.arch == ARM64: + return u"win_arm64" else: raise OkonomiyakiError(msg.format(platform)) else: @@ -325,7 +331,11 @@ def platform_name(self): @property def short(self): - return u"{0}-{1}".format(self.platform_name, self.arch_bits) + if self.arch in (X86, X86_64): + return u"{0}-{1}".format(self.platform_name, self.arch_bits) + else: + raise ValueError(f'No legacy short name available for {self}') + def __str__(self): return u"{0.platform_name}_{0.arch}".format(self) @@ -461,10 +471,12 @@ def _is_supported(platform): arch_and_machine_are_intel = ( platform.arch in (X86, X86_64) and platform.machine in (X86, X86_64)) + arch_and_machine_are_arm = ( + platform.arch == ARM64 and platform.machine == ARM64) if platform.os_kind == OSKind.windows: - return arch_and_machine_are_intel + return arch_and_machine_are_intel or arch_and_machine_are_arm if platform.os_kind == OSKind.darwin: - return arch_and_machine_are_intel + return arch_and_machine_are_intel or arch_and_machine_are_arm if platform.os_kind == OSKind.solaris: return arch_and_machine_are_intel if platform.os_kind == OSKind.linux: diff --git a/okonomiyaki/platforms/tests/test_epd_platform.py b/okonomiyaki/platforms/tests/test_epd_platform.py index 1002920..351b5a8 100644 --- a/okonomiyaki/platforms/tests/test_epd_platform.py +++ b/okonomiyaki/platforms/tests/test_epd_platform.py @@ -9,7 +9,7 @@ from .. import EPDPlatform from ..epd_platform import ( - EPD_PLATFORM_SHORT_NAMES, X86, X86_64, applies) + EPD_PLATFORM_SHORT_NAMES, X86, X86_64, ARM64, applies) from ..legacy import _SUBDIR from .._platform import OSKind, FamilyKind, NameKind @@ -17,7 +17,8 @@ mock_architecture_32bit, mock_architecture_64bit, mock_centos_5_8, mock_centos_6_3, mock_darwin, mock_machine_x86, mock_machine_x86_64, mock_solaris, mock_ubuntu_raring, mock_x86, mock_x86_64, - mock_centos_7_6, mock_windows_10, mock_windows_11, mock_windows_7) + mock_centos_7_6, mock_windows_10, mock_windows_11, mock_windows_7, + mock_machine_arm64, mock_machine) if sys.version_info < (2, 7): import unittest2 as unittest @@ -35,6 +36,7 @@ def setUp(self): items = [ platform + "-x86_64" for platform in ("rh6", "rh7", "rh8")] + items += ["osx-arm64", "win-arm64"] self.platform_strings = tuple(items) def test_short_names_consistency(self): @@ -51,7 +53,13 @@ def test_epd_platform_from_legacy_short_string(self): def test_pep425_is_unicode(self): # When/Then for platform_string in self.platform_strings: - platform = EPDPlatform.from_string(platform_string) + if platform_string == 'osx-arm64': + # arm is only suppported on 3.11 and above + platform = EPDPlatform.from_string( + platform_string, + runtime_version=RuntimeVersion.from_string('3.11')) + else: + platform = EPDPlatform.from_string(platform_string) self.assertIsInstance(platform.pep425_tag, six.text_type) def test_platform_name_is_unicode(self): @@ -99,6 +107,18 @@ def test_epd_platform_from_string_new_names(self): self.assertEqual(epd_platform.arch_bits, "64") self.assertEqual(epd_platform.platform_name, "win") + archs = ("arm64", "aarch64") + + # When + epd_platforms = tuple( + EPDPlatform.from_string("osx-" + arch) + for arch in archs) + + # Then + for epd_platform in epd_platforms: + self.assertEqual(epd_platform.arch_bits, "64") + self.assertEqual(epd_platform.platform_name, "osx") + def test_epd_platform_from_string_with_runtime_version(self): # given version = RuntimeVersion.from_string('3.6.5+6') @@ -201,6 +221,47 @@ def test_from_running_system_windows_11(self): epd_platform = EPDPlatform.from_running_system('x86') self.assertEqual(str(epd_platform), "win_x86") + @mock_darwin + @mock_machine_arm64 + def test_from_running_python_apple_silicon(self): + # When + with mock_architecture_64bit: + epd_platform = EPDPlatform.from_running_python() + + # Then + self.assertEqual(str(epd_platform), "osx_arm64") + + # When + with mock_architecture_32bit: + with self.assertRaises(OkonomiyakiError): + EPDPlatform.from_running_python() + + @mock_windows + def test_from_running_system_windows(self): + with mock_machine_x86: + epd_platform = EPDPlatform.from_running_system() + self.assertEqual(str(epd_platform), "win_x86") + + epd_platform = EPDPlatform.from_running_system('x86') + self.assertEqual(str(epd_platform), "win_x86") + + with self.assertRaises(OkonomiyakiError): + EPDPlatform.from_running_system('AMD64') + + with mock_machine_x86_64: + epd_platform = EPDPlatform.from_running_system() + self.assertEqual(str(epd_platform), "win_x86_64") + + epd_platform = EPDPlatform.from_running_system('x86') + self.assertEqual(str(epd_platform), "win_x86") + + with mock_machine_arm64: + epd_platform = EPDPlatform.from_running_system() + self.assertEqual(str(epd_platform), "win_arm64") + + epd_platform = EPDPlatform.from_running_system('arm64') + self.assertEqual(str(epd_platform), "win_arm64") + @mock_darwin def test_from_running_system_darwin(self): with mock_machine_x86: @@ -225,6 +286,11 @@ def test_from_running_system_darwin(self): epd_platform = EPDPlatform.from_running_system('x86') self.assertEqual(str(epd_platform), "osx_x86") + with mock_machine_arm64: + # When/Then + epd_platform = EPDPlatform.from_running_system() + self.assertEqual(str(epd_platform), "osx_arm64") + @mock_centos_5_8 def test_from_running_system_centos_5(self): with mock_machine_x86: @@ -246,6 +312,10 @@ def test_from_running_system_centos_5(self): epd_platform = EPDPlatform.from_running_system('x86') self.assertEqual(str(epd_platform), "rh5_x86") + with mock_machine_arm64: + with self.assertRaises(OkonomiyakiError): + EPDPlatform.from_running_system() + @mock_centos_6_3 def test_from_running_system_centos_6(self): with mock_machine_x86: @@ -267,6 +337,10 @@ def test_from_running_system_centos_6(self): epd_platform = EPDPlatform.from_running_system('x86') self.assertEqual(str(epd_platform), "rh6_x86") + with mock_machine_arm64: + with self.assertRaises(OkonomiyakiError): + EPDPlatform.from_running_system() + @mock_centos_7_6 def test_from_running_system_centos_7(self): with mock_machine_x86: @@ -283,6 +357,10 @@ def test_from_running_system_centos_7(self): epd_platform = EPDPlatform.from_running_system('x86') self.assertEqual(str(epd_platform), "rh7_x86") + with mock_machine_arm64: + with self.assertRaises(OkonomiyakiError): + EPDPlatform.from_running_system() + @given(sampled_from(( ("rh5_x86", None, "linux_i686"), ("rh5_x86_64", None, "linux_x86_64"), @@ -291,8 +369,10 @@ def test_from_running_system_centos_7(self): ("osx_x86_64", None, "macosx_10_6_x86_64"), ("osx_x86_64", '3.8.9+1', "macosx_10_14_x86_64"), ("osx_x86_64", '3.11.2+1', "macosx_12_0_x86_64"), + ("osx_arm64", '3.11.2+1', "macosx_12_0_arm64"), ("win_x86", None, "win32"), ("win_x86_64", None, "win_amd64"), + ("win_arm64", None, "win_arm64"), ("win_x86_64", '3.9.1', "win_amd64")))) def test_pep425_tag(self, arguments): # Given @@ -322,7 +402,7 @@ def test_pep425_tag(self, arguments): ('win32', None, 'x86', 'win32', 'cp36', 'msvc2015'), ('win32', None, 'amd64', 'win_amd64', 'cp36', 'msvc2015'), ('win32', None, 'x86', 'win32', 'cp38', 'msvc2019'), - ('win32', None, 'amd64', 'win32', 'cp311', 'msvc2022'), + ('win32', None, 'arm64', 'win32', 'cp311', 'msvc2022'), ('win32', None, 'amd64', 'win_amd64', 'cp38', 'msvc2019'), ))) def test_from_spec_depend_data(self, arguments): @@ -331,7 +411,9 @@ def test_from_spec_depend_data(self, arguments): platform, osdist, arch_name, platform_tag, python_version, platform_abi = arguments # then - if '64' in arch_name: + if 'arm' in arch_name: + self.assertEqual(epd_platform.arch, ARM64) + elif '64' in arch_name: self.assertEqual(epd_platform.arch, X86_64) else: self.assertEqual(epd_platform.arch, X86) @@ -507,6 +589,20 @@ def test_from_epd_platform_string(self): self.assertEqual(platform.arch, X86_64) self.assertEqual(platform.machine, X86_64) + # Given + epd_platform_string = "win-arm64" + + # When + epd_platform = EPDPlatform.from_string(epd_platform_string) + platform = epd_platform.platform + + # Then + self.assertEqual(platform.os_kind, OSKind.windows) + self.assertEqual(platform.family_kind, FamilyKind.windows) + self.assertEqual(platform.name_kind, NameKind.windows) + self.assertEqual(platform.arch, ARM64) + self.assertEqual(platform.machine, ARM64) + def test_from_epd_platform_string_invalid(self): # Given # Invalid bitwidth @@ -540,7 +636,9 @@ def test_from_platform_tag(self): ("linux_x86_64", "rh5_x86_64"), ("win32", "win_x86"), ("win_amd64", "win_x86_64"), + ("win_arm64", "win_arm64"), ("macosx_10_6_x86_64", "osx_x86_64"), + ("macosx_10_6_arm64", "osx_arm64"), ) # When/Then