[Python-checkins] bpo-41832: PyType_FromModuleAndSpec() now accepts NULL tp_doc (GH-23123)

vstinner webhook-mailer at python.org
Fri Nov 6 11:05:00 EST 2020


https://github.com/python/cpython/commit/88c2cfd9ffbcfc43fd1364f2984852a819547d43
commit: 88c2cfd9ffbcfc43fd1364f2984852a819547d43
branch: master
author: Hai Shi <shihai1992 at gmail.com>
committer: vstinner <vstinner at python.org>
date: 2020-11-06T17:04:47+01:00
summary:

bpo-41832: PyType_FromModuleAndSpec() now accepts NULL tp_doc (GH-23123)

files:
A Misc/NEWS.d/next/C API/2020-11-03-19-47-06.bpo-41832.dL1VJJ.rst
M Doc/c-api/type.rst
M Doc/whatsnew/3.10.rst
M Lib/test/test_capi.py
M Modules/_lsprof.c
M Modules/_testcapimodule.c
M Objects/typeobject.c

diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 73f26875d8194..fcd92e38e2428 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 0ed7084ccd2ff..1e6c7c4067f3f 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 db62b47100ad3..a4ebe4a0a1b5c 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -405,6 +405,9 @@ def test_heap_ctype_doc_and_text_signature(self):
         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 0000000000000..e0bce54eb9364
--- /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 78d464d1481d7..c32699cb8ad58 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 28d2c124d5177..22d20d220d408 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 2daf374f170b0..3822b8cf813cf 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) {



More information about the Python-checkins mailing list