| import sys |
| import unittest |
| import sysconfig |
| |
| from test.support import subTests |
| from test.support import import_helper |
| |
| _testcapi = import_helper.import_module('_testcapi') |
| |
| |
| class Test_ABIInfo_Check(unittest.TestCase): |
| @subTests('modname', (None, 'test_mod')) |
| def test_zero(self, modname): |
| _testcapi.pyabiinfo_check(modname, 0, 0, 0, 0, 0) |
| _testcapi.pyabiinfo_check(modname, 1, 0, 0, 0, 0) |
| |
| def test_large_major_version(self): |
| with self.assertRaisesRegex(ImportError, |
| '^PyABIInfo version too high$'): |
| _testcapi.pyabiinfo_check(None, 2, 0, 0, 0, 0) |
| with self.assertRaisesRegex(ImportError, |
| '^test_mod: PyABIInfo version too high$'): |
| _testcapi.pyabiinfo_check("test_mod", 2, 0, 0, 0, 0) |
| |
| @subTests('modname', (None, 'test_mod')) |
| def test_large_minor_version(self, modname): |
| _testcapi.pyabiinfo_check(modname, 1, 2, 0, 0, 0) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('major', (0, 1)) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| def test_positive_regular(self, modname, major, minor, build): |
| ver = sys.hexversion |
| truncated = ver & 0xffff0000 |
| filled = truncated | 0x12b8 |
| maxed = truncated | 0xffff |
| for abi_version in (0, ver, truncated, filled, maxed): |
| with self.subTest(abi_version=abi_version): |
| _testcapi.pyabiinfo_check(modname, major, minor, 0, |
| build, abi_version) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| @subTests('offset', (+0x00010000, -0x00010000)) |
| def test_negative_regular(self, modname, minor, build, offset): |
| ver = sys.hexversion + offset |
| truncated = ver & 0xffff0000 |
| filled = truncated | 0x12b8 |
| maxed = truncated | 0xffff |
| for abi_version in (ver, truncated, filled, maxed): |
| with self.subTest(abi_version=abi_version): |
| with self.assertRaisesRegex( |
| ImportError, |
| r'incompatible ABI version \(3\.\d+\)$'): |
| _testcapi.pyabiinfo_check(modname, 1, minor, 0, |
| build, |
| abi_version) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('major', (0, 1)) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| @subTests('abi_version', ( |
| 0, |
| 0x03020000, |
| sys.hexversion, |
| sys.hexversion & 0xffff0000, |
| sys.hexversion - 0x00010000, |
| )) |
| def test_positive_stable(self, modname, major, minor, build, abi_version): |
| _testcapi.pyabiinfo_check(modname, major, minor, |
| _testcapi.PyABIInfo_STABLE, |
| build, |
| abi_version) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| @subTests('abi_version_and_msg', ( |
| (1, 'invalid'), |
| (3, 'invalid'), |
| (0x0301ffff, 'invalid'), |
| ((sys.hexversion & 0xffff0000) + 0x00010000, 'incompatible future'), |
| (sys.hexversion + 0x00010000, 'incompatible future'), |
| (0x04000000, 'incompatible future'), |
| )) |
| def test_negative_stable(self, modname, minor, build, abi_version_and_msg): |
| abi_version, msg = abi_version_and_msg |
| with self.assertRaisesRegex( |
| ImportError, |
| rf'{msg} stable ABI version \(\d+\.\d+\)$'): |
| _testcapi.pyabiinfo_check(modname, 1, minor, |
| _testcapi.PyABIInfo_STABLE, |
| build, |
| abi_version) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('major', (0, 1)) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| @subTests('abi_version', (0, sys.hexversion)) |
| def test_positive_internal(self, modname, major, minor, build, abi_version): |
| _testcapi.pyabiinfo_check(modname, major, minor, |
| _testcapi.PyABIInfo_INTERNAL, |
| build, |
| abi_version) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| @subTests('abi_version', ( |
| sys.hexversion - 0x00010000, |
| sys.hexversion - 1, |
| sys.hexversion + 1, |
| sys.hexversion + 0x00010000, |
| )) |
| def test_negative_internal(self, modname, minor, build, abi_version): |
| with self.assertRaisesRegex( |
| ImportError, |
| r'incompatible internal ABI \(0x[\da-f]+ != 0x[\da-f]+\)$'): |
| _testcapi.pyabiinfo_check(modname, 1, minor, |
| _testcapi.PyABIInfo_INTERNAL, |
| build, |
| abi_version) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| @subTests('ft_flag', ( |
| 0, |
| (_testcapi.PyABIInfo_FREETHREADED |
| if sysconfig.get_config_var("Py_GIL_DISABLED") |
| else _testcapi.PyABIInfo_GIL), |
| _testcapi.PyABIInfo_FREETHREADING_AGNOSTIC, |
| )) |
| def test_positive_freethreading(self, modname, minor, build, ft_flag): |
| self.assertEqual(ft_flag & _testcapi.PyABIInfo_FREETHREADING_AGNOSTIC, |
| ft_flag) |
| _testcapi.pyabiinfo_check(modname, 1, minor, ft_flag, build, 0) |
| |
| @subTests('modname', (None, 'test_mod')) |
| @subTests('minor', (0, 1, 9)) |
| @subTests('build', (0, sys.hexversion)) |
| def test_negative_freethreading(self, modname, minor, build): |
| if sysconfig.get_config_var("Py_GIL_DISABLED"): |
| ft_flag = _testcapi.PyABIInfo_GIL |
| msg = "incompatible with free-threaded CPython" |
| else: |
| ft_flag = _testcapi.PyABIInfo_FREETHREADED |
| msg = "only compatible with free-threaded CPython" |
| with self.assertRaisesRegex(ImportError, msg): |
| _testcapi.pyabiinfo_check(modname, 1, minor, ft_flag, build, 0) |