summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2020-09-02 16:29:06 (GMT)
committerGitHub <noreply@github.com>2020-09-02 16:29:06 (GMT)
commit3940333637b98a2781869977b077552514784529 (patch)
tree3b2c264f2acccc540076922a08d7e45e477ad4b1
parent5a4a963a6c798fa9207a9998618a9c0ec3b6b6d7 (diff)
downloadcpython-3940333637b98a2781869977b077552514784529.zip
cpython-3940333637b98a2781869977b077552514784529.tar.gz
cpython-3940333637b98a2781869977b077552514784529.tar.bz2
closes bpo-41689: Preserve text signature from tp_doc in C heap type creation. (GH-22058)
-rw-r--r--Lib/test/test_capi.py4
-rw-r--r--Misc/NEWS.d/next/C API/2020-09-01-23-39-45.bpo-41689.zxHbLB.rst2
-rw-r--r--Modules/_testcapimodule.c30
-rw-r--r--Objects/typeobject.c15
4 files changed, 48 insertions, 3 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 892cc74..db62b47 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -401,6 +401,10 @@ class CAPITest(unittest.TestCase):
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 0000000..44cf58a
--- /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 593034e..7536d29 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 c66f8fc..7404075 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)