|
2 | 2 | import unittest |
3 | 3 |
|
4 | 4 | _testcapi = import_helper.import_module('_testcapi') |
| 5 | +_testlimitedcapi = import_helper.import_module('_testlimitedcapi') |
5 | 6 |
|
6 | 7 |
|
7 | 8 | class BuiltinStaticTypesTests(unittest.TestCase): |
@@ -39,15 +40,18 @@ def test_tp_mro_is_set(self): |
39 | 40 |
|
40 | 41 | class TypeTests(unittest.TestCase): |
41 | 42 | def test_get_type_name(self): |
| 43 | + # Test PyType_GetName(), PyType_GetQualName(), |
| 44 | + # PyType_GetFullyQualifiedName() and PyType_GetModuleName(). |
| 45 | + |
42 | 46 | class MyType: |
43 | 47 | pass |
44 | 48 |
|
45 | | - from _testcapi import ( |
| 49 | + from _testlimitedcapi import ( |
46 | 50 | get_type_name, get_type_qualname, |
47 | 51 | get_type_fullyqualname, get_type_module_name) |
48 | 52 |
|
49 | 53 | from collections import OrderedDict |
50 | | - ht = _testcapi.get_heaptype_for_name() |
| 54 | + ht = _testlimitedcapi.get_heaptype_for_name() |
51 | 55 | for cls, fullname, modname, qualname, name in ( |
52 | 56 | (int, |
53 | 57 | 'int', |
@@ -215,7 +219,7 @@ class H2(int): pass |
215 | 219 |
|
216 | 220 | def test_freeze(self): |
217 | 221 | # test PyType_Freeze() |
218 | | - type_freeze = _testcapi.type_freeze |
| 222 | + type_freeze = _testlimitedcapi.type_freeze |
219 | 223 |
|
220 | 224 | # simple case, no inherante |
221 | 225 | class MyType: |
@@ -250,7 +254,7 @@ class D(A, C): pass |
250 | 254 | "Specialization failure triggers gh-127773") |
251 | 255 | def test_freeze_meta(self): |
252 | 256 | """test PyType_Freeze() with overridden MRO""" |
253 | | - type_freeze = _testcapi.type_freeze |
| 257 | + type_freeze = _testlimitedcapi.type_freeze |
254 | 258 |
|
255 | 259 | class Base: |
256 | 260 | value = 1 |
@@ -299,3 +303,160 @@ def test_extension_managed_weakref_nogc_type(self): |
299 | 303 | "flag but not Py_TPFLAGS_HAVE_GC flag") |
300 | 304 | with self.assertRaisesRegex(SystemError, msg): |
301 | 305 | _testcapi.create_managed_weakref_nogc_type() |
| 306 | + |
| 307 | + def test_type_ready(self): |
| 308 | + # Test PyType_Ready(): calling it on initialized types |
| 309 | + # must not raise an exception. |
| 310 | + type_ready = _testlimitedcapi.type_ready |
| 311 | + |
| 312 | + class HeapType: |
| 313 | + pass |
| 314 | + |
| 315 | + type_ready(int) |
| 316 | + type_ready(dict) |
| 317 | + type_ready(HeapType) |
| 318 | + |
| 319 | + def test_type_clearcache(self): |
| 320 | + # Test PyType_ClearCache() |
| 321 | + type_clearcache = _testlimitedcapi.type_clearcache |
| 322 | + version_tag = type_clearcache() |
| 323 | + self.assertEqual(type(version_tag), int) |
| 324 | + self.assertGreaterEqual(version_tag, 0) |
| 325 | + |
| 326 | + def test_type_getflags(self): |
| 327 | + # Test PyType_GetFlags() |
| 328 | + type_getflags = _testlimitedcapi.type_getflags |
| 329 | + |
| 330 | + from _testlimitedcapi import ( |
| 331 | + Py_TPFLAGS_HEAPTYPE, |
| 332 | + Py_TPFLAGS_HAVE_GC, |
| 333 | + Py_TPFLAGS_HAVE_FINALIZE, |
| 334 | + Py_TPFLAGS_HAVE_VERSION_TAG, |
| 335 | + Py_TPFLAGS_VALID_VERSION_TAG, |
| 336 | + Py_TPFLAGS_HAVE_VECTORCALL, |
| 337 | + Py_TPFLAGS_DISALLOW_INSTANTIATION, |
| 338 | + Py_TPFLAGS_IMMUTABLETYPE, |
| 339 | + Py_TPFLAGS_READY, |
| 340 | + Py_TPFLAGS_READYING, |
| 341 | + Py_TPFLAGS_LONG_SUBCLASS, |
| 342 | + Py_TPFLAGS_LIST_SUBCLASS, |
| 343 | + Py_TPFLAGS_TUPLE_SUBCLASS, |
| 344 | + Py_TPFLAGS_BYTES_SUBCLASS, |
| 345 | + Py_TPFLAGS_UNICODE_SUBCLASS, |
| 346 | + Py_TPFLAGS_DICT_SUBCLASS, |
| 347 | + Py_TPFLAGS_BASE_EXC_SUBCLASS, |
| 348 | + Py_TPFLAGS_TYPE_SUBCLASS, |
| 349 | + Py_TPFLAGS_IS_ABSTRACT, |
| 350 | + Py_TPFLAGS_BASETYPE, |
| 351 | + _Py_TPFLAGS_MATCH_SELF, |
| 352 | + Py_TPFLAGS_ITEMS_AT_END, |
| 353 | + Py_TPFLAGS_METHOD_DESCRIPTOR, |
| 354 | + ) |
| 355 | + from _testcapi import ( |
| 356 | + _Py_TPFLAGS_STATIC_BUILTIN, |
| 357 | + Py_TPFLAGS_SEQUENCE, |
| 358 | + Py_TPFLAGS_MAPPING, |
| 359 | + Py_TPFLAGS_INLINE_VALUES, |
| 360 | + Py_TPFLAGS_MANAGED_WEAKREF, |
| 361 | + Py_TPFLAGS_MANAGED_DICT, |
| 362 | + ) |
| 363 | + |
| 364 | + def check_flag(flags, flag, expected): |
| 365 | + self.assertEqual(bool(flags & flag), expected) |
| 366 | + |
| 367 | + def check_subclasses(test_type, flags): |
| 368 | + for flag, base_type in ( |
| 369 | + (Py_TPFLAGS_LONG_SUBCLASS, int), |
| 370 | + (Py_TPFLAGS_LIST_SUBCLASS, list), |
| 371 | + (Py_TPFLAGS_TUPLE_SUBCLASS, tuple), |
| 372 | + (Py_TPFLAGS_BYTES_SUBCLASS, bytes), |
| 373 | + (Py_TPFLAGS_UNICODE_SUBCLASS, str), |
| 374 | + (Py_TPFLAGS_DICT_SUBCLASS, dict), |
| 375 | + (Py_TPFLAGS_BASE_EXC_SUBCLASS, BaseException), |
| 376 | + (Py_TPFLAGS_TYPE_SUBCLASS, type), |
| 377 | + ): |
| 378 | + with self.subTest(test_type=test_type, flag=flag, base_type=base_type): |
| 379 | + check_flag(flags, flag, issubclass(test_type, base_type)) |
| 380 | + |
| 381 | + def check_type(test_type, static_type, have_gc=False, have_vectorcall=False, |
| 382 | + is_base_type=True, sequence=False, mapping=False, |
| 383 | + match_self=True, items_at_end=False): |
| 384 | + heap_type = not static_type |
| 385 | + |
| 386 | + flags = type_getflags(test_type) |
| 387 | + check_flag(flags, _Py_TPFLAGS_STATIC_BUILTIN, static_type) |
| 388 | + check_flag(flags, Py_TPFLAGS_HEAPTYPE, heap_type) |
| 389 | + check_flag(flags, Py_TPFLAGS_HAVE_GC, have_gc) |
| 390 | + check_subclasses(test_type, flags) |
| 391 | + check_flag(flags, Py_TPFLAGS_HAVE_VECTORCALL, have_vectorcall) |
| 392 | + check_flag(flags, Py_TPFLAGS_DISALLOW_INSTANTIATION, False) |
| 393 | + check_flag(flags, Py_TPFLAGS_IMMUTABLETYPE, static_type) |
| 394 | + check_flag(flags, Py_TPFLAGS_READY, True) |
| 395 | + check_flag(flags, Py_TPFLAGS_READYING, False) |
| 396 | + check_flag(flags, Py_TPFLAGS_IS_ABSTRACT, False) |
| 397 | + check_flag(flags, Py_TPFLAGS_BASETYPE, is_base_type) |
| 398 | + check_flag(flags, Py_TPFLAGS_SEQUENCE, sequence) |
| 399 | + check_flag(flags, Py_TPFLAGS_MAPPING, mapping) |
| 400 | + |
| 401 | + check_flag(flags, Py_TPFLAGS_INLINE_VALUES, heap_type) |
| 402 | + check_flag(flags, Py_TPFLAGS_MANAGED_WEAKREF, heap_type) |
| 403 | + check_flag(flags, Py_TPFLAGS_MANAGED_DICT, heap_type) |
| 404 | + check_flag(flags, Py_TPFLAGS_ITEMS_AT_END, items_at_end) |
| 405 | + check_flag(flags, Py_TPFLAGS_METHOD_DESCRIPTOR, False) |
| 406 | + |
| 407 | + check_flag(flags, _Py_TPFLAGS_MATCH_SELF, match_self) |
| 408 | + |
| 409 | + # Flags kept for backward compatibility |
| 410 | + check_flag(flags, Py_TPFLAGS_HAVE_FINALIZE, False) |
| 411 | + check_flag(flags, Py_TPFLAGS_HAVE_VERSION_TAG, False) |
| 412 | + check_flag(flags, Py_TPFLAGS_VALID_VERSION_TAG, False) |
| 413 | + |
| 414 | + # Scalar types |
| 415 | + check_type(int, static_type=True) |
| 416 | + check_type(bool, static_type=True, |
| 417 | + is_base_type=False) |
| 418 | + check_type(float, static_type=True) |
| 419 | + check_type(complex, static_type=True, |
| 420 | + match_self=False) |
| 421 | + check_type(bytes, static_type=True) |
| 422 | + check_type(bytearray, static_type=True) |
| 423 | + check_type(str, static_type=True) |
| 424 | + |
| 425 | + # Collection types |
| 426 | + check_type(tuple, static_type=True, have_gc=True, |
| 427 | + sequence=True) |
| 428 | + check_type(list, static_type=True, have_gc=True, |
| 429 | + sequence=True) |
| 430 | + check_type(dict, static_type=True, have_gc=True, |
| 431 | + mapping=True) |
| 432 | + check_type(frozendict, static_type=True, have_gc=True, |
| 433 | + mapping=True) |
| 434 | + check_type(set, static_type=True, have_gc=True) |
| 435 | + check_type(frozenset, static_type=True, have_gc=True) |
| 436 | + |
| 437 | + # Other types |
| 438 | + check_type(BaseException, static_type=True, have_gc=True, |
| 439 | + match_self=False) |
| 440 | + check_type(type, static_type=True, have_gc=True, |
| 441 | + have_vectorcall=True, |
| 442 | + match_self=False, |
| 443 | + items_at_end=True) |
| 444 | + |
| 445 | + # Heap type |
| 446 | + class HeapType: |
| 447 | + pass |
| 448 | + check_type(HeapType, static_type=False, have_gc=True, match_self=False) |
| 449 | + |
| 450 | + def test_type_issubtype(self): |
| 451 | + # Test PyType_IsSubtype() |
| 452 | + type_issubtype = _testlimitedcapi.type_issubtype |
| 453 | + |
| 454 | + class MyList(list): |
| 455 | + pass |
| 456 | + |
| 457 | + self.assertTrue(type_issubtype(bool, int)) |
| 458 | + self.assertTrue(type_issubtype(MyList, list)) |
| 459 | + |
| 460 | + self.assertFalse(type_issubtype(int, type)) |
| 461 | + self.assertFalse(type_issubtype(frozendict, dict)) |
| 462 | + self.assertFalse(type_issubtype(MyList, tuple)) |
0 commit comments