Repository navigation
Stable ABI contains outdated symbols #82
Description
Copying from @victor's comment from #4 (comment)
It would be nice to consider designing an abi4 to cleanup the dust: remove functions which are already removed in the API level. The abi3 has 61 symbols which are "ABI only": has been removed from the limited C API.
Well, there are also private symbols which are used by limited C API macros/functions which still exist. For example, the ABI-only variable _Py_NoneStruct is used to implement Py_None at the API level: #define Py_None (&_Py_NoneStruct).
These removals are related to different Python changes. Examples:
- Only use Py_ssize_t in the PyArg_ParseTuple() API: PY_SSIZE_T_CLEAN macro.
_PyArg_ParseTuple_SizeT()was removed, sincePyArg_ParseTuple()now usesPy_ssize_t. - Removal of the legacy API to configuration the Python initialization: see issue [C API] PEP 741: Add PyInitConfig C API to customize the Python initialization python/cpython#107954, the limited C API has no replacement yet :-(
- Removal of the legacy Python 3.2 API for Unicode strings: PEP 623 and [PEP 624](https://peps.python.org/pep-0624/]
- API using
FILE*were removed, likePyMarshal_ReadObjectFromString(): PEP 384 excludedFILE*from the limited C API. PyEval_AcquireLock()andPyEval_ReleaseLock()functions were broken and have been replaced with existingPyEval_SaveThread()andPyEval_RestoreThread()functions: removed in Python 3.13.
I see that _Py_RefTotal is an ABI-only symbol added to support the Python debug build (Py_DEBUG), but I'm not sure that it was needed to expose it. Before 3.9, Python debug build didn't support the limited C API. In Python 3.10, Py_INCREF() and Py_DECREF() got support for the limited API but are implemented as opaque function calls in this case. Maybe the problem is about supporting the limited C API version 3.9 and older on a debug build. I forgot the complicated details.
ABI-only symbols (functions and variables) of the Python 3.13 stable ABI:
- PyCFunction_Call()
- PyEval_AcquireLock()
- PyEval_CallFunction()
- PyEval_CallMethod()
- PyEval_CallObjectWithKeywords()
- PyEval_InitThreads()
- PyEval_ReleaseLock()
- PyEval_ThreadsInitialized()
- PyMarshal_ReadObjectFromString()
- PyMarshal_WriteObjectToString()
- PyObject_AsCharBuffer()
- PyObject_AsReadBuffer()
- PyObject_AsWriteBuffer()
- PyObject_CheckReadBuffer()
- PySys_AddWarnOption()
- PySys_AddWarnOptionUnicode()
- PySys_AddXOption()
- PySys_HasWarnOptions()
- PySys_SetArgv()
- PySys_SetArgvEx()
- PySys_SetPath()
- PyThreadState_DeleteCurrent()
- PyUnicode_GetSize()
- PyUnicode_InternImmortal()
- Py_GetArgcArgv()
- Py_SetPath()
- Py_SetProgramName()
- Py_SetPythonHome()
- _PyArg_ParseTupleAndKeywords_SizeT()
- _PyArg_ParseTuple_SizeT()
- _PyArg_Parse_SizeT()
- _PyArg_VaParseTupleAndKeywords_SizeT()
- _PyArg_VaParse_SizeT()
- _PyErr_BadInternalCall()
- _PyObject_CallFunction_SizeT()
- _PyObject_CallMethod_SizeT()
- _PyObject_GC_New()
- _PyObject_GC_NewVar()
- _PyObject_GC_Resize()
- _PyObject_New()
- _PyObject_NewVar()
- _PyState_AddModule()
- _PyThreadState_Init()
- _PyThreadState_Prealloc()
- _PyWeakref_CallableProxyType
- _PyWeakref_ProxyType
- _PyWeakref_RefType
- _Py_BuildValue_SizeT()
- _Py_CheckRecursiveCall()
- _Py_Dealloc()
- _Py_DecRef()
- _Py_EllipsisObject
- _Py_FalseStruct
- _Py_IncRef()
- _Py_NegativeRefcount()
- _Py_NoneStruct
- _Py_NotImplementedStruct
- _Py_RefTotal
- _Py_SwappedOp
- _Py_TrueStruct
- _Py_VaBuildValue_SizeT()
Activity
encukou commentedon Jun 4, 2026
I consider this a non-problem. PEP 387 says:
By the time we can safely remove these symbols, they generally will have a small maintenance overhead -- they'll do nothing, always raise, or transparently forward to a newer function.