[Python-checkins] closes bpo-41689: Preserve text signature from tp_doc in C heap type creation. (GH-22058)

Benjamin Peterson webhook-mailer at python.org
Wed Sep 2 12:29:15 EDT 2020


https://github.com/python/cpython/commit/3940333637b98a2781869977b077552514784529
commit: 3940333637b98a2781869977b077552514784529
branch: master
author: Benjamin Peterson <benjamin at python.org>
committer: GitHub <noreply at github.com>
date: 2020-09-02T11:29:06-05:00
summary:

closes bpo-41689: Preserve text signature from tp_doc in C heap type creation. (GH-22058)

files:
A Misc/NEWS.d/next/C API/2020-09-01-23-39-45.bpo-41689.zxHbLB.rst
M Lib/test/test_capi.py
M Modules/_testcapimodule.c
M Objects/typeobject.c

diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 892cc74ec3915..db62b47100ad3 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -401,6 +401,10 @@ def __del__(self):
             del L
             self.assertEqual(PyList.num, 0)
 
+    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_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-09-01-23-39-45.bpo-41689.zxHbLB.rst b/Misc/NEWS.d/next/C API/2020-09-01-23-39-45.bpo-41689.zxHbLB.rst
new file mode 100644
index 0000000000000..44cf58a4b0638
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-09-01-23-39-45.bpo-41689.zxHbLB.rst	
@@ -0,0 +1,2 @@
+Types created with :c:func:`PyType_FromSpec` now make any signature in their
+``tp_doc`` slot accessible from ``__text_signature__``.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 593034ef65e2c..7536d29535038 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -6462,6 +6462,30 @@ static PyTypeObject MethodDescriptor2_Type = {
     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
 };
 
+PyDoc_STRVAR(heapdocctype__doc__,
+"HeapDocCType(arg1, arg2)\n"
+"--\n"
+"\n"
+"somedoc");
+
+typedef struct {
+    PyObject_HEAD
+} HeapDocCTypeObject;
+
+static PyType_Slot HeapDocCType_slots[] = {
+    {Py_tp_doc, (char*)heapdocctype__doc__},
+    {0},
+};
+
+static PyType_Spec HeapDocCType_spec = {
+    "_testcapi.HeapDocCType",
+    sizeof(HeapDocCTypeObject),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    HeapDocCType_slots
+};
+
+
 PyDoc_STRVAR(heapgctype__doc__,
 "A heap type with GC, and with overridden dealloc.\n\n"
 "The 'value' attribute is set to 10 in __init__.");
@@ -7130,6 +7154,12 @@ PyInit__testcapi(void)
     Py_INCREF(TestError);
     PyModule_AddObject(m, "error", TestError);
 
+    PyObject *HeapDocCType = PyType_FromSpec(&HeapDocCType_spec);
+    if (HeapDocCType == NULL) {
+        return NULL;
+    }
+    PyModule_AddObject(m, "HeapDocCType", HeapDocCType);
+
     PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec);
     if (HeapGcCType == NULL) {
         return NULL;
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c66f8fcec8ed5..74040757a0702 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3018,15 +3018,14 @@ 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 */
-            const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot->pfunc);
-            size_t len = strlen(old_doc)+1;
+            size_t len = strlen(slot->pfunc)+1;
             char *tp_doc = PyObject_MALLOC(len);
             if (tp_doc == NULL) {
                 type->tp_doc = NULL;
                 PyErr_NoMemory();
                 goto fail;
             }
-            memcpy(tp_doc, old_doc, len);
+            memcpy(tp_doc, slot->pfunc, len);
             type->tp_doc = tp_doc;
         }
         else if (slot->slot == Py_tp_members) {
@@ -3058,6 +3057,16 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
         res->ht_cached_keys = _PyDict_NewKeysForClass();
     }
 
+    if (type->tp_doc) {
+        PyObject *__doc__ = PyUnicode_FromString(_PyType_DocWithoutSignature(type->tp_name, type->tp_doc));
+        if (!__doc__)
+            goto fail;
+        int ret = _PyDict_SetItemId(type->tp_dict, &PyId___doc__, __doc__);
+        Py_DECREF(__doc__);
+        if (ret < 0)
+            goto fail;
+    }
+
     if (weaklistoffset) {
         type->tp_weaklistoffset = weaklistoffset;
         if (PyDict_DelItemString((PyObject *)type->tp_dict, "__weaklistoffset__") < 0)



More information about the Python-checkins mailing list