diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 73f26875d81..fcd92e38e24 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -169,6 +169,10 @@ The following functions and structs are used to create .. versionadded:: 3.9 + .. versionchanged:: 3.10 + + The function now accepts NULL ``tp_doc`` slot. + .. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) Equivalent to ``PyType_FromModuleAndSpec(NULL, spec, bases)``. @@ -259,5 +263,3 @@ The following functions and structs are used to create The desired value of the slot. In most cases, this is a pointer to a function. - - May not be ``NULL``. diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 0ed7084ccd2..1e6c7c4067f 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -401,6 +401,10 @@ New Features reference count of an object and return the object. (Contributed by Victor Stinner in :issue:`42262`.) +* The :c:func:`PyType_FromModuleAndSpec` function now accepts NULL ``tp_doc`` + slot. + (Contributed by Hai Shi in :issue:`41832`.) + Porting to Python 3.10 ---------------------- diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index db62b47100a..a4ebe4a0a1b 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -405,6 +405,9 @@ class CAPITest(unittest.TestCase): self.assertEqual(_testcapi.HeapDocCType.__doc__, "somedoc") self.assertEqual(_testcapi.HeapDocCType.__text_signature__, "(arg1, arg2)") + def test_null_type_doc(self): + self.assertEqual(_testcapi.NullTpDocType.__doc__, None) + def test_subclass_of_heap_gc_ctype_with_tpdealloc_decrefs_once(self): class HeapGcCTypeSubclass(_testcapi.HeapGcCType): def __init__(self): diff --git a/Misc/NEWS.d/next/C API/2020-11-03-19-47-06.bpo-41832.dL1VJJ.rst b/Misc/NEWS.d/next/C API/2020-11-03-19-47-06.bpo-41832.dL1VJJ.rst new file mode 100644 index 00000000000..e0bce54eb93 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-11-03-19-47-06.bpo-41832.dL1VJJ.rst @@ -0,0 +1,2 @@ +The :c:func:`PyType_FromModuleAndSpec` function now accepts NULL ``tp_doc`` +slot. diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 78d464d1481..c32699cb8ad 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -489,15 +489,15 @@ static PyStructSequence_Field profiler_subentry_fields[] = { static PyStructSequence_Desc profiler_entry_desc = { .name = "_lsprof.profiler_entry", - .doc = "", .fields = profiler_entry_fields, + .doc = NULL, .n_in_sequence = 6 }; static PyStructSequence_Desc profiler_subentry_desc = { .name = "_lsprof.profiler_subentry", - .doc = "", .fields = profiler_subentry_fields, + .doc = NULL, .n_in_sequence = 5 }; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 28d2c124d51..22d20d220d4 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -6508,6 +6508,23 @@ static PyType_Spec HeapDocCType_spec = { HeapDocCType_slots }; +typedef struct { + PyObject_HEAD +} NullTpDocTypeObject; + +static PyType_Slot NullTpDocType_slots[] = { + {Py_tp_doc, NULL}, + {0, 0}, +}; + +static PyType_Spec NullTpDocType_spec = { + "_testcapi.NullTpDocType", + sizeof(NullTpDocTypeObject), + 0, + Py_TPFLAGS_DEFAULT, + NullTpDocType_slots +}; + PyDoc_STRVAR(heapgctype__doc__, "A heap type with GC, and with overridden dealloc.\n\n" @@ -7183,6 +7200,14 @@ PyInit__testcapi(void) } PyModule_AddObject(m, "HeapDocCType", HeapDocCType); + /* bpo-41832: Add a new type to test PyType_FromSpec() + now can accept a NULL tp_doc slot. */ + PyObject *NullTpDocType = PyType_FromSpec(&NullTpDocType_spec); + if (NullTpDocType == NULL) { + return NULL; + } + PyModule_AddObject(m, "NullTpDocType", NullTpDocType); + PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec); if (HeapGcCType == NULL) { return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2daf374f170..3822b8cf813 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3012,6 +3012,10 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) else if (slot->slot == Py_tp_doc) { /* For the docstring slot, which usually points to a static string literal, we need to make a copy */ + if (slot->pfunc == NULL) { + type->tp_doc = NULL; + continue; + } size_t len = strlen(slot->pfunc)+1; char *tp_doc = PyObject_MALLOC(len); if (tp_doc == NULL) {