diff options
author | Benjamin Peterson <benjamin@python.org> | 2020-09-02 16:29:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-02 16:29:06 (GMT) |
commit | 3940333637b98a2781869977b077552514784529 (patch) | |
tree | 3b2c264f2acccc540076922a08d7e45e477ad4b1 | |
parent | 5a4a963a6c798fa9207a9998618a9c0ec3b6b6d7 (diff) | |
download | cpython-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.py | 4 | ||||
-rw-r--r-- | Misc/NEWS.d/next/C API/2020-09-01-23-39-45.bpo-41689.zxHbLB.rst | 2 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 30 | ||||
-rw-r--r-- | Objects/typeobject.c | 15 |
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) |