From b5d770b0a2394faade22bb084d89b2c48c488e5f Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Sun, 26 Sep 2021 23:48:15 +0800 Subject: [PATCH 1/3] Add PyStructSequence_FromModuleAndDesc() to create a new struct sequence type. --- Doc/c-api/tuple.rst | 8 ++++++ Doc/data/refcounts.dat | 5 ++++ Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.11.rst | 4 +++ Include/structseq.h | 4 +++ .../2021-09-26-23-05-34.bpo-45113.oePRV8.rst | 2 ++ Misc/stable_abi.txt | 2 ++ Modules/_testcapimodule.c | 26 +++++++++++++++++++ Objects/structseq.c | 17 +++++++++--- PC/python3dll.c | 1 + 10 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 6919e61022788f..8385ed05ea4f5a 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -119,6 +119,14 @@ objects, i.e. a sequence whose items can also be accessed through attributes. To create a struct sequence, you first have to create a specific struct sequence type. +.. c:function:: PyTypeObject* PyStructSequence_FromModuleAndDesc(PyObject *module, PyStructSequence_Desc *desc, unsigned long tp_flags) + + Create and return a new struct sequence type from the *desc*. + This function is similar to :c:func:`PyStructSequence_NewType`. + + .. versionadded:: 3.11 + + .. c:function:: PyTypeObject* PyStructSequence_NewType(PyStructSequence_Desc *desc) Create a new struct sequence type from the data in *desc*, described below. Instances diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 1694cad6f43ba7..e0ead6cdbe5e23 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -2089,6 +2089,11 @@ PyState_FindModule:PyModuleDef*:def:: PyState_RemoveModule:int::: PyState_RemoveModule:PyModuleDef*:def:: +PyStructSequence_FromModuleAndDesc:PyTypeObject*::+1: +PyStructSequence_FromModuleAndDesc:PyObject*:module:+1: +PyStructSequence_FromModuleAndDesc:PyStructSequence_Desc*:desc:: +PyStructSequence_FromModuleAndDesc:unsigned long:tp_flags:: + PyStructSequence_GET_ITEM:PyObject*::0: PyStructSequence_GET_ITEM:PyObject*:p:0: PyStructSequence_GET_ITEM:Py_ssize_t:pos:: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index b41027dee87bc8..ced7ee5bd09f7c 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -565,6 +565,7 @@ function,PyState_FindModule,3.2, function,PyState_RemoveModule,3.3, type,PyStructSequence_Desc,3.2, type,PyStructSequence_Field,3.2, +function,PyStructSequence_FromModuleAndDesc,3.11, function,PyStructSequence_GetItem,3.2, function,PyStructSequence_New,3.2, function,PyStructSequence_NewType,3.2, diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 818208edbf2631..0c3327f6f281bd 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -455,6 +455,10 @@ New Features * Add a new :c:func:`PyType_GetQualName` function to get type's qualified name. (Contributed by Hai Shi in :issue:`42035`.) +* Add a new :c:func:`PyStructSequence_FromModuleAndDesc` function to create + a new struct sequence type from the desc. + (Contributed by Hai Shi in :issue:`45113`.) + Porting to Python 3.11 ---------------------- diff --git a/Include/structseq.h b/Include/structseq.h index 8f51c89163a4e1..fc3fcd77f2d414 100644 --- a/Include/structseq.h +++ b/Include/structseq.h @@ -42,6 +42,10 @@ typedef PyTupleObject PyStructSequence; PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030B0000 +PyAPI_FUNC(PyTypeObject *) PyStructSequence_FromModuleAndDesc( + PyObject *, PyStructSequence_Desc *, unsigned long); +#endif #ifdef __cplusplus } diff --git a/Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst b/Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst new file mode 100644 index 00000000000000..7288a123287f1a --- /dev/null +++ b/Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst @@ -0,0 +1,2 @@ +Add a new :c:func:`PyStructSequence_FromModuleAndDesc` function to create a new +struct sequence type in heap. diff --git a/Misc/stable_abi.txt b/Misc/stable_abi.txt index 72fa426cd79b9f..0dcf2dd9d4d3f8 100644 --- a/Misc/stable_abi.txt +++ b/Misc/stable_abi.txt @@ -2149,6 +2149,8 @@ function PyType_GetName added 3.11 function PyType_GetQualName added 3.11 +function PyStructSequence_FromModuleAndDesc + added 3.11 # (Detailed comments aren't really needed for further entries: from here on # we can use version control logs.) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 51323f03e23689..d0b0a1d7da100c 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3919,6 +3919,30 @@ test_structseq_newtype_null_descr_doc(PyObject *Py_UNUSED(self), Py_RETURN_NONE; } +static PyObject * +test_structseq_newtype_from_heap(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(args)) +{ + PyStructSequence_Desc descr; + PyStructSequence_Field descr_fields[2]; + + descr_fields[0] = (PyStructSequence_Field){"foo", "foo value"}; + descr_fields[1] = (PyStructSequence_Field){0, NULL}; + + descr.name = "_testcapi.test_descr"; + descr.fields = descr_fields; + descr.doc = "This is used to test for creating a new type from heap"; + descr.n_in_sequence = 1; + + PyTypeObject* structseq_type = + (PyTypeObject *)PyStructSequence_FromModuleAndDesc(NULL, &descr, 0); + assert(structseq_type != NULL); + assert(PyType_Check(structseq_type)); + Py_DECREF(structseq_type); + + Py_RETURN_NONE; +} + static PyObject * test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored)) { @@ -5691,6 +5715,8 @@ static PyMethodDef TestMethods[] = { test_structseq_newtype_doesnt_leak, METH_NOARGS}, {"test_structseq_newtype_null_descr_doc", test_structseq_newtype_null_descr_doc, METH_NOARGS}, + {"test_structseq_newtype_from_heap", + test_structseq_newtype_from_heap, METH_NOARGS}, {"test_incref_decref_API", test_incref_decref_API, METH_NOARGS}, {"test_long_and_overflow", test_long_and_overflow, METH_NOARGS}, {"test_long_as_double", test_long_as_double, METH_NOARGS}, diff --git a/Objects/structseq.c b/Objects/structseq.c index 73795b677b404f..5a7d1c6986b0e3 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -532,7 +532,9 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) } PyTypeObject * -PyStructSequence_NewType(PyStructSequence_Desc *desc) +PyStructSequence_FromModuleAndDesc(PyObject *module, + PyStructSequence_Desc *desc, + unsigned long tp_flags) { PyMemberDef *members; PyTypeObject *type; @@ -565,14 +567,17 @@ PyStructSequence_NewType(PyStructSequence_Desc *desc) spec.name = desc->name; spec.basicsize = sizeof(PyStructSequence) - sizeof(PyObject *); spec.itemsize = sizeof(PyObject *); - spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC; + spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags; spec.slots = slots; - type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, (PyObject *)&PyTuple_Type); + type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, + (PyObject *)&PyTuple_Type); PyMem_Free(members); if (type == NULL) { return NULL; } + Py_XINCREF(module); + ((PyHeapTypeObject *)type)->ht_module = module; if (initialize_structseq_dict( desc, type->tp_dict, n_members, n_unnamed_members) < 0) { @@ -583,6 +588,12 @@ PyStructSequence_NewType(PyStructSequence_Desc *desc) return type; } +PyTypeObject * +PyStructSequence_NewType(PyStructSequence_Desc *desc) +{ + return PyStructSequence_FromModuleAndDesc(NULL, desc, 0); +} + int _PyStructSequence_Init(void) { if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL diff --git a/PC/python3dll.c b/PC/python3dll.c index 49b51e69d626e1..bc499a52d3373d 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -519,6 +519,7 @@ EXPORT_FUNC(PySlice_Unpack) EXPORT_FUNC(PyState_AddModule) EXPORT_FUNC(PyState_FindModule) EXPORT_FUNC(PyState_RemoveModule) +EXPORT_FUNC(PyStructSequence_FromModuleAndDesc) EXPORT_FUNC(PyStructSequence_GetItem) EXPORT_FUNC(PyStructSequence_New) EXPORT_FUNC(PyStructSequence_NewType) From 2c4cc7b149232d118781b1f752deeb9ba900ac46 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Thu, 7 Oct 2021 09:03:30 +0800 Subject: [PATCH 2/3] apply Erlend's comment --- Objects/structseq.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Objects/structseq.c b/Objects/structseq.c index 5a7d1c6986b0e3..6cbfe42a32bdc7 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -576,8 +576,7 @@ PyStructSequence_FromModuleAndDesc(PyObject *module, if (type == NULL) { return NULL; } - Py_XINCREF(module); - ((PyHeapTypeObject *)type)->ht_module = module; + ((PyHeapTypeObject *)type)->ht_module = Py_XNewRef(module); if (initialize_structseq_dict( desc, type->tp_dict, n_members, n_unnamed_members) < 0) { From 735ffb0a0410e5ee1f1e719af296e83b30290c68 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Fri, 22 Oct 2021 00:57:02 +0800 Subject: [PATCH 3/3] Add Petr and Christian's comments. --- Doc/c-api/tuple.rst | 3 +++ .../NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst | 2 +- Objects/structseq.c | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 8385ed05ea4f5a..9e96da75e87b07 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -123,6 +123,9 @@ type. Create and return a new struct sequence type from the *desc*. This function is similar to :c:func:`PyStructSequence_NewType`. + The *module* argument is associated with the new type and can be retrieved + with :c:func:`PyType_GetModule`. It must be a module object or ``NULL``. + The *tp_flags* argument is used to set :c:member:`PyTypeObject.tp_flags`. .. versionadded:: 3.11 diff --git a/Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst b/Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst index 7288a123287f1a..9fa85d2bb7d24e 100644 --- a/Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst +++ b/Misc/NEWS.d/next/C API/2021-09-26-23-05-34.bpo-45113.oePRV8.rst @@ -1,2 +1,2 @@ Add a new :c:func:`PyStructSequence_FromModuleAndDesc` function to create a new -struct sequence type in heap. +struct sequence type on the heap. diff --git a/Objects/structseq.c b/Objects/structseq.c index 6cbfe42a32bdc7..6b9146bfd7dc48 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -570,13 +570,12 @@ PyStructSequence_FromModuleAndDesc(PyObject *module, spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags; spec.slots = slots; - type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, + type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &spec, (PyObject *)&PyTuple_Type); PyMem_Free(members); if (type == NULL) { return NULL; } - ((PyHeapTypeObject *)type)->ht_module = Py_XNewRef(module); if (initialize_structseq_dict( desc, type->tp_dict, n_members, n_unnamed_members) < 0) {