diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 70d68c06187b60..34764a7e4f097b 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -11,6 +11,51 @@ 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 + + .. versionadded:: next + + An object containing information about the ABI of the currently running + Python interpreter. + It should include information that affect the CPython ABI in ways that + require a specific build of the interpreter chosen from variants that can + co-exist on a single machine. + For example, it does not encode the base OS (Linux or Windows), but does + include pointer size since some systems support both 32- and 64-bit builds. + The available entries are the same on all platforms; + e.g. *pointer_size* is available even on 64-bit-only architectures. + + The following attributes are available: + + .. attribute:: abi_info.pointer_bits + + The width of pointers in bits, as an integer, + equivalent to ``8 * sizeof(void *)``. + Usually, this is ``32`` or ``64``. + + .. attribute:: abi_info.free_threaded + + A Boolean indicating whether the interpreter was built with + :term:`free threading` support. + This reflects either the presence of the :option:`--disable-gil` + :file:`configure` option (on Unix) + or setting the ``DisableGil`` property (on Windows). + + .. attribute:: abi_info.debug + + A Boolean indicating whether the interpreter was built in + :ref:`debug mode `. + This reflects either the presence of the :option:`--with-pydebug` + :file:`configure` option (on Unix) + or the ``Debug`` configuration (on Windows). + + .. attribute:: abi_info.byteorder + + A string indicating the native byte order, + either ``'big'`` or ``'little'``. + This is the same as the :data:`byteorder` attribute. + + .. data:: abiflags On POSIX systems where Python was built with the standard ``configure`` diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index b98ee202ec6db6..01f1f31647f5e3 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -460,6 +460,13 @@ ssl (Contributed by Ron Frederick in :gh:`138252`.) +sys +--- + +* Add :data:`sys.abi_info` namespace to improve access to ABI information. + (Contributed by Klaus Zimmermann in :gh:`137476`.) + + tarfile ------- diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index f89237931b7185..42672eb7912eba 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -739,6 +739,20 @@ def test_thread_info(self): elif sys.platform == "wasi": self.assertEqual(info.name, "pthread-stubs") + def test_abi_info(self): + info = sys.abi_info + self.assertEqual(len(info.__dict__), 4) + pointer_bits = 64 if sys.maxsize > 2**32 else 32 + self.assertEqual(info.pointer_bits, pointer_bits) + self.assertEqual(info.byteorder, sys.byteorder) + for attr, flag in [ + ("free_threaded", "Py_GIL_DISABLED"), + ("debug", "Py_DEBUG"), + ]: + self.assertEqual(getattr(info, attr, None), + bool(sysconfig.get_config_var(flag)), + f"for {attr}") + @unittest.skipUnless(support.is_emscripten, "only available on Emscripten") def test_emscripten_info(self): self.assertEqual(len(sys._emscripten_info), 4) 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. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index cc798f6ae5c034..95ab87589718ce 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3268,6 +3268,7 @@ PyDoc_STR( "\n\ Static objects:\n\ \n\ +abi_info -- Python ABI information.\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\ @@ -3638,6 +3639,73 @@ make_impl_info(PyObject *version_info) return NULL; } + +static PyObject * +make_abi_info(void) +{ + // New entries should be added when needed for a supported platform, or (for + // enabling an unsupported one) by core dev consensus. Entries should be removed + // following PEP 387. + 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, "free_threaded", value); + if (res < 0) { + goto error; + } + +#ifdef Py_DEBUG + value = Py_True; +#else + value = Py_False; +#endif + res = PyDict_SetItemString(abi_info, "debug", value); + if (res < 0) { + goto error; + } + +#if PY_BIG_ENDIAN + value = PyUnicode_FromString("big"); +#else + value = PyUnicode_FromString("little"); +#endif + if (value == NULL) { + goto error; + } + res = PyDict_SetItemString(abi_info, "byteorder", value); + Py_DECREF(value); + if (res < 0) { + goto error; + } + + ns = _PyNamespace_New(abi_info); + Py_DECREF(abi_info); + return ns; + +error: + Py_DECREF(abi_info); + return NULL; +} + #ifdef __EMSCRIPTEN__ PyDoc_STRVAR(emscripten_info__doc__, @@ -3863,6 +3931,8 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("thread_info", PyThread_GetInfo()); + SET_SYS("abi_info", make_abi_info()); + /* initialize asyncgen_hooks */ if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, &asyncgen_hooks_desc) < 0)