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
+ `__ 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 0dcecd4944f2f6..6f99cb2f38c5c8 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -1370,12 +1370,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
+`__ 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