gh-128863: Deprecate private C API functions (#128864)
https://github.com/python/cpython/commit/9012fa741d55419dc77c5c191794eb93e71... commit: 9012fa741d55419dc77c5c191794eb93e71ae9a4 branch: main author: Victor Stinner <vstinner@python.org> committer: vstinner <vstinner@python.org> date: 2025-01-22T11:04:19Z summary: gh-128863: Deprecate private C API functions (#128864) Deprecate private C API functions: * _PyBytes_Join() * _PyDict_GetItemStringWithError() * _PyDict_Pop() * _PyThreadState_UncheckedGet() * _PyUnicode_AsString() * _Py_HashPointer() * _Py_fopen_obj() Replace _Py_HashPointer() with Py_HashPointer(). Remove references to deprecated functions. files: A Doc/deprecations/c-api-pending-removal-in-3.18.rst A Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst M Doc/whatsnew/3.14.rst M Include/cpython/bytesobject.h M Include/cpython/dictobject.h M Include/cpython/fileutils.h M Include/cpython/pyhash.h M Include/cpython/pystate.h M Include/cpython/unicodeobject.h M Lib/test/audit-tests.py M Objects/descrobject.c M Objects/dictobject.c M Objects/methodobject.c M Objects/odictobject.c M Python/context.c M Python/fileutils.c diff --git a/Doc/deprecations/c-api-pending-removal-in-3.18.rst b/Doc/deprecations/c-api-pending-removal-in-3.18.rst new file mode 100644 index 00000000000000..d04c746cd9f33e --- /dev/null +++ b/Doc/deprecations/c-api-pending-removal-in-3.18.rst @@ -0,0 +1,16 @@ +Pending removal in Python 3.18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Deprecated private functions (:gh:`128863`): + + * :c:func:`!_PyBytes_Join`: use :c:func:`PyBytes_Join`. + * :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. + * :c:func:`!_PyDict_Pop()`: :c:func:`PyDict_Pop`. + * :c:func:`!_PyThreadState_UncheckedGet`: use :c:func:`PyThreadState_GetUnchecked`. + * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`. + * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`. + * :c:func:`!_Py_fopen_obj`: use :c:func:`Py_fopen`. + + 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. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 5652a63ce8d701..685a09dc70eec2 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1376,12 +1376,31 @@ Deprecated .. include:: ../deprecations/c-api-pending-removal-in-3.15.rst +.. include:: ../deprecations/c-api-pending-removal-in-3.18.rst + .. include:: ../deprecations/c-api-pending-removal-in-future.rst * The ``PyMonitoring_FireBranchEvent`` function is deprecated and should be replaced with calls to :c:func:`PyMonitoring_FireBranchLeftEvent` and :c:func:`PyMonitoring_FireBranchRightEvent`. +* The following private functions are deprecated and planned for removal in + Python 3.18: + + * :c:func:`!_PyBytes_Join`: use :c:func:`PyBytes_Join`. + * :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. + * :c:func:`!_PyDict_Pop()`: use :c:func:`PyDict_Pop`. + * :c:func:`!_PyThreadState_UncheckedGet`: use :c:func:`PyThreadState_GetUnchecked`. + * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`. + * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`. + * :c:func:`!_Py_fopen_obj`: use :c:func:`Py_fopen`. + + The `pythoncapi-compat project`_ can be used to get these new public + functions on Python 3.13 and older. + + (Contributed by Victor Stinner in :gh:`128863`.) + + Removed ------- diff --git a/Include/cpython/bytesobject.h b/Include/cpython/bytesobject.h index cf3f0387ecf323..71c133f173f157 100644 --- a/Include/cpython/bytesobject.h +++ b/Include/cpython/bytesobject.h @@ -34,5 +34,9 @@ static inline Py_ssize_t PyBytes_GET_SIZE(PyObject *op) { PyAPI_FUNC(PyObject*) PyBytes_Join(PyObject *sep, PyObject *iterable); -// Alias kept for backward compatibility -#define _PyBytes_Join PyBytes_Join +// Deprecated alias kept for backward compatibility +Py_DEPRECATED(3.14) static inline PyObject* +_PyBytes_Join(PyObject *sep, PyObject *iterable) +{ + return PyBytes_Join(sep, iterable); +} diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h index 78473e54898fa5..df9ec7050fca1a 100644 --- a/Include/cpython/dictobject.h +++ b/Include/cpython/dictobject.h @@ -68,7 +68,12 @@ PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused); PyAPI_FUNC(int) PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result); PyAPI_FUNC(int) PyDict_PopString(PyObject *dict, const char *key, PyObject **result); -PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value); + +// Use PyDict_Pop() instead +Py_DEPRECATED(3.14) PyAPI_FUNC(PyObject *) _PyDict_Pop( + PyObject *dict, + PyObject *key, + PyObject *default_value); /* Dictionary watchers */ diff --git a/Include/cpython/fileutils.h b/Include/cpython/fileutils.h index 702f89aca324c5..626b1ad57b3846 100644 --- a/Include/cpython/fileutils.h +++ b/Include/cpython/fileutils.h @@ -6,9 +6,11 @@ PyAPI_FUNC(FILE*) Py_fopen( PyObject *path, const char *mode); -// Deprecated alias to Py_fopen() kept for backward compatibility -Py_DEPRECATED(3.14) PyAPI_FUNC(FILE*) _Py_fopen_obj( - PyObject *path, - const char *mode); +// Deprecated alias kept for backward compatibility +Py_DEPRECATED(3.14) static inline FILE* +_Py_fopen_obj(PyObject *path, const char *mode) +{ + return Py_fopen(path, mode); +} PyAPI_FUNC(int) Py_fclose(FILE *file); diff --git a/Include/cpython/pyhash.h b/Include/cpython/pyhash.h index 876a7f0ea44f4d..a33ba10b8d3a37 100644 --- a/Include/cpython/pyhash.h +++ b/Include/cpython/pyhash.h @@ -29,9 +29,6 @@ /* Helpers for hash functions */ PyAPI_FUNC(Py_hash_t) _Py_HashDouble(PyObject *, double); -// Kept for backward compatibility -#define _Py_HashPointer Py_HashPointer - /* hash function definition */ typedef struct { @@ -44,6 +41,14 @@ typedef struct { PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void); PyAPI_FUNC(Py_hash_t) Py_HashPointer(const void *ptr); + +// Deprecated alias kept for backward compatibility +Py_DEPRECATED(3.14) static inline Py_hash_t +_Py_HashPointer(const void *ptr) +{ + return Py_HashPointer(ptr); +} + PyAPI_FUNC(Py_hash_t) PyObject_GenericHash(PyObject *); PyAPI_FUNC(Py_hash_t) Py_HashBuffer(const void *ptr, Py_ssize_t len); diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 32f68378ea5d72..cd6d9582496850 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -239,8 +239,12 @@ struct _ts { * if it is NULL. */ PyAPI_FUNC(PyThreadState *) PyThreadState_GetUnchecked(void); -// Alias kept for backward compatibility -#define _PyThreadState_UncheckedGet PyThreadState_GetUnchecked +// Deprecated alias kept for backward compatibility +Py_DEPRECATED(3.14) static inline PyThreadState* +_PyThreadState_UncheckedGet(void) +{ + return PyThreadState_GetUnchecked(); +} // Disable tracing and profiling. diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 46a01c8e591709..287de52b96202c 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -630,8 +630,12 @@ _PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer); PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); -// Alias kept for backward compatibility -#define _PyUnicode_AsString PyUnicode_AsUTF8 +// Deprecated alias kept for backward compatibility +Py_DEPRECATED(3.14) static inline const char* +_PyUnicode_AsString(PyObject *unicode) +{ + return PyUnicode_AsUTF8(unicode); +} /* === Characters Type APIs =============================================== */ diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 6df09d891433ea..6b9b21cf7f6a3c 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -187,7 +187,7 @@ class C(A): def test_open(testfn): - # SSLContext.load_dh_params uses _Py_fopen_obj rather than normal open() + # SSLContext.load_dh_params uses Py_fopen() rather than normal open() try: import ssl diff --git a/Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst b/Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst new file mode 100644 index 00000000000000..a94d7933ad32ef --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst @@ -0,0 +1,16 @@ +The following private functions are deprecated and planned for removal in +Python 3.18: + +* :c:func:`!_PyBytes_Join`: use :c:func:`PyBytes_Join`. +* :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. +* :c:func:`!_PyDict_Pop()`: use :c:func:`PyDict_Pop`. +* :c:func:`!_PyThreadState_UncheckedGet`: use :c:func:`PyThreadState_GetUnchecked`. +* :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`. +* :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`. +* :c:func:`!_Py_fopen_obj`: use :c:func:`Py_fopen`. + +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. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 1852118359f014..238becee241d1d 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1349,7 +1349,7 @@ wrapper_hash(PyObject *self) wrapperobject *wp = (wrapperobject *)self; Py_hash_t x, y; x = PyObject_GenericHash(wp->self); - y = _Py_HashPointer(wp->descr); + y = Py_HashPointer(wp->descr); x = x ^ y; if (x == -1) x = -2; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 504e65b01ca959..8fe71123252a75 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3090,8 +3090,8 @@ PyDict_PopString(PyObject *op, const char *key, PyObject **result) } -PyObject * -_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) +static PyObject * +dict_pop_default(PyObject *dict, PyObject *key, PyObject *default_value) { PyObject *result; if (PyDict_Pop(dict, key, &result) == 0) { @@ -3104,6 +3104,12 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) return result; } +PyObject * +_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) +{ + return dict_pop_default(dict, key, default_value); +} + static PyDictObject * dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp, PyObject *iterable, PyObject *value) @@ -4465,7 +4471,7 @@ static PyObject * dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value) /*[clinic end generated code: output=3abb47b89f24c21c input=e221baa01044c44c]*/ { - return _PyDict_Pop((PyObject*)self, key, default_value); + return dict_pop_default((PyObject*)self, key, default_value); } /*[clinic input] diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 345da4607423cf..ecec0f7205a11d 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -331,7 +331,7 @@ meth_hash(PyObject *self) { PyCFunctionObject *a = _PyCFunctionObject_CAST(self); Py_hash_t x = PyObject_GenericHash(a->m_self); - Py_hash_t y = _Py_HashPointer((void*)(a->m_ml->ml_meth)); + Py_hash_t y = Py_HashPointer((void*)(a->m_ml->ml_meth)); x ^= y; if (x == -1) { x = -2; diff --git a/Objects/odictobject.c b/Objects/odictobject.c index e151023dd764bf..f2d8da0c567878 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -260,7 +260,7 @@ mp_length __len__ - dict_length mp_subscript __getitem__ - dict_subscript mp_ass_subscript __setitem__ - dict_ass_sub __delitem__ -tp_hash __hash__ _Py_HashPointer ..._HashNotImpl +tp_hash __hash__ Py_HashPointer ..._HashNotImpl tp_str __str__ object_str - tp_getattro __getattribute__ ..._GenericGetAttr (repeated) __getattr__ diff --git a/Python/context.c b/Python/context.c index f30b59b9443bbf..bb1aa42b9c5e4f 100644 --- a/Python/context.c +++ b/Python/context.c @@ -860,7 +860,7 @@ contextvar_generate_hash(void *addr, PyObject *name) return -1; } - Py_hash_t res = _Py_HashPointer(addr) ^ name_hash; + Py_hash_t res = Py_HashPointer(addr) ^ name_hash; return res == -1 ? -2 : res; } diff --git a/Python/fileutils.c b/Python/fileutils.c index 72804c39220591..68d24bc6b93465 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1842,14 +1842,6 @@ Py_fopen(PyObject *path, const char *mode) } -// Deprecated alias to Py_fopen() kept for backward compatibility -FILE* -_Py_fopen_obj(PyObject *path, const char *mode) -{ - return Py_fopen(path, mode); -} - - // Call fclose(). // // On Windows, files opened by Py_fopen() in the Python DLL must be closed by
participants (1)
-
vstinner