diff --git a/docs/api.rst b/docs/api.rst index ac4f654..de80e3d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -29,6 +29,21 @@ Latest version of the header file: Python 3.15 ----------- +.. c:function:: PyBytesWriter* PyBytesWriter_Create(Py_ssize_t size) +.. c:function:: void* PyBytesWriter_GetData(PyBytesWriter *writer) +.. c:function:: Py_ssize_t PyBytesWriter_GetSize(PyBytesWriter *writer) +.. c:function:: PyObject* PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size) +.. c:function:: PyObject* PyBytesWriter_Finish(PyBytesWriter *writer) +.. c:function:: PyObject* PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf) +.. c:function:: void PyBytesWriter_Discard(PyBytesWriter *writer) +.. c:function:: int PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size) +.. c:function:: int PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t size) +.. c:function:: void* PyBytesWriter_GrowAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, void *buf) +.. c:function:: int PyBytesWriter_WriteBytes(PyBytesWriter *writer, const void *bytes, Py_ssize_t size) +.. c:function:: int PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) + + See `PyBytesWriter documentation `__. + .. c:function:: PyObject* PySys_GetAttr(const char *name) See `PySys_GetAttr() documentation `__. @@ -45,20 +60,9 @@ Python 3.15 See `PySys_GetOptionalAttrString() documentation `__. -.. c:function:: PyBytesWriter* PyBytesWriter_Create(Py_ssize_t size) -.. c:function:: void* PyBytesWriter_GetData(PyBytesWriter *writer) -.. c:function:: Py_ssize_t PyBytesWriter_GetSize(PyBytesWriter *writer) -.. c:function:: PyObject* PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size) -.. c:function:: PyObject* PyBytesWriter_Finish(PyBytesWriter *writer) -.. c:function:: PyObject* PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf) -.. c:function:: void PyBytesWriter_Discard(PyBytesWriter *writer) -.. c:function:: int PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size) -.. c:function:: int PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t size) -.. c:function:: void* PyBytesWriter_GrowAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, void *buf) -.. c:function:: int PyBytesWriter_WriteBytes(PyBytesWriter *writer, const void *bytes, Py_ssize_t size) -.. c:function:: int PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) +.. c:function:: PyObject* PyTuple_FromArray(PyObject *const *array, Py_ssize_t size) - See `PyBytesWriter documentation `__. + See `PyTuple_FromArray() documentation `__. Python 3.14 diff --git a/docs/changelog.rst b/docs/changelog.rst index 60a818c..2d84389 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,7 +1,8 @@ Changelog ========= -* 2025-11-18: Add PEP 782 functions: +* 2025-10-14: Add ``PyTuple_FromArray()`` function. +* 2025-09-18: Add PEP 782 functions: * ``PyBytesWriter_Create()`` * ``PyBytesWriter_Discard()`` diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index 6a7037e..55b2dbd 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -2553,6 +2553,23 @@ PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) #endif // PY_VERSION_HEX < 0x030F00A1 +#if PY_VERSION_HEX < 0x030F00A1 +static inline PyObject* +PyTuple_FromArray(PyObject *const *array, Py_ssize_t size) +{ + PyObject *tuple = PyTuple_New(size); + if (tuple == NULL) { + return NULL; + } + for (Py_ssize_t i=0; i < size; i++) { + PyObject *item = array[i]; + PyTuple_SET_ITEM(tuple, i, Py_NewRef(item)); + } + return tuple; +} +#endif + + #ifdef __cplusplus } #endif diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index aa53ae0..25c7499 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -2392,6 +2392,54 @@ test_byteswriter(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) } +static PyObject* +test_tuple_fromarray(void) +{ + PyObject* array[] = { + PyLong_FromLong(1), + PyLong_FromLong(2), + PyLong_FromLong(3) + }; + PyObject *tuple = PyTuple_FromArray(array, 3); + if (tuple == NULL) { + goto error; + } + + assert(PyTuple_GET_SIZE(tuple) == 3); + assert(PyTuple_GET_ITEM(tuple, 0) == array[0]); + assert(PyTuple_GET_ITEM(tuple, 1) == array[1]); + assert(PyTuple_GET_ITEM(tuple, 2) == array[2]); + + Py_DECREF(tuple); + Py_DECREF(array[0]); + Py_DECREF(array[1]); + Py_DECREF(array[2]); + + // Test PyTuple_FromArray(NULL, 0) + tuple = PyTuple_FromArray(NULL, 0); + if (tuple == NULL) { + return NULL; + } + assert(PyTuple_GET_SIZE(tuple) == 0); + Py_DECREF(tuple); + + Py_RETURN_NONE; + +error: + Py_DECREF(array[0]); + Py_DECREF(array[1]); + Py_DECREF(array[2]); + return NULL; +} + + +static PyObject* +test_tuple(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + return test_tuple_fromarray(); +} + + static struct PyMethodDef methods[] = { {"test_object", test_object, METH_NOARGS, _Py_NULL}, {"test_py_is", test_py_is, METH_NOARGS, _Py_NULL}, @@ -2446,6 +2494,7 @@ static struct PyMethodDef methods[] = { {"test_sys", test_sys, METH_NOARGS, _Py_NULL}, {"test_uniquely_referenced", test_uniquely_referenced, METH_NOARGS, _Py_NULL}, {"test_byteswriter", test_byteswriter, METH_NOARGS, _Py_NULL}, + {"test_tuple", test_tuple, METH_NOARGS, _Py_NULL}, {_Py_NULL, _Py_NULL, 0, _Py_NULL} };