diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 6919e61022788f..9e96da75e87b07 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -119,6 +119,17 @@ 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`. + 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 + + .. 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 46ee321b660c3a..39ee3215ccec3d 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 74fc7536ea231c..1fa8c57138feee 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -503,6 +503,10 @@ New Features suspend and resume tracing and profiling. (Contributed by Victor Stinner in :issue:`43760`.) +* 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 e89265a67c322e..ccafe8d87f8f51 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..9fa85d2bb7d24e --- /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 on the heap. diff --git a/Misc/stable_abi.txt b/Misc/stable_abi.txt index 23e5b96a0e8a78..c662c3ce16f109 100644 --- a/Misc/stable_abi.txt +++ b/Misc/stable_abi.txt @@ -2151,6 +2151,8 @@ function PyType_GetQualName added 3.11 data PyStructSequence_UnnamedField 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 5e4c5779626018..30f6b02abe02a1 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4029,6 +4029,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)) { @@ -5892,6 +5916,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..6b9146bfd7dc48 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,10 +567,11 @@ 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_FromModuleAndSpec(module, &spec, + (PyObject *)&PyTuple_Type); PyMem_Free(members); if (type == NULL) { return NULL; @@ -583,6 +586,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 d9e6fd3e7ca7cb..8d14cc493b7eae 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)