https://github.com/python/cpython/commit/1acb718ea215da7ff030f5457bdfa42c31ef39c1
commit: 1acb718ea215da7ff030f5457bdfa42c31ef39c1
branch: main
author: Klaus Zimmermann <[email protected]>
committer: encukou <[email protected]>
date: 2025-09-08T14:35:44Z
summary:

gh-133143: Add sys.abi_info (GH-137476)

This makes information about the interpreter ABI more accessible.

Co-authored-by: Petr Viktorin <[email protected]>
Co-authored-by: Victor Stinner <[email protected]>
Co-authored-by: Adam Turner <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst
M Doc/library/sys.rst
M Doc/whatsnew/3.15.rst
M Lib/test/test_sys.py
M Python/sysmodule.c

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 <debug-build>`.
+      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)

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to