From d7f5f06cb69e3cb008c693c93f712a1d3a889127 Mon Sep 17 00:00:00 2001 From: Klaus Zimmermann Date: Fri, 1 Aug 2025 19:03:56 +0200 Subject: [PATCH 1/7] Add sys.abi_info --- Doc/data/stable_abi.dat | 1 + Doc/library/sys.rst | 25 +++++ Include/Python.h | 1 + Include/internal/pycore_abiinfo.h | 13 +++ Include/pyabiinfo.h | 15 +++ Lib/test/_test_embed_structseq.py | 1 + Lib/test/test_stable_abi_ctypes.py | 1 + Makefile.pre.in | 1 + Misc/stable_abi.toml | 2 + PC/python3dll.c | 1 + PCbuild/_freeze_module.vcxproj | 1 + PCbuild/_freeze_module.vcxproj.filters | 3 + PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/abiinfo.c | 100 ++++++++++++++++++++ Python/pylifecycle.c | 7 ++ Python/sysmodule.c | 3 + Tools/c-analyzer/TODO | 1 + Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 + 19 files changed, 181 insertions(+) create mode 100644 Include/internal/pycore_abiinfo.h create mode 100644 Include/pyabiinfo.h create mode 100644 Python/abiinfo.c diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 0d0dfb3843260e..a92f6ecdf0c8e4 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -1,6 +1,7 @@ role,name,added,ifdef_note,struct_abi_kind macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,, func,PyAIter_Check,3.10,, +func,PyAbiInfo_GetInfo,3.15,, func,PyArg_Parse,3.2,, func,PyArg_ParseTuple,3.2,, func,PyArg_ParseTupleAndKeywords,3.2,, diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 771e0f2709a4aa..fed7ef7692341e 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -11,6 +11,31 @@ interpreter and to functions that interact strongly with the interpreter. It is always available. Unless explicitly noted otherwise, all variables are read-only. +.. data:: abi_info + + A :term:`named tuple` holding information about the ABI of the interpreter. + + .. attribute:: abi_info.pointer_bits + + The width of pointers in bits, as an integer. + + * ``32``: 32-bit build + * ``64``: 64-bit build + * ``None`` if this information is unknown or neither 32 nore 64 bits. + + .. attribute:: abi_info.Py_GIL_DISABLED + + A boolean indicating whether the interpreter was built in with the GIL + disabled, i.e. with the :option:`--disable-gil` option, aka free-threading. + + .. attribute:: abi_info.Py_DEBUG + + A boolean indicating whether the interpreter was built in debug mode, + i.e. with the :option:`--with-pydebug` option. + + .. versionadded:: next + + .. data:: abiflags On POSIX systems where Python was built with the standard ``configure`` diff --git a/Include/Python.h b/Include/Python.h index b6ee500aada791..83261cb154fc0d 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -138,5 +138,6 @@ #include "fileutils.h" #include "cpython/pyfpe.h" #include "cpython/tracemalloc.h" +#include "pyabiinfo.h" #endif /* !Py_PYTHON_H */ diff --git a/Include/internal/pycore_abiinfo.h b/Include/internal/pycore_abiinfo.h new file mode 100644 index 00000000000000..814af444c44f51 --- /dev/null +++ b/Include/internal/pycore_abiinfo.h @@ -0,0 +1,13 @@ +#ifndef Py_INTERNAL_ABIINFO_H +#define Py_INTERNAL_ABIINFO_H +#ifdef __cplusplus +extern "C" { +#endif + +extern PyStatus _PyAbiInfo_InitTypes(PyInterpreterState *); +extern void _PyAbiInfo_FiniTypes(PyInterpreterState *interp); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_ABIINFO_H */ diff --git a/Include/pyabiinfo.h b/Include/pyabiinfo.h new file mode 100644 index 00000000000000..97ea8f00ac80b8 --- /dev/null +++ b/Include/pyabiinfo.h @@ -0,0 +1,15 @@ +#ifndef Py_PYABIINFO_H +#define Py_PYABIINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030F0000 +PyAPI_FUNC(PyObject *) PyAbiInfo_GetInfo(void); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYABIINFO_H */ diff --git a/Lib/test/_test_embed_structseq.py b/Lib/test/_test_embed_structseq.py index 4cac84d7a469ac..90635319e1eef4 100644 --- a/Lib/test/_test_embed_structseq.py +++ b/Lib/test/_test_embed_structseq.py @@ -25,6 +25,7 @@ def check_structseq(self, obj_type): def test_sys_attrs(self): for attr_name in ( + 'abi_info', # AbiInfoType 'flags', # FlagsType 'float_info', # FloatInfoType 'hash_info', # Hash_InfoType diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 5a6ba9de337904..ac97970dee7b19 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -46,6 +46,7 @@ def test_windows_feature_macros(self): SYMBOL_NAMES = ( "PyAIter_Check", + "PyAbiInfo_GetInfo", "PyArg_Parse", "PyArg_ParseTuple", "PyArg_ParseTupleAndKeywords", diff --git a/Makefile.pre.in b/Makefile.pre.in index bcf19654adfb35..98e1bdab732ac4 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -423,6 +423,7 @@ PYTHON_OBJS= \ Python/_warnings.o \ Python/Python-ast.o \ Python/Python-tokenize.o \ + Python/abiinfo.o \ Python/asdl.o \ Python/assemble.o \ Python/ast.o \ diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 1f323cc03973e5..a9b3a1c72e27a5 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2583,3 +2583,5 @@ added = '3.15' [function.PySys_GetOptionalAttrString] added = '3.15' +[function.PyAbiInfo_GetInfo] + added = '3.15' diff --git a/PC/python3dll.c b/PC/python3dll.c index 8ec791f8280f13..303c7c5cb7686d 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -93,6 +93,7 @@ EXPORT_FUNC(Py_SetRecursionLimit) EXPORT_FUNC(Py_TYPE) EXPORT_FUNC(Py_VaBuildValue) EXPORT_FUNC(Py_XNewRef) +EXPORT_FUNC(PyAbiInfo_GetInfo) EXPORT_FUNC(PyAIter_Check) EXPORT_FUNC(PyArg_Parse) EXPORT_FUNC(PyArg_ParseTuple) diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 5ceddf759b8f3b..3b90666acb9b84 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -188,6 +188,7 @@ + diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 332d466b1f7409..3c7caf07c3a834 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -25,6 +25,9 @@ Source Files + + Python + Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 517103acea8d8e..3d169da7464ba9 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -582,6 +582,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index e9eedfd1312fae..19f47b92c3ec58 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1316,6 +1316,9 @@ Python + + Python + Python diff --git a/Python/abiinfo.c b/Python/abiinfo.c new file mode 100644 index 00000000000000..8b11079465914b --- /dev/null +++ b/Python/abiinfo.c @@ -0,0 +1,100 @@ +/* ABI information object implementation */ + +#include "Python.h" +#include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_structseq.h" // _PyStructSequence_InitBuiltin() + +static PyTypeObject AbiInfoType; + +PyDoc_STRVAR(abi_info__doc__, +"ABI information object.\n\ +This object provides information about the ABI \ +features available in the current Python interpreter.\n"); + +static PyStructSequence_Field abi_info_fields[] = { + {"pointer_bits", "Is this a 32-bit or 64-bit build?"}, + {"Py_GIL_DISABLED", "Is free-threading enabled?"}, + {"Py_DEBUG", "Is debug mode enabled?"}, + {0} +}; + +static PyStructSequence_Desc abi_info_desc = { + "sys.abi_info", + abi_info__doc__, + abi_info_fields, + 3 +}; + +PyObject * +_PyAbiInfo_GetPointerBits(void) +{ + PyObject *pointer_bits; + switch (SIZEOF_VOID_P) { + case 4: + pointer_bits = PyLong_FromLong(32); + break; + case 8: + pointer_bits = PyLong_FromLong(64); + break; + default: + pointer_bits = Py_NewRef(Py_None); + break; + } + if (pointer_bits == NULL) { + return NULL; + } + return pointer_bits; +} + +PyObject * +PyAbiInfo_GetInfo(void) +{ + PyObject *abi_info, *value; + int pos = 0; + abi_info = PyStructSequence_New(&AbiInfoType); + if (abi_info == NULL) { + goto error; + } + + value = _PyAbiInfo_GetPointerBits(); + if (value == NULL) { + goto error; + } + PyStructSequence_SetItem(abi_info, pos++, value); + +#ifdef Py_GIL_DISABLED + value = Py_True; +#else + value = Py_False; +#endif + PyStructSequence_SetItem(abi_info, pos++, value); + +#ifdef Py_DEBUG + value = Py_True; +#else + value = Py_False; +#endif + PyStructSequence_SetItem(abi_info, pos++, value); + + return abi_info; + +error: + Py_XDECREF(abi_info); + return NULL; +} + +PyStatus +_PyAbiInfo_InitTypes(PyInterpreterState *interp) +{ + if (_PyStructSequence_InitBuiltin(interp, &AbiInfoType, &abi_info_desc) < 0) { + return _PyStatus_ERR("Failed to initialize AbiInfoType"); + } + + return _PyStatus_OK(); +} + +void +_PyAbiInfo_FiniTypes(PyInterpreterState *interp) +{ + _PyStructSequence_FiniBuiltin(interp, &AbiInfoType); +} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index e22a9cc1c75050..4441ebcb66afe6 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1,6 +1,7 @@ /* Python interpreter top-level routines, including init/exit */ #include "Python.h" +#include "pycore_abiinfo.h" // _PyAbiInfo_InitTypes() #include "pycore_audit.h" // _PySys_ClearAuditHooks() #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_ceval.h" // _PyEval_FiniGIL() @@ -711,6 +712,11 @@ pycore_init_types(PyInterpreterState *interp) return status; } + status = _PyAbiInfo_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + status = _PyLong_InitTypes(interp); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1860,6 +1866,7 @@ static void finalize_interp_types(PyInterpreterState *interp) { _PyTypes_FiniExtTypes(interp); + _PyAbiInfo_FiniTypes(interp); _PyUnicode_FiniTypes(interp); _PySys_FiniTypes(interp); _PyXI_FiniTypes(interp); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index ae6cf306735939..c74be21cfd33b0 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3260,6 +3260,7 @@ PyDoc_STR( "\n\ Static objects:\n\ \n\ +abi_info -- a named tuple with information about the ABI.\n\ builtin_module_names -- tuple of module names built into this interpreter\n\ copyright -- copyright notice pertaining to this interpreter\n\ exec_prefix -- prefix used to find the machine-specific Python library\n\ @@ -3855,6 +3856,8 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("thread_info", PyThread_GetInfo()); + SET_SYS("abi_info", PyAbiInfo_GetInfo()); + /* initialize asyncgen_hooks */ if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) diff --git a/Tools/c-analyzer/TODO b/Tools/c-analyzer/TODO index 2077534ccf4128..81d3dc8dc2d1bc 100644 --- a/Tools/c-analyzer/TODO +++ b/Tools/c-analyzer/TODO @@ -841,6 +841,7 @@ Objects/unicodeobject.c:PyUnicode_Type PyTypeObject Py Objects/weakrefobject.c:_PyWeakref_CallableProxyType PyTypeObject _PyWeakref_CallableProxyType Objects/weakrefobject.c:_PyWeakref_ProxyType PyTypeObject _PyWeakref_ProxyType Objects/weakrefobject.c:_PyWeakref_RefType PyTypeObject _PyWeakref_RefType +Python/abiinfo.c:AbiInfoType static PyTypeObject AbiInfoType Python/bltinmodule.c:PyFilter_Type PyTypeObject PyFilter_Type Python/bltinmodule.c:PyMap_Type PyTypeObject PyMap_Type Python/bltinmodule.c:PyZip_Type PyTypeObject PyZip_Type diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 3c3cb2f9c86f16..f0d0bb201b459a 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -153,6 +153,7 @@ Objects/object.c - _PyLegacyEventHandler_Type - Objects/floatobject.c - FloatInfoType - Objects/longobject.c - Int_InfoType - +Python/abiinfo.c - AbiInfoType - Python/errors.c - UnraisableHookArgsType - Python/sysmodule.c - AsyncGenHooksType - Python/sysmodule.c - FlagsType - From 8890dc5e8adb48f9e7833a8827d8ad376bace78e Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:55:46 +0000 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst new file mode 100644 index 00000000000000..eaffb4022c6770 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst @@ -0,0 +1 @@ +Add ``sys.abi_info`` object to make ABI information more easily accessible. From a6f7d2ed117f716117e50df30f332830d0355312 Mon Sep 17 00:00:00 2001 From: Klaus Zimmermann Date: Thu, 7 Aug 2025 11:12:03 +0200 Subject: [PATCH 3/7] Simplify pointer_bits handling --- Doc/library/sys.rst | 5 +---- Python/abiinfo.c | 23 +---------------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index fed7ef7692341e..7ed5fcca443b36 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -18,10 +18,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only .. attribute:: abi_info.pointer_bits The width of pointers in bits, as an integer. - - * ``32``: 32-bit build - * ``64``: 64-bit build - * ``None`` if this information is unknown or neither 32 nore 64 bits. + Equivalent to ``8 * sizeof(void *)``, i.e. usually ``32`` or ``64``. .. attribute:: abi_info.Py_GIL_DISABLED diff --git a/Python/abiinfo.c b/Python/abiinfo.c index 8b11079465914b..a682f6e56aa218 100644 --- a/Python/abiinfo.c +++ b/Python/abiinfo.c @@ -25,27 +25,6 @@ static PyStructSequence_Desc abi_info_desc = { 3 }; -PyObject * -_PyAbiInfo_GetPointerBits(void) -{ - PyObject *pointer_bits; - switch (SIZEOF_VOID_P) { - case 4: - pointer_bits = PyLong_FromLong(32); - break; - case 8: - pointer_bits = PyLong_FromLong(64); - break; - default: - pointer_bits = Py_NewRef(Py_None); - break; - } - if (pointer_bits == NULL) { - return NULL; - } - return pointer_bits; -} - PyObject * PyAbiInfo_GetInfo(void) { @@ -56,7 +35,7 @@ PyAbiInfo_GetInfo(void) goto error; } - value = _PyAbiInfo_GetPointerBits(); + value = PyLong_FromLong(sizeof(void *) * 8); if (value == NULL) { goto error; } From b6c945c3c973bc27d26fb6851fcb9223bbfaf46c Mon Sep 17 00:00:00 2001 From: Klaus Zimmermann Date: Thu, 7 Aug 2025 11:29:25 +0200 Subject: [PATCH 4/7] Remove explicit C API function --- Doc/data/stable_abi.dat | 1 - Include/Python.h | 1 - Include/internal/pycore_abiinfo.h | 1 + Include/pyabiinfo.h | 15 --------------- Lib/test/test_stable_abi_ctypes.py | 1 - Misc/stable_abi.toml | 2 -- PC/python3dll.c | 1 - Python/abiinfo.c | 2 +- Python/sysmodule.c | 3 ++- 9 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 Include/pyabiinfo.h diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index a92f6ecdf0c8e4..0d0dfb3843260e 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -1,7 +1,6 @@ role,name,added,ifdef_note,struct_abi_kind macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,, func,PyAIter_Check,3.10,, -func,PyAbiInfo_GetInfo,3.15,, func,PyArg_Parse,3.2,, func,PyArg_ParseTuple,3.2,, func,PyArg_ParseTupleAndKeywords,3.2,, diff --git a/Include/Python.h b/Include/Python.h index 83261cb154fc0d..b6ee500aada791 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -138,6 +138,5 @@ #include "fileutils.h" #include "cpython/pyfpe.h" #include "cpython/tracemalloc.h" -#include "pyabiinfo.h" #endif /* !Py_PYTHON_H */ diff --git a/Include/internal/pycore_abiinfo.h b/Include/internal/pycore_abiinfo.h index 814af444c44f51..3b01bc27047f4b 100644 --- a/Include/internal/pycore_abiinfo.h +++ b/Include/internal/pycore_abiinfo.h @@ -4,6 +4,7 @@ extern "C" { #endif +extern PyObject *_PyAbiInfo_GetInfo(void); extern PyStatus _PyAbiInfo_InitTypes(PyInterpreterState *); extern void _PyAbiInfo_FiniTypes(PyInterpreterState *interp); diff --git a/Include/pyabiinfo.h b/Include/pyabiinfo.h deleted file mode 100644 index 97ea8f00ac80b8..00000000000000 --- a/Include/pyabiinfo.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef Py_PYABIINFO_H -#define Py_PYABIINFO_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030F0000 -PyAPI_FUNC(PyObject *) PyAbiInfo_GetInfo(void); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYABIINFO_H */ diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index ac97970dee7b19..5a6ba9de337904 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -46,7 +46,6 @@ def test_windows_feature_macros(self): SYMBOL_NAMES = ( "PyAIter_Check", - "PyAbiInfo_GetInfo", "PyArg_Parse", "PyArg_ParseTuple", "PyArg_ParseTupleAndKeywords", diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index a9b3a1c72e27a5..1f323cc03973e5 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2583,5 +2583,3 @@ added = '3.15' [function.PySys_GetOptionalAttrString] added = '3.15' -[function.PyAbiInfo_GetInfo] - added = '3.15' diff --git a/PC/python3dll.c b/PC/python3dll.c index 303c7c5cb7686d..8ec791f8280f13 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -93,7 +93,6 @@ EXPORT_FUNC(Py_SetRecursionLimit) EXPORT_FUNC(Py_TYPE) EXPORT_FUNC(Py_VaBuildValue) EXPORT_FUNC(Py_XNewRef) -EXPORT_FUNC(PyAbiInfo_GetInfo) EXPORT_FUNC(PyAIter_Check) EXPORT_FUNC(PyArg_Parse) EXPORT_FUNC(PyArg_ParseTuple) diff --git a/Python/abiinfo.c b/Python/abiinfo.c index a682f6e56aa218..1090d7e9f6400a 100644 --- a/Python/abiinfo.c +++ b/Python/abiinfo.c @@ -26,7 +26,7 @@ static PyStructSequence_Desc abi_info_desc = { }; PyObject * -PyAbiInfo_GetInfo(void) +_PyAbiInfo_GetInfo(void) { PyObject *abi_info, *value; int pos = 0; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index c74be21cfd33b0..d303b46468fdb1 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -15,6 +15,7 @@ Data members: */ #include "Python.h" +#include "pycore_abiinfo.h" // _PyAbiInfo_GetInfo() #include "pycore_audit.h" // _Py_AuditHookEntry #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_SetAsyncGenFinalizer() @@ -3856,7 +3857,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("thread_info", PyThread_GetInfo()); - SET_SYS("abi_info", PyAbiInfo_GetInfo()); + SET_SYS("abi_info", _PyAbiInfo_GetInfo()); /* initialize asyncgen_hooks */ if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, From defb2b2579e8ee3fb61ee3bc6ac3552e1d523980 Mon Sep 17 00:00:00 2001 From: Klaus Zimmermann Date: Thu, 7 Aug 2025 15:00:48 +0200 Subject: [PATCH 5/7] Make abi_info object a simple namespace with no explicit C API --- Doc/library/sys.rst | 22 +++---- Include/internal/pycore_abiinfo.h | 14 ----- Makefile.pre.in | 1 - PCbuild/_freeze_module.vcxproj | 1 - PCbuild/_freeze_module.vcxproj.filters | 3 - PCbuild/pythoncore.vcxproj | 1 - PCbuild/pythoncore.vcxproj.filters | 3 - Python/abiinfo.c | 79 -------------------------- Python/pylifecycle.c | 7 --- Python/sysmodule.c | 53 ++++++++++++++++- 10 files changed, 60 insertions(+), 124 deletions(-) delete mode 100644 Include/internal/pycore_abiinfo.h delete mode 100644 Python/abiinfo.c diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 7ed5fcca443b36..487c7559ef80ad 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -13,22 +13,18 @@ always available. Unless explicitly noted otherwise, all variables are read-only .. data:: abi_info - A :term:`named tuple` holding information about the ABI of the interpreter. + An object containing information about the ABI of the currently running + Python interpreter. The following attributes are available in cpython: - .. attribute:: abi_info.pointer_bits + *pointer_bits* is the width of pointers in bits, as an integer, equivalent + to ``8 * sizeof(void *)``, i.e. usually ``32`` or ``64``. - The width of pointers in bits, as an integer. - Equivalent to ``8 * sizeof(void *)``, i.e. usually ``32`` or ``64``. + *Py_GIL_DISABLED* is a boolean indicating whether the interpreter was built + with the GIL disabled, i.e. with the :option:`--disable-gil` option, + aka free-threading. - .. attribute:: abi_info.Py_GIL_DISABLED - - A boolean indicating whether the interpreter was built in with the GIL - disabled, i.e. with the :option:`--disable-gil` option, aka free-threading. - - .. attribute:: abi_info.Py_DEBUG - - A boolean indicating whether the interpreter was built in debug mode, - i.e. with the :option:`--with-pydebug` option. + *Py_DEBUG* is a boolean indicating whether the interpreter was built in + debug mode, i.e. with the :option:`--with-pydebug` option. .. versionadded:: next diff --git a/Include/internal/pycore_abiinfo.h b/Include/internal/pycore_abiinfo.h deleted file mode 100644 index 3b01bc27047f4b..00000000000000 --- a/Include/internal/pycore_abiinfo.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef Py_INTERNAL_ABIINFO_H -#define Py_INTERNAL_ABIINFO_H -#ifdef __cplusplus -extern "C" { -#endif - -extern PyObject *_PyAbiInfo_GetInfo(void); -extern PyStatus _PyAbiInfo_InitTypes(PyInterpreterState *); -extern void _PyAbiInfo_FiniTypes(PyInterpreterState *interp); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_ABIINFO_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 98e1bdab732ac4..bcf19654adfb35 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -423,7 +423,6 @@ PYTHON_OBJS= \ Python/_warnings.o \ Python/Python-ast.o \ Python/Python-tokenize.o \ - Python/abiinfo.o \ Python/asdl.o \ Python/assemble.o \ Python/ast.o \ diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 3b90666acb9b84..5ceddf759b8f3b 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -188,7 +188,6 @@ - diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 3c7caf07c3a834..332d466b1f7409 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -25,9 +25,6 @@ Source Files - - Python - Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 3d169da7464ba9..517103acea8d8e 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -582,7 +582,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 19f47b92c3ec58..e9eedfd1312fae 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1316,9 +1316,6 @@ Python - - Python - Python diff --git a/Python/abiinfo.c b/Python/abiinfo.c deleted file mode 100644 index 1090d7e9f6400a..00000000000000 --- a/Python/abiinfo.c +++ /dev/null @@ -1,79 +0,0 @@ -/* ABI information object implementation */ - -#include "Python.h" -#include "pycore_initconfig.h" // _PyStatus_OK() -#include "pycore_structseq.h" // _PyStructSequence_InitBuiltin() - -static PyTypeObject AbiInfoType; - -PyDoc_STRVAR(abi_info__doc__, -"ABI information object.\n\ -This object provides information about the ABI \ -features available in the current Python interpreter.\n"); - -static PyStructSequence_Field abi_info_fields[] = { - {"pointer_bits", "Is this a 32-bit or 64-bit build?"}, - {"Py_GIL_DISABLED", "Is free-threading enabled?"}, - {"Py_DEBUG", "Is debug mode enabled?"}, - {0} -}; - -static PyStructSequence_Desc abi_info_desc = { - "sys.abi_info", - abi_info__doc__, - abi_info_fields, - 3 -}; - -PyObject * -_PyAbiInfo_GetInfo(void) -{ - PyObject *abi_info, *value; - int pos = 0; - abi_info = PyStructSequence_New(&AbiInfoType); - if (abi_info == NULL) { - goto error; - } - - value = PyLong_FromLong(sizeof(void *) * 8); - if (value == NULL) { - goto error; - } - PyStructSequence_SetItem(abi_info, pos++, value); - -#ifdef Py_GIL_DISABLED - value = Py_True; -#else - value = Py_False; -#endif - PyStructSequence_SetItem(abi_info, pos++, value); - -#ifdef Py_DEBUG - value = Py_True; -#else - value = Py_False; -#endif - PyStructSequence_SetItem(abi_info, pos++, value); - - return abi_info; - -error: - Py_XDECREF(abi_info); - return NULL; -} - -PyStatus -_PyAbiInfo_InitTypes(PyInterpreterState *interp) -{ - if (_PyStructSequence_InitBuiltin(interp, &AbiInfoType, &abi_info_desc) < 0) { - return _PyStatus_ERR("Failed to initialize AbiInfoType"); - } - - return _PyStatus_OK(); -} - -void -_PyAbiInfo_FiniTypes(PyInterpreterState *interp) -{ - _PyStructSequence_FiniBuiltin(interp, &AbiInfoType); -} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 4441ebcb66afe6..e22a9cc1c75050 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1,7 +1,6 @@ /* Python interpreter top-level routines, including init/exit */ #include "Python.h" -#include "pycore_abiinfo.h" // _PyAbiInfo_InitTypes() #include "pycore_audit.h" // _PySys_ClearAuditHooks() #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_ceval.h" // _PyEval_FiniGIL() @@ -712,11 +711,6 @@ pycore_init_types(PyInterpreterState *interp) return status; } - status = _PyAbiInfo_InitTypes(interp); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - status = _PyLong_InitTypes(interp); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1866,7 +1860,6 @@ static void finalize_interp_types(PyInterpreterState *interp) { _PyTypes_FiniExtTypes(interp); - _PyAbiInfo_FiniTypes(interp); _PyUnicode_FiniTypes(interp); _PySys_FiniTypes(interp); _PyXI_FiniTypes(interp); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index d303b46468fdb1..c77edb05368145 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -15,7 +15,6 @@ Data members: */ #include "Python.h" -#include "pycore_abiinfo.h" // _PyAbiInfo_GetInfo() #include "pycore_audit.h" // _Py_AuditHookEntry #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_SetAsyncGenFinalizer() @@ -3632,6 +3631,56 @@ make_impl_info(PyObject *version_info) return NULL; } + +PyObject * +make_abi_info(void) +{ + int res; + PyObject *abi_info, *value, *ns; + abi_info = PyDict_New(); + if (abi_info == NULL) { + goto error; + } + + value = PyLong_FromLong(sizeof(void *) * 8); + if (value == NULL) { + goto error; + } + res = PyDict_SetItemString(abi_info, "pointer_bits", value); + Py_DECREF(value); + if (res < 0) { + goto error; + } + +#ifdef Py_GIL_DISABLED + value = Py_True; +#else + value = Py_False; +#endif + res = PyDict_SetItemString(abi_info, "Py_GIL_DISABLED", value); + if (res < 0) { + goto error; + } + +#ifdef Py_DEBUG + value = Py_True; +#else + value = Py_False; +#endif + res = PyDict_SetItemString(abi_info, "Py_DEBUG", value); + if (res < 0) { + goto error; + } + + ns = _PyNamespace_New(abi_info); + Py_DECREF(abi_info); + return ns; + +error: + Py_CLEAR(abi_info); + return NULL; +} + #ifdef __EMSCRIPTEN__ PyDoc_STRVAR(emscripten_info__doc__, @@ -3857,7 +3906,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("thread_info", PyThread_GetInfo()); - SET_SYS("abi_info", _PyAbiInfo_GetInfo()); + SET_SYS("abi_info", make_abi_info()); /* initialize asyncgen_hooks */ if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, From 8364d784e4d2c92865a5640876e1b271ea102ccb Mon Sep 17 00:00:00 2001 From: Klaus Zimmermann Date: Thu, 7 Aug 2025 15:42:54 +0200 Subject: [PATCH 6/7] Cleanup scaffolding --- Lib/test/_test_embed_structseq.py | 1 - Tools/c-analyzer/TODO | 1 - Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 3 files changed, 3 deletions(-) diff --git a/Lib/test/_test_embed_structseq.py b/Lib/test/_test_embed_structseq.py index 90635319e1eef4..4cac84d7a469ac 100644 --- a/Lib/test/_test_embed_structseq.py +++ b/Lib/test/_test_embed_structseq.py @@ -25,7 +25,6 @@ def check_structseq(self, obj_type): def test_sys_attrs(self): for attr_name in ( - 'abi_info', # AbiInfoType 'flags', # FlagsType 'float_info', # FloatInfoType 'hash_info', # Hash_InfoType diff --git a/Tools/c-analyzer/TODO b/Tools/c-analyzer/TODO index 81d3dc8dc2d1bc..2077534ccf4128 100644 --- a/Tools/c-analyzer/TODO +++ b/Tools/c-analyzer/TODO @@ -841,7 +841,6 @@ Objects/unicodeobject.c:PyUnicode_Type PyTypeObject Py Objects/weakrefobject.c:_PyWeakref_CallableProxyType PyTypeObject _PyWeakref_CallableProxyType Objects/weakrefobject.c:_PyWeakref_ProxyType PyTypeObject _PyWeakref_ProxyType Objects/weakrefobject.c:_PyWeakref_RefType PyTypeObject _PyWeakref_RefType -Python/abiinfo.c:AbiInfoType static PyTypeObject AbiInfoType Python/bltinmodule.c:PyFilter_Type PyTypeObject PyFilter_Type Python/bltinmodule.c:PyMap_Type PyTypeObject PyMap_Type Python/bltinmodule.c:PyZip_Type PyTypeObject PyZip_Type diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index f0d0bb201b459a..3c3cb2f9c86f16 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -153,7 +153,6 @@ Objects/object.c - _PyLegacyEventHandler_Type - Objects/floatobject.c - FloatInfoType - Objects/longobject.c - Int_InfoType - -Python/abiinfo.c - AbiInfoType - Python/errors.c - UnraisableHookArgsType - Python/sysmodule.c - AsyncGenHooksType - Python/sysmodule.c - FlagsType - From 3e1c98f9472aefab0659c4635b45778469078646 Mon Sep 17 00:00:00 2001 From: Klaus Zimmermann Date: Thu, 7 Aug 2025 15:43:56 +0200 Subject: [PATCH 7/7] Fix make_abi_info to be static --- Python/sysmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index c77edb05368145..53296f3b4f9823 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3632,7 +3632,7 @@ make_impl_info(PyObject *version_info) } -PyObject * +static PyObject * make_abi_info(void) { int res;