https://github.com/python/cpython/commit/519c2c6740178831125359babbfe288cee4c25e0
commit: 519c2c6740178831125359babbfe288cee4c25e0
branch: main
author: Victor Stinner <vstin...@python.org>
committer: vstinner <vstin...@python.org>
date: 2025-02-20T14:02:02+01:00
summary:

gh-128863: Deprecate the private _PyUnicodeWriter API (#129245)

Deprecate private C API functions:

* _PyUnicodeWriter_Init()
* _PyUnicodeWriter_Finish()
* _PyUnicodeWriter_Dealloc()
* _PyUnicodeWriter_WriteChar()
* _PyUnicodeWriter_WriteStr()
* _PyUnicodeWriter_WriteSubstring()
* _PyUnicodeWriter_WriteASCIIString()
* _PyUnicodeWriter_WriteLatin1String()

These functions are not deprecated in the internal C API (if the
Py_BUILD_CORE macro is defined).

files:
A Misc/NEWS.d/next/C_API/2025-02-19-14-41-26.gh-issue-128863.TELwyV.rst
M Doc/deprecations/c-api-pending-removal-in-3.18.rst
M Doc/whatsnew/3.14.rst
M Include/cpython/unicodeobject.h

diff --git a/Doc/deprecations/c-api-pending-removal-in-3.18.rst 
b/Doc/deprecations/c-api-pending-removal-in-3.18.rst
index 0689d8b4f9e959..564cfb79a0b513 100644
--- a/Doc/deprecations/c-api-pending-removal-in-3.18.rst
+++ b/Doc/deprecations/c-api-pending-removal-in-3.18.rst
@@ -11,6 +11,32 @@ Pending removal in Python 3.18
     use :c:func:`PyLongWriter_Create`.
   * :c:func:`!_PyThreadState_UncheckedGet`: use 
:c:func:`PyThreadState_GetUnchecked`.
   * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`.
+  * :c:func:`!_PyUnicodeWriter_Init`:
+    replace ``_PyUnicodeWriter_Init(&writer)`` with
+    :c:func:`writer = PyUnicodeWriter_Create(0) <PyUnicodeWriter_Create>`.
+  * :c:func:`!_PyUnicodeWriter_Finish`:
+    replace ``_PyUnicodeWriter_Finish(&writer)`` with
+    :c:func:`PyUnicodeWriter_Finish(writer) <PyUnicodeWriter_Finish>`.
+  * :c:func:`!_PyUnicodeWriter_Dealloc`:
+    replace ``_PyUnicodeWriter_Dealloc(&writer)`` with
+    :c:func:`PyUnicodeWriter_Discard(writer) <PyUnicodeWriter_Discard>`.
+  * :c:func:`!_PyUnicodeWriter_WriteChar`:
+    replace ``_PyUnicodeWriter_WriteChar(&writer, ch)`` with
+    :c:func:`PyUnicodeWriter_WriteChar(writer, ch) 
<PyUnicodeWriter_WriteChar>`.
+  * :c:func:`!_PyUnicodeWriter_WriteStr`:
+    replace ``_PyUnicodeWriter_WriteStr(&writer, str)`` with
+    :c:func:`PyUnicodeWriter_WriteStr(writer, str) <PyUnicodeWriter_WriteStr>`.
+  * :c:func:`!_PyUnicodeWriter_WriteSubstring`:
+    replace ``_PyUnicodeWriter_WriteSubstring(&writer, str, start, end)`` with
+    :c:func:`PyUnicodeWriter_WriteSubstring(writer, str, start, end) 
<PyUnicodeWriter_WriteSubstring>`.
+  * :c:func:`!_PyUnicodeWriter_WriteASCIIString`:
+    replace ``_PyUnicodeWriter_WriteASCIIString(&writer, str)`` with
+    :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) 
<PyUnicodeWriter_WriteUTF8>`.
+  * :c:func:`!_PyUnicodeWriter_WriteLatin1String`:
+    replace ``_PyUnicodeWriter_WriteLatin1String(&writer, str)`` with
+    :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) 
<PyUnicodeWriter_WriteUTF8>`.
+  * :c:func:`!_PyUnicodeWriter_Prepare`: (no replacement).
+  * :c:func:`!_PyUnicodeWriter_PrepareKind`: (no replacement).
   * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`.
   * :c:func:`!_Py_fopen_obj`: use :c:func:`Py_fopen`.
 
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 05221a8edf4066..514c138c0ed061 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -1497,21 +1497,23 @@ Porting to Python 3.14
 
 * Private functions promoted to public C APIs:
 
-  * ``_PyBytes_Join()``: :c:func:`PyBytes_Join`;
-  * ``_PyLong_IsNegative()``: :c:func:`PyLong_IsNegative`;
-  * ``_PyLong_IsPositive()``: :c:func:`PyLong_IsPositive`;
-  * ``_PyLong_IsZero()``: :c:func:`PyLong_IsZero`;
-  * ``_PyLong_Sign()``: :c:func:`PyLong_GetSign`;
-  * ``_PyUnicodeWriter_Dealloc()``: :c:func:`PyUnicodeWriter_Discard`;
-  * ``_PyUnicodeWriter_Finish()``: :c:func:`PyUnicodeWriter_Finish`;
-  * ``_PyUnicodeWriter_Init()``: :c:func:`PyUnicodeWriter_Create`;
-  * ``_PyUnicodeWriter_WriteChar()``: :c:func:`PyUnicodeWriter_WriteChar`;
-  * ``_PyUnicodeWriter_WriteStr()``: :c:func:`PyUnicodeWriter_WriteStr`;
-  * ``_PyUnicodeWriter_WriteSubstring()``: 
:c:func:`PyUnicodeWriter_WriteSubstring`;
-  * ``_PyUnicode_EQ()``: :c:func:`PyUnicode_Equal`;
-  * ``_PyUnicode_Equal()``: :c:func:`PyUnicode_Equal`;
-  * ``_Py_GetConfig()``: :c:func:`PyConfig_Get` and :c:func:`PyConfig_GetInt`;
-  * ``_Py_HashBytes()``: :c:func:`Py_HashBuffer`;
+  * ``_PyBytes_Join()``: :c:func:`PyBytes_Join`.
+  * ``_PyLong_IsNegative()``: :c:func:`PyLong_IsNegative`.
+  * ``_PyLong_IsPositive()``: :c:func:`PyLong_IsPositive`.
+  * ``_PyLong_IsZero()``: :c:func:`PyLong_IsZero`.
+  * ``_PyLong_Sign()``: :c:func:`PyLong_GetSign`.
+  * ``_PyUnicodeWriter_Dealloc()``: :c:func:`PyUnicodeWriter_Discard`.
+  * ``_PyUnicodeWriter_Finish()``: :c:func:`PyUnicodeWriter_Finish`.
+  * ``_PyUnicodeWriter_Init()``: use :c:func:`PyUnicodeWriter_Create`.
+  * ``_PyUnicodeWriter_Prepare()``: (no replacement).
+  * ``_PyUnicodeWriter_PrepareKind()``: (no replacement).
+  * ``_PyUnicodeWriter_WriteChar()``: :c:func:`PyUnicodeWriter_WriteChar`.
+  * ``_PyUnicodeWriter_WriteStr()``: :c:func:`PyUnicodeWriter_WriteStr`.
+  * ``_PyUnicodeWriter_WriteSubstring()``: 
:c:func:`PyUnicodeWriter_WriteSubstring`.
+  * ``_PyUnicode_EQ()``: :c:func:`PyUnicode_Equal`.
+  * ``_PyUnicode_Equal()``: :c:func:`PyUnicode_Equal`.
+  * ``_Py_GetConfig()``: :c:func:`PyConfig_Get` and :c:func:`PyConfig_GetInt`.
+  * ``_Py_HashBytes()``: :c:func:`Py_HashBuffer`.
   * ``_Py_fopen_obj()``: :c:func:`Py_fopen`.
 
   The `pythoncapi-compat project`_ can be used to get most of these new
@@ -1556,6 +1558,30 @@ Deprecated
     use :c:func:`PyLongWriter_Create`.
   * :c:func:`!_PyThreadState_UncheckedGet`: use 
:c:func:`PyThreadState_GetUnchecked`.
   * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`.
+  * :c:func:`!_PyUnicodeWriter_Init`:
+    replace ``_PyUnicodeWriter_Init(&writer)`` with
+    :c:func:`writer = PyUnicodeWriter_Create(0) <PyUnicodeWriter_Create>`.
+  * :c:func:`!_PyUnicodeWriter_Finish`:
+    replace ``_PyUnicodeWriter_Finish(&writer)`` with
+    :c:func:`PyUnicodeWriter_Finish(writer) <PyUnicodeWriter_Finish>`.
+  * :c:func:`!_PyUnicodeWriter_Dealloc`:
+    replace ``_PyUnicodeWriter_Dealloc(&writer)`` with
+    :c:func:`PyUnicodeWriter_Discard(writer) <PyUnicodeWriter_Discard>`.
+  * :c:func:`!_PyUnicodeWriter_WriteChar`:
+    replace ``_PyUnicodeWriter_WriteChar(&writer, ch)`` with
+    :c:func:`PyUnicodeWriter_WriteChar(writer, ch) 
<PyUnicodeWriter_WriteChar>`.
+  * :c:func:`!_PyUnicodeWriter_WriteStr`:
+    replace ``_PyUnicodeWriter_WriteStr(&writer, str)`` with
+    :c:func:`PyUnicodeWriter_WriteStr(writer, str) <PyUnicodeWriter_WriteStr>`.
+  * :c:func:`!_PyUnicodeWriter_WriteSubstring`:
+    replace ``_PyUnicodeWriter_WriteSubstring(&writer, str, start, end)`` with
+    :c:func:`PyUnicodeWriter_WriteSubstring(writer, str, start, end) 
<PyUnicodeWriter_WriteSubstring>`.
+  * :c:func:`!_PyUnicodeWriter_WriteASCIIString`:
+    replace ``_PyUnicodeWriter_WriteASCIIString(&writer, str)`` with
+    :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) 
<PyUnicodeWriter_WriteUTF8>`.
+  * :c:func:`!_PyUnicodeWriter_WriteLatin1String`:
+    replace ``_PyUnicodeWriter_WriteLatin1String(&writer, str)`` with
+    :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) 
<PyUnicodeWriter_WriteUTF8>`.
   * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`.
   * :c:func:`!_Py_fopen_obj`: use :c:func:`Py_fopen`.
 
diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h
index cea69dd1280999..c7e5508f625cd3 100644
--- a/Include/cpython/unicodeobject.h
+++ b/Include/cpython/unicodeobject.h
@@ -530,8 +530,8 @@ typedef struct {
 // By default, the minimum buffer size is 0 character and overallocation is
 // disabled. Set min_length, min_char and overallocate attributes to control
 // the allocation of the buffer.
-PyAPI_FUNC(void)
-_PyUnicodeWriter_Init(_PyUnicodeWriter *writer);
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(void) _PyUnicodeWriter_Init(
+    _PyUnicodeWriter *writer);
 
 /* Prepare the buffer to write 'length' characters
    with the specified maximum character.
@@ -547,9 +547,10 @@ _PyUnicodeWriter_Init(_PyUnicodeWriter *writer);
 
 /* Don't call this function directly, use the _PyUnicodeWriter_Prepare() macro
    instead. */
-PyAPI_FUNC(int)
-_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer,
-                                 Py_ssize_t length, Py_UCS4 maxchar);
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(int) 
_PyUnicodeWriter_PrepareInternal(
+    _PyUnicodeWriter *writer,
+    Py_ssize_t length,
+    Py_UCS4 maxchar);
 
 /* Prepare the buffer to have at least the kind KIND.
    For example, kind=PyUnicode_2BYTE_KIND ensures that the writer will
@@ -563,58 +564,53 @@ _PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer,
 
 /* Don't call this function directly, use the _PyUnicodeWriter_PrepareKind()
    macro instead. */
-PyAPI_FUNC(int)
-_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer,
-                                     int kind);
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(int) 
_PyUnicodeWriter_PrepareKindInternal(
+    _PyUnicodeWriter *writer,
+    int kind);
 
 /* Append a Unicode character.
    Return 0 on success, raise an exception and return -1 on error. */
-PyAPI_FUNC(int)
-_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer,
-    Py_UCS4 ch
-    );
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(int) _PyUnicodeWriter_WriteChar(
+    _PyUnicodeWriter *writer,
+    Py_UCS4 ch);
 
 /* Append a Unicode string.
    Return 0 on success, raise an exception and return -1 on error. */
-PyAPI_FUNC(int)
-_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer,
-    PyObject *str               /* Unicode string */
-    );
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(int) _PyUnicodeWriter_WriteStr(
+    _PyUnicodeWriter *writer,
+    PyObject *str);               /* Unicode string */
 
 /* Append a substring of a Unicode string.
    Return 0 on success, raise an exception and return -1 on error. */
-PyAPI_FUNC(int)
-_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer,
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(int) 
_PyUnicodeWriter_WriteSubstring(
+    _PyUnicodeWriter *writer,
     PyObject *str,              /* Unicode string */
     Py_ssize_t start,
-    Py_ssize_t end
-    );
+    Py_ssize_t end);
 
 /* Append an ASCII-encoded byte string.
    Return 0 on success, raise an exception and return -1 on error. */
-PyAPI_FUNC(int)
-_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer,
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(int) 
_PyUnicodeWriter_WriteASCIIString(
+    _PyUnicodeWriter *writer,
     const char *str,           /* ASCII-encoded byte string */
-    Py_ssize_t len             /* number of bytes, or -1 if unknown */
-    );
+    Py_ssize_t len);           /* number of bytes, or -1 if unknown */
 
 /* Append a latin1-encoded byte string.
    Return 0 on success, raise an exception and return -1 on error. */
-PyAPI_FUNC(int)
-_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer,
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(int) 
_PyUnicodeWriter_WriteLatin1String(
+    _PyUnicodeWriter *writer,
     const char *str,           /* latin1-encoded byte string */
-    Py_ssize_t len             /* length in bytes */
-    );
+    Py_ssize_t len);           /* length in bytes */
 
 /* Get the value of the writer as a Unicode string. Clear the
    buffer of the writer. Raise an exception and return NULL
    on error. */
-PyAPI_FUNC(PyObject *)
-_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer);
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(PyObject *) _PyUnicodeWriter_Finish(
+    _PyUnicodeWriter *writer);
 
 /* Deallocate memory of a writer (clear its internal buffer). */
-PyAPI_FUNC(void)
-_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer);
+_Py_DEPRECATED_EXTERNALLY(3.14) PyAPI_FUNC(void) _PyUnicodeWriter_Dealloc(
+    _PyUnicodeWriter *writer);
 
 
 /* --- Manage the default encoding ---------------------------------------- */
diff --git 
a/Misc/NEWS.d/next/C_API/2025-02-19-14-41-26.gh-issue-128863.TELwyV.rst 
b/Misc/NEWS.d/next/C_API/2025-02-19-14-41-26.gh-issue-128863.TELwyV.rst
new file mode 100644
index 00000000000000..17d454803eca24
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2025-02-19-14-41-26.gh-issue-128863.TELwyV.rst
@@ -0,0 +1,35 @@
+The following private functions are deprecated and planned for removal in
+Python 3.18:
+
+* :c:func:`!_PyUnicodeWriter_Init`:
+  replace ``_PyUnicodeWriter_Init(&writer)`` with
+  :c:func:`writer = PyUnicodeWriter_Create(0) <PyUnicodeWriter_Create>`.
+* :c:func:`!_PyUnicodeWriter_Finish`:
+  replace ``_PyUnicodeWriter_Finish(&writer)`` with
+  :c:func:`PyUnicodeWriter_Finish(writer) <PyUnicodeWriter_Finish>`.
+* :c:func:`!_PyUnicodeWriter_Dealloc`:
+  replace ``_PyUnicodeWriter_Dealloc(&writer)`` with
+  :c:func:`PyUnicodeWriter_Discard(writer) <PyUnicodeWriter_Discard>`.
+* :c:func:`!_PyUnicodeWriter_WriteChar`:
+  replace ``_PyUnicodeWriter_WriteChar(&writer, ch)`` with
+  :c:func:`PyUnicodeWriter_WriteChar(writer, ch) <PyUnicodeWriter_WriteChar>`.
+* :c:func:`!_PyUnicodeWriter_WriteStr`:
+  replace ``_PyUnicodeWriter_WriteStr(&writer, str)`` with
+  :c:func:`PyUnicodeWriter_WriteStr(writer, str) <PyUnicodeWriter_WriteStr>`.
+* :c:func:`!_PyUnicodeWriter_WriteSubstring`:
+  replace ``_PyUnicodeWriter_WriteSubstring(&writer, str, start, end)`` with
+  :c:func:`PyUnicodeWriter_WriteSubstring(writer, str, start, end) 
<PyUnicodeWriter_WriteSubstring>`.
+* :c:func:`!_PyUnicodeWriter_WriteASCIIString`:
+  replace ``_PyUnicodeWriter_WriteASCIIString(&writer, str)`` with
+  :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) <PyUnicodeWriter_WriteUTF8>`.
+* :c:func:`!_PyUnicodeWriter_WriteLatin1String`:
+  replace ``_PyUnicodeWriter_WriteLatin1String(&writer, str)`` with
+  :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) <PyUnicodeWriter_WriteUTF8>`.
+* :c:func:`!_PyUnicodeWriter_Prepare`: (no replacement).
+* :c:func:`!_PyUnicodeWriter_PrepareKind`: (no replacement).
+
+The `pythoncapi-compat project
+<https://github.com/python/pythoncapi-compat/>`__ can be used to get these
+new public functions on Python 3.13 and older.
+
+Patch by Victor Stinner.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to