Skip to content

Commit 3940333

Browse files
authored
closes bpo-41689: Preserve text signature from tp_doc in C heap type creation. (GH-22058)
1 parent 5a4a963 commit 3940333

File tree

4 files changed

+48
-3
lines changed

4 files changed

+48
-3
lines changed

Lib/test/test_capi.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,10 @@ def __del__(self):
401401
del L
402402
self.assertEqual(PyList.num, 0)
403403

404+
def test_heap_ctype_doc_and_text_signature(self):
405+
self.assertEqual(_testcapi.HeapDocCType.__doc__, "somedoc")
406+
self.assertEqual(_testcapi.HeapDocCType.__text_signature__, "(arg1, arg2)")
407+
404408
def test_subclass_of_heap_gc_ctype_with_tpdealloc_decrefs_once(self):
405409
class HeapGcCTypeSubclass(_testcapi.HeapGcCType):
406410
def __init__(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Types created with :c:func:`PyType_FromSpec` now make any signature in their
2+
``tp_doc`` slot accessible from ``__text_signature__``.

Modules/_testcapimodule.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6462,6 +6462,30 @@ static PyTypeObject MethodDescriptor2_Type = {
64626462
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
64636463
};
64646464

6465+
PyDoc_STRVAR(heapdocctype__doc__,
6466+
"HeapDocCType(arg1, arg2)\n"
6467+
"--\n"
6468+
"\n"
6469+
"somedoc");
6470+
6471+
typedef struct {
6472+
PyObject_HEAD
6473+
} HeapDocCTypeObject;
6474+
6475+
static PyType_Slot HeapDocCType_slots[] = {
6476+
{Py_tp_doc, (char*)heapdocctype__doc__},
6477+
{0},
6478+
};
6479+
6480+
static PyType_Spec HeapDocCType_spec = {
6481+
"_testcapi.HeapDocCType",
6482+
sizeof(HeapDocCTypeObject),
6483+
0,
6484+
Py_TPFLAGS_DEFAULT,
6485+
HeapDocCType_slots
6486+
};
6487+
6488+
64656489
PyDoc_STRVAR(heapgctype__doc__,
64666490
"A heap type with GC, and with overridden dealloc.\n\n"
64676491
"The 'value' attribute is set to 10 in __init__.");
@@ -7130,6 +7154,12 @@ PyInit__testcapi(void)
71307154
Py_INCREF(TestError);
71317155
PyModule_AddObject(m, "error", TestError);
71327156

7157+
PyObject *HeapDocCType = PyType_FromSpec(&HeapDocCType_spec);
7158+
if (HeapDocCType == NULL) {
7159+
return NULL;
7160+
}
7161+
PyModule_AddObject(m, "HeapDocCType", HeapDocCType);
7162+
71337163
PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec);
71347164
if (HeapGcCType == NULL) {
71357165
return NULL;

Objects/typeobject.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3018,15 +3018,14 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
30183018
else if (slot->slot == Py_tp_doc) {
30193019
/* For the docstring slot, which usually points to a static string
30203020
literal, we need to make a copy */
3021-
const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot->pfunc);
3022-
size_t len = strlen(old_doc)+1;
3021+
size_t len = strlen(slot->pfunc)+1;
30233022
char *tp_doc = PyObject_MALLOC(len);
30243023
if (tp_doc == NULL) {
30253024
type->tp_doc = NULL;
30263025
PyErr_NoMemory();
30273026
goto fail;
30283027
}
3029-
memcpy(tp_doc, old_doc, len);
3028+
memcpy(tp_doc, slot->pfunc, len);
30303029
type->tp_doc = tp_doc;
30313030
}
30323031
else if (slot->slot == Py_tp_members) {
@@ -3058,6 +3057,16 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
30583057
res->ht_cached_keys = _PyDict_NewKeysForClass();
30593058
}
30603059

3060+
if (type->tp_doc) {
3061+
PyObject *__doc__ = PyUnicode_FromString(_PyType_DocWithoutSignature(type->tp_name, type->tp_doc));
3062+
if (!__doc__)
3063+
goto fail;
3064+
int ret = _PyDict_SetItemId(type->tp_dict, &PyId___doc__, __doc__);
3065+
Py_DECREF(__doc__);
3066+
if (ret < 0)
3067+
goto fail;
3068+
}
3069+
30613070
if (weaklistoffset) {
30623071
type->tp_weaklistoffset = weaklistoffset;
30633072
if (PyDict_DelItemString((PyObject *)type->tp_dict, "__weaklistoffset__") < 0)

0 commit comments

Comments
 (0)