Skip to content

Commit a2b620c

Browse files
shihai1991Fidget-Spinner
authored andcommitted
bpo-41832: PyType_FromModuleAndSpec() now accepts NULL tp_doc (pythonGH-23123)
1 parent e6aa45f commit a2b620c

File tree

5 files changed

+72
-2
lines changed

5 files changed

+72
-2
lines changed

Doc/c-api/type.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ The following functions and structs are used to create
172172
173173
.. versionadded:: 3.9
174174
175+
.. versionchanged:: 3.10
176+
177+
The function now accepts NULL ``tp_doc`` slot.
178+
175179
.. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
176180
177181
Equivalent to ``PyType_FromModuleAndSpec(NULL, spec, bases)``.
@@ -263,5 +267,3 @@ The following functions and structs are used to create
263267
264268
The desired value of the slot. In most cases, this is a pointer
265269
to a function.
266-
267-
May not be ``NULL``.

Lib/test/test_capi.py

+7
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,13 @@ def __del__(self):
398398
del L
399399
self.assertEqual(PyList.num, 0)
400400

401+
def test_heap_ctype_doc_and_text_signature(self):
402+
self.assertEqual(_testcapi.HeapDocCType.__doc__, "somedoc")
403+
self.assertEqual(_testcapi.HeapDocCType.__text_signature__, "(arg1, arg2)")
404+
405+
def test_null_type_doc(self):
406+
self.assertEqual(_testcapi.NullTpDocType.__doc__, None)
407+
401408
def test_subclass_of_heap_gc_ctype_with_tpdealloc_decrefs_once(self):
402409
class HeapGcCTypeSubclass(_testcapi.HeapGcCType):
403410
def __init__(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The :c:func:`PyType_FromModuleAndSpec` function now accepts NULL ``tp_doc``
2+
slot.

Modules/_testcapimodule.c

+55
Original file line numberDiff line numberDiff line change
@@ -6215,6 +6215,47 @@ static PyTypeObject MethodDescriptor2_Type = {
62156215
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
62166216
};
62176217

6218+
PyDoc_STRVAR(heapdocctype__doc__,
6219+
"HeapDocCType(arg1, arg2)\n"
6220+
"--\n"
6221+
"\n"
6222+
"somedoc");
6223+
6224+
typedef struct {
6225+
PyObject_HEAD
6226+
} HeapDocCTypeObject;
6227+
6228+
static PyType_Slot HeapDocCType_slots[] = {
6229+
{Py_tp_doc, (char*)heapdocctype__doc__},
6230+
{0},
6231+
};
6232+
6233+
static PyType_Spec HeapDocCType_spec = {
6234+
"_testcapi.HeapDocCType",
6235+
sizeof(HeapDocCTypeObject),
6236+
0,
6237+
Py_TPFLAGS_DEFAULT,
6238+
HeapDocCType_slots
6239+
};
6240+
6241+
typedef struct {
6242+
PyObject_HEAD
6243+
} NullTpDocTypeObject;
6244+
6245+
static PyType_Slot NullTpDocType_slots[] = {
6246+
{Py_tp_doc, NULL},
6247+
{0, 0},
6248+
};
6249+
6250+
static PyType_Spec NullTpDocType_spec = {
6251+
"_testcapi.NullTpDocType",
6252+
sizeof(NullTpDocTypeObject),
6253+
0,
6254+
Py_TPFLAGS_DEFAULT,
6255+
NullTpDocType_slots
6256+
};
6257+
6258+
62186259
PyDoc_STRVAR(heapgctype__doc__,
62196260
"A heap type with GC, and with overridden dealloc.\n\n"
62206261
"The 'value' attribute is set to 10 in __init__.");
@@ -6883,6 +6924,20 @@ PyInit__testcapi(void)
68836924
Py_INCREF(TestError);
68846925
PyModule_AddObject(m, "error", TestError);
68856926

6927+
PyObject *HeapDocCType = PyType_FromSpec(&HeapDocCType_spec);
6928+
if (HeapDocCType == NULL) {
6929+
return NULL;
6930+
}
6931+
PyModule_AddObject(m, "HeapDocCType", HeapDocCType);
6932+
6933+
/* bpo-41832: Add a new type to test PyType_FromSpec()
6934+
now can accept a NULL tp_doc slot. */
6935+
PyObject *NullTpDocType = PyType_FromSpec(&NullTpDocType_spec);
6936+
if (NullTpDocType == NULL) {
6937+
return NULL;
6938+
}
6939+
PyModule_AddObject(m, "NullTpDocType", NullTpDocType);
6940+
68866941
PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec);
68876942
if (HeapGcCType == NULL) {
68886943
return NULL;

Objects/typeobject.c

+4
Original file line numberDiff line numberDiff line change
@@ -3015,6 +3015,10 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
30153015
else if (slot->slot == Py_tp_doc) {
30163016
/* For the docstring slot, which usually points to a static string
30173017
literal, we need to make a copy */
3018+
if (slot->pfunc == NULL) {
3019+
type->tp_doc = NULL;
3020+
continue;
3021+
}
30183022
const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot->pfunc);
30193023
size_t len = strlen(old_doc)+1;
30203024
char *tp_doc = PyObject_MALLOC(len);

0 commit comments

Comments
 (0)