Skip to content

Commit 5424e3b

Browse files
authored
gh-93649: Add Modules/_testcapi/type.c file (#129516)
Move PyType C API tests to a new file. Move following tests from test_capi.test_misc to test_capi.test_type: * BuiltinStaticTypesTests * test_get_type_name() * test_get_base_by_token()
1 parent 881984b commit 5424e3b

File tree

8 files changed

+434
-393
lines changed

8 files changed

+434
-393
lines changed

Lib/test/test_capi/test_misc.py

Lines changed: 0 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,147 +1111,6 @@ class Data(_testcapi.ObjExtraData):
11111111
del d.extra
11121112
self.assertIsNone(d.extra)
11131113

1114-
def test_get_type_name(self):
1115-
class MyType:
1116-
pass
1117-
1118-
from _testcapi import (
1119-
get_type_name, get_type_qualname,
1120-
get_type_fullyqualname, get_type_module_name)
1121-
1122-
from collections import OrderedDict
1123-
ht = _testcapi.get_heaptype_for_name()
1124-
for cls, fullname, modname, qualname, name in (
1125-
(int,
1126-
'int',
1127-
'builtins',
1128-
'int',
1129-
'int'),
1130-
(OrderedDict,
1131-
'collections.OrderedDict',
1132-
'collections',
1133-
'OrderedDict',
1134-
'OrderedDict'),
1135-
(ht,
1136-
'_testcapi.HeapTypeNameType',
1137-
'_testcapi',
1138-
'HeapTypeNameType',
1139-
'HeapTypeNameType'),
1140-
(MyType,
1141-
f'{__name__}.CAPITest.test_get_type_name.<locals>.MyType',
1142-
__name__,
1143-
'CAPITest.test_get_type_name.<locals>.MyType',
1144-
'MyType'),
1145-
):
1146-
with self.subTest(cls=repr(cls)):
1147-
self.assertEqual(get_type_fullyqualname(cls), fullname)
1148-
self.assertEqual(get_type_module_name(cls), modname)
1149-
self.assertEqual(get_type_qualname(cls), qualname)
1150-
self.assertEqual(get_type_name(cls), name)
1151-
1152-
# override __module__
1153-
ht.__module__ = 'test_module'
1154-
self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType')
1155-
self.assertEqual(get_type_module_name(ht), 'test_module')
1156-
self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType')
1157-
self.assertEqual(get_type_name(ht), 'HeapTypeNameType')
1158-
1159-
# override __name__ and __qualname__
1160-
MyType.__name__ = 'my_name'
1161-
MyType.__qualname__ = 'my_qualname'
1162-
self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname')
1163-
self.assertEqual(get_type_module_name(MyType), __name__)
1164-
self.assertEqual(get_type_qualname(MyType), 'my_qualname')
1165-
self.assertEqual(get_type_name(MyType), 'my_name')
1166-
1167-
# override also __module__
1168-
MyType.__module__ = 'my_module'
1169-
self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname')
1170-
self.assertEqual(get_type_module_name(MyType), 'my_module')
1171-
self.assertEqual(get_type_qualname(MyType), 'my_qualname')
1172-
self.assertEqual(get_type_name(MyType), 'my_name')
1173-
1174-
# PyType_GetFullyQualifiedName() ignores the module if it's "builtins"
1175-
# or "__main__" of it is not a string
1176-
MyType.__module__ = 'builtins'
1177-
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
1178-
MyType.__module__ = '__main__'
1179-
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
1180-
MyType.__module__ = 123
1181-
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
1182-
1183-
def test_get_base_by_token(self):
1184-
def get_base_by_token(src, key, comparable=True):
1185-
def run(use_mro):
1186-
find_first = _testcapi.pytype_getbasebytoken
1187-
ret1, result = find_first(src, key, use_mro, True)
1188-
ret2, no_result = find_first(src, key, use_mro, False)
1189-
self.assertIn(ret1, (0, 1))
1190-
self.assertEqual(ret1, result is not None)
1191-
self.assertEqual(ret1, ret2)
1192-
self.assertIsNone(no_result)
1193-
return result
1194-
1195-
found_in_mro = run(True)
1196-
found_in_bases = run(False)
1197-
if comparable:
1198-
self.assertIs(found_in_mro, found_in_bases)
1199-
return found_in_mro
1200-
return found_in_mro, found_in_bases
1201-
1202-
create_type = _testcapi.create_type_with_token
1203-
get_token = _testcapi.get_tp_token
1204-
1205-
Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC
1206-
self.assertEqual(Py_TP_USE_SPEC, 0)
1207-
1208-
A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC)
1209-
self.assertTrue(get_token(A1) != Py_TP_USE_SPEC)
1210-
1211-
B1 = create_type('_testcapi.B1', id(self))
1212-
self.assertTrue(get_token(B1) == id(self))
1213-
1214-
tokenA1 = get_token(A1)
1215-
# find A1 from A1
1216-
found = get_base_by_token(A1, tokenA1)
1217-
self.assertIs(found, A1)
1218-
1219-
# no token in static types
1220-
STATIC = type(1)
1221-
self.assertEqual(get_token(STATIC), 0)
1222-
found = get_base_by_token(STATIC, tokenA1)
1223-
self.assertIs(found, None)
1224-
1225-
# no token in pure subtypes
1226-
class A2(A1): pass
1227-
self.assertEqual(get_token(A2), 0)
1228-
# find A1
1229-
class Z(STATIC, B1, A2): pass
1230-
found = get_base_by_token(Z, tokenA1)
1231-
self.assertIs(found, A1)
1232-
1233-
# searching for NULL token is an error
1234-
with self.assertRaises(SystemError):
1235-
get_base_by_token(Z, 0)
1236-
with self.assertRaises(SystemError):
1237-
get_base_by_token(STATIC, 0)
1238-
1239-
# share the token with A1
1240-
C1 = create_type('_testcapi.C1', tokenA1)
1241-
self.assertTrue(get_token(C1) == tokenA1)
1242-
1243-
# find C1 first by shared token
1244-
class Z(C1, A2): pass
1245-
found = get_base_by_token(Z, tokenA1)
1246-
self.assertIs(found, C1)
1247-
# B1 not found
1248-
found = get_base_by_token(Z, get_token(B1))
1249-
self.assertIs(found, None)
1250-
1251-
with self.assertRaises(TypeError):
1252-
_testcapi.pytype_getbasebytoken(
1253-
'not a type', id(self), True, False)
1254-
12551114
def test_gen_get_code(self):
12561115
def genf(): yield
12571116
gen = genf()
@@ -2922,39 +2781,6 @@ def test_linked_lifecycle_link_incref_unlink_decref(self):
29222781
0, get_refcount(interpid))
29232782

29242783

2925-
class BuiltinStaticTypesTests(unittest.TestCase):
2926-
2927-
TYPES = [
2928-
object,
2929-
type,
2930-
int,
2931-
str,
2932-
dict,
2933-
type(None),
2934-
bool,
2935-
BaseException,
2936-
Exception,
2937-
Warning,
2938-
DeprecationWarning, # Warning subclass
2939-
]
2940-
2941-
def test_tp_bases_is_set(self):
2942-
# PyTypeObject.tp_bases is documented as public API.
2943-
# See https://github.com/python/cpython/issues/105020.
2944-
for typeobj in self.TYPES:
2945-
with self.subTest(typeobj):
2946-
bases = _testcapi.type_get_tp_bases(typeobj)
2947-
self.assertIsNot(bases, None)
2948-
2949-
def test_tp_mro_is_set(self):
2950-
# PyTypeObject.tp_bases is documented as public API.
2951-
# See https://github.com/python/cpython/issues/105020.
2952-
for typeobj in self.TYPES:
2953-
with self.subTest(typeobj):
2954-
mro = _testcapi.type_get_tp_mro(typeobj)
2955-
self.assertIsNot(mro, None)
2956-
2957-
29582784
class TestStaticTypes(unittest.TestCase):
29592785

29602786
_has_run = False

Lib/test/test_capi/test_type.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,181 @@
44
_testcapi = import_helper.import_module('_testcapi')
55

66

7+
class BuiltinStaticTypesTests(unittest.TestCase):
8+
9+
TYPES = [
10+
object,
11+
type,
12+
int,
13+
str,
14+
dict,
15+
type(None),
16+
bool,
17+
BaseException,
18+
Exception,
19+
Warning,
20+
DeprecationWarning, # Warning subclass
21+
]
22+
23+
def test_tp_bases_is_set(self):
24+
# PyTypeObject.tp_bases is documented as public API.
25+
# See https://github.com/python/cpython/issues/105020.
26+
for typeobj in self.TYPES:
27+
with self.subTest(typeobj):
28+
bases = _testcapi.type_get_tp_bases(typeobj)
29+
self.assertIsNot(bases, None)
30+
31+
def test_tp_mro_is_set(self):
32+
# PyTypeObject.tp_bases is documented as public API.
33+
# See https://github.com/python/cpython/issues/105020.
34+
for typeobj in self.TYPES:
35+
with self.subTest(typeobj):
36+
mro = _testcapi.type_get_tp_mro(typeobj)
37+
self.assertIsNot(mro, None)
38+
39+
740
class TypeTests(unittest.TestCase):
41+
def test_get_type_name(self):
42+
class MyType:
43+
pass
44+
45+
from _testcapi import (
46+
get_type_name, get_type_qualname,
47+
get_type_fullyqualname, get_type_module_name)
48+
49+
from collections import OrderedDict
50+
ht = _testcapi.get_heaptype_for_name()
51+
for cls, fullname, modname, qualname, name in (
52+
(int,
53+
'int',
54+
'builtins',
55+
'int',
56+
'int'),
57+
(OrderedDict,
58+
'collections.OrderedDict',
59+
'collections',
60+
'OrderedDict',
61+
'OrderedDict'),
62+
(ht,
63+
'_testcapi.HeapTypeNameType',
64+
'_testcapi',
65+
'HeapTypeNameType',
66+
'HeapTypeNameType'),
67+
(MyType,
68+
f'{__name__}.TypeTests.test_get_type_name.<locals>.MyType',
69+
__name__,
70+
'TypeTests.test_get_type_name.<locals>.MyType',
71+
'MyType'),
72+
):
73+
with self.subTest(cls=repr(cls)):
74+
self.assertEqual(get_type_fullyqualname(cls), fullname)
75+
self.assertEqual(get_type_module_name(cls), modname)
76+
self.assertEqual(get_type_qualname(cls), qualname)
77+
self.assertEqual(get_type_name(cls), name)
78+
79+
# override __module__
80+
ht.__module__ = 'test_module'
81+
self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType')
82+
self.assertEqual(get_type_module_name(ht), 'test_module')
83+
self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType')
84+
self.assertEqual(get_type_name(ht), 'HeapTypeNameType')
85+
86+
# override __name__ and __qualname__
87+
MyType.__name__ = 'my_name'
88+
MyType.__qualname__ = 'my_qualname'
89+
self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname')
90+
self.assertEqual(get_type_module_name(MyType), __name__)
91+
self.assertEqual(get_type_qualname(MyType), 'my_qualname')
92+
self.assertEqual(get_type_name(MyType), 'my_name')
93+
94+
# override also __module__
95+
MyType.__module__ = 'my_module'
96+
self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname')
97+
self.assertEqual(get_type_module_name(MyType), 'my_module')
98+
self.assertEqual(get_type_qualname(MyType), 'my_qualname')
99+
self.assertEqual(get_type_name(MyType), 'my_name')
100+
101+
# PyType_GetFullyQualifiedName() ignores the module if it's "builtins"
102+
# or "__main__" of it is not a string
103+
MyType.__module__ = 'builtins'
104+
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
105+
MyType.__module__ = '__main__'
106+
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
107+
MyType.__module__ = 123
108+
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
109+
110+
def test_get_base_by_token(self):
111+
def get_base_by_token(src, key, comparable=True):
112+
def run(use_mro):
113+
find_first = _testcapi.pytype_getbasebytoken
114+
ret1, result = find_first(src, key, use_mro, True)
115+
ret2, no_result = find_first(src, key, use_mro, False)
116+
self.assertIn(ret1, (0, 1))
117+
self.assertEqual(ret1, result is not None)
118+
self.assertEqual(ret1, ret2)
119+
self.assertIsNone(no_result)
120+
return result
121+
122+
found_in_mro = run(True)
123+
found_in_bases = run(False)
124+
if comparable:
125+
self.assertIs(found_in_mro, found_in_bases)
126+
return found_in_mro
127+
return found_in_mro, found_in_bases
128+
129+
create_type = _testcapi.create_type_with_token
130+
get_token = _testcapi.get_tp_token
131+
132+
Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC
133+
self.assertEqual(Py_TP_USE_SPEC, 0)
134+
135+
A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC)
136+
self.assertTrue(get_token(A1) != Py_TP_USE_SPEC)
137+
138+
B1 = create_type('_testcapi.B1', id(self))
139+
self.assertTrue(get_token(B1) == id(self))
140+
141+
tokenA1 = get_token(A1)
142+
# find A1 from A1
143+
found = get_base_by_token(A1, tokenA1)
144+
self.assertIs(found, A1)
145+
146+
# no token in static types
147+
STATIC = type(1)
148+
self.assertEqual(get_token(STATIC), 0)
149+
found = get_base_by_token(STATIC, tokenA1)
150+
self.assertIs(found, None)
151+
152+
# no token in pure subtypes
153+
class A2(A1): pass
154+
self.assertEqual(get_token(A2), 0)
155+
# find A1
156+
class Z(STATIC, B1, A2): pass
157+
found = get_base_by_token(Z, tokenA1)
158+
self.assertIs(found, A1)
159+
160+
# searching for NULL token is an error
161+
with self.assertRaises(SystemError):
162+
get_base_by_token(Z, 0)
163+
with self.assertRaises(SystemError):
164+
get_base_by_token(STATIC, 0)
165+
166+
# share the token with A1
167+
C1 = create_type('_testcapi.C1', tokenA1)
168+
self.assertTrue(get_token(C1) == tokenA1)
169+
170+
# find C1 first by shared token
171+
class Z(C1, A2): pass
172+
found = get_base_by_token(Z, tokenA1)
173+
self.assertIs(found, C1)
174+
# B1 not found
175+
found = get_base_by_token(Z, get_token(B1))
176+
self.assertIs(found, None)
177+
178+
with self.assertRaises(TypeError):
179+
_testcapi.pytype_getbasebytoken(
180+
'not a type', id(self), True, False)
181+
8182
def test_freeze(self):
9183
# test PyType_Freeze()
10184
type_freeze = _testcapi.type_freeze

Modules/Setup.stdlib.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
163163
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
164164
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
165-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c
165+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c
166166
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
167167
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
168168
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c

Modules/_testcapi/parts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,6 @@ int _PyTestCapi_Init_Object(PyObject *module);
6363
int _PyTestCapi_Init_Config(PyObject *mod);
6464
int _PyTestCapi_Init_Import(PyObject *mod);
6565
int _PyTestCapi_Init_Frame(PyObject *mod);
66+
int _PyTestCapi_Init_Type(PyObject *mod);
6667

6768
#endif // Py_TESTCAPI_PARTS_H

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy