gh-155503: Add more PyType C API tests (#155505) · python/cpython@29837a9

GitHub

@@ -2,6 +2,9 @@

22importunittest

3344_testcapi=import_helper.import_module('_testcapi')

5+_testlimitedcapi=import_helper.import_module('_testlimitedcapi')

6+7+NULL=None

5869710classBuiltinStaticTypesTests(unittest.TestCase):

@@ -39,15 +42,18 @@ def test_tp_mro_is_set(self):

39424043classTypeTests(unittest.TestCase):

4144deftest_get_type_name(self):

45+# Test PyType_GetName(), PyType_GetQualName(),

46+# PyType_GetFullyQualifiedName() and PyType_GetModuleName().

47+4248classMyType:

4349pass

445045-from_testcapiimport (

51+from_testlimitedcapiimport (

4652get_type_name, get_type_qualname,

4753get_type_fullyqualname, get_type_module_name)

48544955fromcollectionsimportOrderedDict

50-ht=_testcapi.get_heaptype_for_name()

56+ht=_testlimitedcapi.get_heaptype_for_name()

5157forcls, fullname, modname, qualname, namein (

5258 (int,

5359'int',

@@ -107,6 +113,15 @@ class MyType:

107113MyType.__module__=123

108114self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')

109115116+# CRASHES get_type_name(NULL)

117+# CRASHES get_type_qualname(NULL)

118+# CRASHES get_type_fullyqualname(NULL)

119+# CRASHES get_type_module_name(NULL)

120+# CRASHES get_type_name(object()): argument must be a type

121+# CRASHES get_type_qualname(object()): argument must be a type

122+# CRASHES get_type_fullyqualname(object()): argument must be a type

123+# CRASHES get_type_module_name(object()): argument must be a type

124+110125deftest_get_base_by_token(self):

111126defget_base_by_token(src, key, comparable=True):

112127defrun(use_mro):

@@ -215,7 +230,7 @@ class H2(int): pass

215230216231deftest_freeze(self):

217232# test PyType_Freeze()

218-type_freeze=_testcapi.type_freeze

233+type_freeze=_testlimitedcapi.type_freeze

219234220235# simple case, no inherante

221236classMyType:

@@ -245,12 +260,15 @@ class D(A, C): pass

245260# as well

246261type_freeze(D)

247262263+# CRASHES type_freeze(NULL)

264+# CRASHES type_freeze(object()): argument must be a type

[email protected](

249267Py_GIL_DISABLEDandrefleak_helper.hunting_for_refleaks(),

250268"Specialization failure triggers gh-127773")

251269deftest_freeze_meta(self):

252270"""test PyType_Freeze() with overridden MRO"""

253-type_freeze=_testcapi.type_freeze

271+type_freeze=_testlimitedcapi.type_freeze

254272255273classBase:

256274value=1

@@ -299,3 +317,181 @@ def test_extension_managed_weakref_nogc_type(self):

299317"flag but not Py_TPFLAGS_HAVE_GC flag")

300318withself.assertRaisesRegex(SystemError, msg):

301319_testcapi.create_managed_weakref_nogc_type()

320+321+deftest_type_ready(self):

322+# Test PyType_Ready(): calling it on initialized types

323+# must not raise an exception.

324+type_ready=_testlimitedcapi.type_ready

325+326+classHeapType:

327+pass

328+329+type_ready(int)

330+type_ready(dict)

331+type_ready(HeapType)

332+333+# CRASHES type_ready(NULL)

334+# CRASHES type_ready(123): argument must be a type

335+336+deftest_type_clearcache(self):

337+# Test PyType_ClearCache()

338+type_clearcache=_testlimitedcapi.type_clearcache

339+version_tag=type_clearcache()

340+self.assertEqual(type(version_tag), int)

341+self.assertGreaterEqual(version_tag, 0)

342+343+deftest_type_getflags(self):

344+# Test PyType_GetFlags()

345+type_getflags=_testlimitedcapi.type_getflags

346+347+from_testlimitedcapiimport (

348+Py_TPFLAGS_HEAPTYPE,

349+Py_TPFLAGS_HAVE_GC,

350+Py_TPFLAGS_HAVE_FINALIZE,

351+Py_TPFLAGS_HAVE_VERSION_TAG,

352+Py_TPFLAGS_VALID_VERSION_TAG,

353+Py_TPFLAGS_HAVE_VECTORCALL,

354+Py_TPFLAGS_DISALLOW_INSTANTIATION,

355+Py_TPFLAGS_IMMUTABLETYPE,

356+Py_TPFLAGS_READY,

357+Py_TPFLAGS_READYING,

358+Py_TPFLAGS_LONG_SUBCLASS,

359+Py_TPFLAGS_LIST_SUBCLASS,

360+Py_TPFLAGS_TUPLE_SUBCLASS,

361+Py_TPFLAGS_BYTES_SUBCLASS,

362+Py_TPFLAGS_UNICODE_SUBCLASS,

363+Py_TPFLAGS_DICT_SUBCLASS,

364+Py_TPFLAGS_BASE_EXC_SUBCLASS,

365+Py_TPFLAGS_TYPE_SUBCLASS,

366+Py_TPFLAGS_IS_ABSTRACT,

367+Py_TPFLAGS_BASETYPE,

368+_Py_TPFLAGS_MATCH_SELF,

369+Py_TPFLAGS_ITEMS_AT_END,

370+Py_TPFLAGS_METHOD_DESCRIPTOR,

371+ )

372+from_testcapiimport (

373+_Py_TPFLAGS_STATIC_BUILTIN,

374+Py_TPFLAGS_SEQUENCE,

375+Py_TPFLAGS_MAPPING,

376+Py_TPFLAGS_INLINE_VALUES,

377+Py_TPFLAGS_MANAGED_WEAKREF,

378+Py_TPFLAGS_MANAGED_DICT,

379+ )

380+381+defcheck_flag(flags, flag, expected):

382+self.assertEqual(bool(flags&flag), expected)

383+384+defcheck_subclasses(test_type, flags):

385+forflag, base_typein (

386+ (Py_TPFLAGS_LONG_SUBCLASS, int),

387+ (Py_TPFLAGS_LIST_SUBCLASS, list),

388+ (Py_TPFLAGS_TUPLE_SUBCLASS, tuple),

389+ (Py_TPFLAGS_BYTES_SUBCLASS, bytes),

390+ (Py_TPFLAGS_UNICODE_SUBCLASS, str),

391+ (Py_TPFLAGS_DICT_SUBCLASS, dict),

392+ (Py_TPFLAGS_BASE_EXC_SUBCLASS, BaseException),

393+ (Py_TPFLAGS_TYPE_SUBCLASS, type),

394+ ):

395+withself.subTest(test_type=test_type, flag=flag, base_type=base_type):

396+check_flag(flags, flag, issubclass(test_type, base_type))

397+398+defcheck_type(test_type, static_type, have_gc=False, have_vectorcall=False,

399+is_base_type=True, sequence=False, mapping=False,

400+match_self=True, items_at_end=False):

401+heap_type=notstatic_type

402+403+flags=type_getflags(test_type)

404+check_flag(flags, _Py_TPFLAGS_STATIC_BUILTIN, static_type)

405+check_flag(flags, Py_TPFLAGS_HEAPTYPE, heap_type)

406+check_flag(flags, Py_TPFLAGS_HAVE_GC, have_gc)

407+check_subclasses(test_type, flags)

408+check_flag(flags, Py_TPFLAGS_HAVE_VECTORCALL, have_vectorcall)

409+check_flag(flags, Py_TPFLAGS_DISALLOW_INSTANTIATION, False)

410+check_flag(flags, Py_TPFLAGS_IMMUTABLETYPE, static_type)

411+check_flag(flags, Py_TPFLAGS_READY, True)

412+check_flag(flags, Py_TPFLAGS_READYING, False)

413+check_flag(flags, Py_TPFLAGS_IS_ABSTRACT, False)

414+check_flag(flags, Py_TPFLAGS_BASETYPE, is_base_type)

415+check_flag(flags, Py_TPFLAGS_SEQUENCE, sequence)

416+check_flag(flags, Py_TPFLAGS_MAPPING, mapping)

417+418+check_flag(flags, Py_TPFLAGS_INLINE_VALUES, heap_type)

419+check_flag(flags, Py_TPFLAGS_MANAGED_WEAKREF, heap_type)

420+check_flag(flags, Py_TPFLAGS_MANAGED_DICT, heap_type)

421+check_flag(flags, Py_TPFLAGS_ITEMS_AT_END, items_at_end)

422+check_flag(flags, Py_TPFLAGS_METHOD_DESCRIPTOR, False)

423+424+check_flag(flags, _Py_TPFLAGS_MATCH_SELF, match_self)

425+426+# Flags kept for backward compatibility

427+check_flag(flags, Py_TPFLAGS_HAVE_FINALIZE, False)

428+check_flag(flags, Py_TPFLAGS_HAVE_VERSION_TAG, False)

429+check_flag(flags, Py_TPFLAGS_VALID_VERSION_TAG, False)

430+431+# Scalar types

432+check_type(int, static_type=True)

433+check_type(bool, static_type=True,

434+is_base_type=False)

435+check_type(float, static_type=True)

436+check_type(complex, static_type=True,

437+match_self=False)

438+check_type(bytes, static_type=True)

439+check_type(bytearray, static_type=True)

440+check_type(str, static_type=True)

441+442+# Collection types

443+check_type(tuple, static_type=True, have_gc=True,

444+sequence=True)

445+check_type(list, static_type=True, have_gc=True,

446+sequence=True)

447+check_type(dict, static_type=True, have_gc=True,

448+mapping=True)

449+check_type(frozendict, static_type=True, have_gc=True,

450+mapping=True)

451+check_type(set, static_type=True, have_gc=True)

452+check_type(frozenset, static_type=True, have_gc=True)

453+454+# Other types

455+check_type(BaseException, static_type=True, have_gc=True,

456+match_self=False)

457+check_type(type, static_type=True, have_gc=True,

458+have_vectorcall=True,

459+match_self=False,

460+items_at_end=True)

461+462+# Heap type

463+classHeapType:

464+pass

465+check_type(HeapType, static_type=False, have_gc=True, match_self=False)

466+467+# CRASHES type_getflags(NULL)

468+469+deftest_type_issubtype(self):

470+# Test PyType_IsSubtype()

471+_type_issubtype=_testlimitedcapi.type_issubtype

472+473+deftype_issubtype(type1, type2):

474+res=_type_issubtype(type1, type2)

475+self.assertIn(res, (0, 1))

476+returnbool(res)

477+478+classMyList(list):

479+pass

480+481+self.assertTrue(type_issubtype(bool, int))

482+self.assertTrue(type_issubtype(MyList, list))

483+484+self.assertFalse(type_issubtype(int, type))

485+self.assertFalse(type_issubtype(frozendict, dict))

486+self.assertFalse(type_issubtype(MyList, tuple))

487+488+deftest_type_modified(self):

489+# Test PyType_Modified()

490+type_modified=_testlimitedcapi.type_modified

491+492+classMyType:

493+pass

494+type_modified(MyType)

495+496+# CRASHES type_modified(NULL)

497+# CRASHES type_modified({}): argument must be a type