From fb9e7b58fdfa921677e641d9f71aa17ff92bfe80 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 10 Oct 2026 01:28:39 +0200 Subject: [PATCH 1/2] Add PyUnicodeWriter_WriteUCS4() function --- docs/api.rst | 7 ++++++- docs/changelog.rst | 1 + pythoncapi_compat.h | 15 +++++++++++++++ tests/test_pythoncapi_compat_cext.c | 11 ++++++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 7a5ba70..b0ff7d2 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -193,6 +193,12 @@ Python 3.14 Not available on the limited C API. +.. c:function:: int PyUnicodeWriter_WriteUCS4(PyUnicodeWriter *writer, const Py_UCS4 *ucs4, Py_ssize_t size) + + See `PyUnicodeWriter_WriteUCS4() documentation `__. + + Not available on the limited C API. + .. c:function:: int PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer, const char *str, Py_ssize_t size) See `PyUnicodeWriter_WriteUTF8() documentation `__. @@ -338,7 +344,6 @@ Not supported: * ``PyInitConfig_SetStrList()`` * ``PyType_GetBaseByToken()`` * ``PyUnicodeWriter_DecodeUTF8Stateful()`` -* ``PyUnicodeWriter_WriteUCS4()`` * ``Py_InitializeFromInitConfig()`` diff --git a/docs/changelog.rst b/docs/changelog.rst index 2d9f1b7..db7fc9f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* 2026-10-10: Add ``PyUnicodeWriter_WriteUCS4()`` function. * 2026-10-08: Add support for the limited C API 3.2. * 2026-10-08: Add functions: diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index 735ab24..4d5bf84 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -1620,6 +1620,21 @@ PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str, start, end); } +static inline int +PyUnicodeWriter_WriteUCS4(PyUnicodeWriter *writer, + const Py_UCS4 *ucs4, Py_ssize_t size) +{ + PyObject *str = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, + ucs4, size); + if (str == NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); + Py_DECREF(str); + return res; +} + static inline int PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...) { diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index 55e4e17..9a97f7d 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -1899,6 +1899,7 @@ test_unicodewriter(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) return NULL; } int ret; + const Py_UCS4 ucs4[] = {'u', 'c', 's', '4'}; // test PyUnicodeWriter_WriteStr() PyObject *str = PyUnicode_FromString("var"); @@ -1940,6 +1941,14 @@ test_unicodewriter(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) goto error; } + // test PyUnicodeWriter_WriteUCS4() + if (PyUnicodeWriter_WriteUCS4(writer, ucs4, Py_ARRAY_LENGTH(ucs4)) < 0) { + goto error; + } + if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) { + goto error; + } + // test PyUnicodeWriter_WriteRepr() str = PyUnicode_FromString("repr"); if (str == NULL) { @@ -1958,7 +1967,7 @@ test_unicodewriter(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) if (result == NULL) { return NULL; } - const char *expected = "var=long non-ASCII valu\xC3\xA9 'repr'"; + const char *expected = "var=long non-ASCII valu\xC3\xA9 ucs4 'repr'"; assert(PyUnicode_EqualToUTF8(result, expected)); Py_DECREF(result); } From f6043ab5f4e09b6dd54274a9f643d67847edce0b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 10 Oct 2026 01:33:43 +0200 Subject: [PATCH 2/2] Update doc --- docs/api.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index b0ff7d2..13a9d1b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -2,12 +2,12 @@ pythoncapi_compat.h API +++++++++++++++++++++++ -The ``pythoncapi_compat.h`` header file provides implementations of recent -functions for old Python versions. +The ``pythoncapi_compat.h`` header file provides implementations of around 150 +recent functions for old Python versions. Supported Python versions: -* Python 3.6 - 3.15 +* Python 3.6 - 3.16 * PyPy 3.6 - 3.12 C++03 and C++11 are supported on Python 3.6 and newer.