Skip to content

Commit b258994

Browse files
committed
Address Serhiy's review
* Accept None: treat None as NULL * Fix typo in _PyTestLimitedCAPI_Init_Type(): return -1 on error. * Add test_type_modified(). * Move PyType_IsSubtype() result check to Python.
1 parent 1a238a6 commit b258994

3 files changed

Lines changed: 69 additions & 21 deletions

File tree

Lib/test/test_capi/test_type.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
_testcapi = import_helper.import_module('_testcapi')
55
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
66

7+
NULL = None
8+
79

810
class BuiltinStaticTypesTests(unittest.TestCase):
911

@@ -111,6 +113,11 @@ class MyType:
111113
MyType.__module__ = 123
112114
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
113115

116+
# 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+
114121
def test_get_base_by_token(self):
115122
def get_base_by_token(src, key, comparable=True):
116123
def run(use_mro):
@@ -249,6 +256,8 @@ class D(A, C): pass
249256
# as well
250257
type_freeze(D)
251258

259+
# CRASHES type_freeze(NULL)
260+
252261
@unittest.skipIf(
253262
Py_GIL_DISABLED and refleak_helper.hunting_for_refleaks(),
254263
"Specialization failure triggers gh-127773")
@@ -316,6 +325,8 @@ class HeapType:
316325
type_ready(dict)
317326
type_ready(HeapType)
318327

328+
# CRASHES type_ready(NULL)
329+
319330
def test_type_clearcache(self):
320331
# Test PyType_ClearCache()
321332
type_clearcache = _testlimitedcapi.type_clearcache
@@ -447,9 +458,16 @@ class HeapType:
447458
pass
448459
check_type(HeapType, static_type=False, have_gc=True, match_self=False)
449460

461+
# CRASHES type_getflags(NULL)
462+
450463
def test_type_issubtype(self):
451464
# Test PyType_IsSubtype()
452-
type_issubtype = _testlimitedcapi.type_issubtype
465+
_type_issubtype = _testlimitedcapi.type_issubtype
466+
467+
def type_issubtype(type1, type2):
468+
res = _type_issubtype(type1, type2)
469+
self.assertIn(res, (0, 1))
470+
return bool(res)
453471

454472
class MyList(list):
455473
pass
@@ -460,3 +478,13 @@ class MyList(list):
460478
self.assertFalse(type_issubtype(int, type))
461479
self.assertFalse(type_issubtype(frozendict, dict))
462480
self.assertFalse(type_issubtype(MyList, tuple))
481+
482+
def test_type_modified(self):
483+
# Test PyType_Modified()
484+
type_modified = _testlimitedcapi.type_modified
485+
486+
class MyType:
487+
pass
488+
type_modified(MyType)
489+
490+
# CRASHES type_modified(NULL)

Modules/_testcapi/type.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored))
9898
static int
9999
check_type_arg(PyObject *arg)
100100
{
101+
if (arg == NULL) {
102+
return 0;
103+
}
101104
if (!PyType_Check(arg)) {
102105
PyErr_SetString(PyExc_TypeError, "argument must be a type");
103106
return -1;
@@ -110,6 +113,7 @@ check_type_arg(PyObject *arg)
110113
static PyObject *
111114
type_get_version(PyObject *self, PyObject *arg)
112115
{
116+
NULLABLE(arg);
113117
if (check_type_arg(arg) < 0) {
114118
return NULL;
115119
}
@@ -128,6 +132,7 @@ type_get_version(PyObject *self, PyObject *arg)
128132
static PyObject *
129133
type_assign_version(PyObject *self, PyObject *arg)
130134
{
135+
NULLABLE(arg);
131136
if (check_type_arg(arg) < 0) {
132137
return NULL;
133138
}
@@ -142,6 +147,7 @@ type_assign_version(PyObject *self, PyObject *arg)
142147
static PyObject *
143148
type_get_tp_bases(PyObject *self, PyObject *arg)
144149
{
150+
NULLABLE(arg);
145151
if (check_type_arg(arg) < 0) {
146152
return NULL;
147153
}
@@ -159,6 +165,7 @@ type_get_tp_bases(PyObject *self, PyObject *arg)
159165
static PyObject *
160166
type_get_tp_mro(PyObject *self, PyObject *arg)
161167
{
168+
NULLABLE(arg);
162169
if (check_type_arg(arg) < 0) {
163170
return NULL;
164171
}

Modules/_testlimitedcapi/type.c

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored))
3131
static int
3232
check_type_arg(PyObject *arg)
3333
{
34+
if (arg == NULL) {
35+
return 0;
36+
}
3437
if (!PyType_Check(arg)) {
3538
PyErr_SetString(PyExc_TypeError, "argument must be a type");
3639
return -1;
@@ -41,52 +44,65 @@ check_type_arg(PyObject *arg)
4144

4245
// Test PyType_GetName()
4346
static PyObject*
44-
get_type_name(PyObject *self, PyObject *type)
47+
get_type_name(PyObject *self, PyObject *arg)
4548
{
46-
if (check_type_arg(type) < 0) {
49+
NULLABLE(arg);
50+
if (check_type_arg(arg) < 0) {
4751
return NULL;
4852
}
49-
return PyType_GetName((PyTypeObject *)type);
53+
PyTypeObject *type = (PyTypeObject*)arg;
54+
55+
return PyType_GetName(type);
5056
}
5157

5258

5359
// Test PyType_GetQualName()
5460
static PyObject*
55-
get_type_qualname(PyObject *self, PyObject *type)
61+
get_type_qualname(PyObject *self, PyObject *arg)
5662
{
57-
if (check_type_arg(type) < 0) {
63+
NULLABLE(arg);
64+
if (check_type_arg(arg) < 0) {
5865
return NULL;
5966
}
60-
return PyType_GetQualName((PyTypeObject *)type);
67+
PyTypeObject *type = (PyTypeObject*)arg;
68+
69+
return PyType_GetQualName(type);
6170
}
6271

6372

6473
// Test PyType_GetFullyQualifiedName()
6574
static PyObject*
66-
get_type_fullyqualname(PyObject *self, PyObject *type)
75+
get_type_fullyqualname(PyObject *self, PyObject *arg)
6776
{
68-
if (check_type_arg(type) < 0) {
77+
NULLABLE(arg);
78+
if (check_type_arg(arg) < 0) {
6979
return NULL;
7080
}
71-
return PyType_GetFullyQualifiedName((PyTypeObject *)type);
81+
PyTypeObject *type = (PyTypeObject*)arg;
82+
83+
return PyType_GetFullyQualifiedName(type);
7284
}
7385

7486

7587
// Test PyType_GetModuleName()
7688
static PyObject*
77-
get_type_module_name(PyObject *self, PyObject *type)
89+
get_type_module_name(PyObject *self, PyObject *arg)
7890
{
79-
if (check_type_arg(type) < 0) {
91+
NULLABLE(arg);
92+
if (check_type_arg(arg) < 0) {
8093
return NULL;
8194
}
82-
return PyType_GetModuleName((PyTypeObject *)type);
95+
PyTypeObject *type = (PyTypeObject*)arg;
96+
97+
return PyType_GetModuleName(type);
8398
}
8499

85100

86101
// Test PyType_Modified()
87102
static PyObject*
88103
type_modified(PyObject *self, PyObject *arg)
89104
{
105+
NULLABLE(arg);
90106
if (check_type_arg(arg) < 0) {
91107
return NULL;
92108
}
@@ -103,6 +119,7 @@ type_ready(PyObject *self, PyObject *arg)
103119
{
104120
assert(!PyErr_Occurred());
105121

122+
NULLABLE(arg);
106123
if (check_type_arg(arg) < 0) {
107124
return NULL;
108125
}
@@ -121,6 +138,7 @@ type_ready(PyObject *self, PyObject *arg)
121138
static PyObject *
122139
type_freeze(PyObject *module, PyObject *arg)
123140
{
141+
NULLABLE(arg);
124142
if (check_type_arg(arg) < 0) {
125143
return NULL;
126144
}
@@ -149,6 +167,7 @@ type_clearcache(PyObject *module, PyObject *Py_UNUSED(arg))
149167
static PyObject *
150168
type_getflags(PyObject *module, PyObject *arg)
151169
{
170+
NULLABLE(arg);
152171
if (check_type_arg(arg) < 0) {
153172
return NULL;
154173
}
@@ -172,13 +191,7 @@ type_issubtype(PyObject *module, PyObject *args)
172191
}
173192

174193
int is_subtype = PyType_IsSubtype(type1, type2);
175-
if (is_subtype != 0 && is_subtype != 1) {
176-
PyErr_Format(PyExc_AssertionError,
177-
"PyType_IsSubtype expected result: %i",
178-
is_subtype);
179-
return NULL;
180-
}
181-
return PyBool_FromLong(is_subtype);
194+
return PyLong_FromLong(is_subtype);
182195
}
183196

184197

@@ -201,7 +214,7 @@ int
201214
_PyTestLimitedCAPI_Init_Type(PyObject *m)
202215
{
203216
if (PyModule_AddFunctions(m, test_methods) < 0) {
204-
return 0;
217+
return -1;
205218
}
206219

207220
#define ADD_INT(macro) \

0 commit comments

Comments
 (0)