]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-133143: Add sys.abi_info (GH-137476)
authorKlaus Zimmermann <klaus.zimmermann@quansight.com>
Mon, 8 Sep 2025 14:35:44 +0000 (16:35 +0200)
committerGitHub <noreply@github.com>
Mon, 8 Sep 2025 14:35:44 +0000 (14:35 +0000)
This makes information about the interpreter ABI more accessible.

Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Doc/library/sys.rst
Doc/whatsnew/3.15.rst
Lib/test/test_sys.py
Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst [new file with mode: 0644]
Python/sysmodule.c

index 70d68c06187b605e7979ffccbe8f4cfcc5ef2f65..34764a7e4f097b0c67e2330f57ce43554092e111 100644 (file)
@@ -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``
index b98ee202ec6db6aca5747b7d948f18743fdaf2b7..01f1f31647f5e3f1638445ba959a7c1d21634c20 100644 (file)
@@ -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
 -------
 
index f89237931b7185cee0e447a890dffc3db2c66f1a..42672eb7912ebaa2dcdc6b1c65bdae43098d5bd1 100644 (file)
@@ -739,6 +739,20 @@ class SysModuleTest(unittest.TestCase):
         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 (file)
index 0000000..eaffb40
--- /dev/null
@@ -0,0 +1 @@
+Add ``sys.abi_info`` object to make ABI information more easily accessible.
index cc798f6ae5c0343b006afb0bbee4df9df9bb2df5..95ab87589718ce418eaa3737b3723be12af302a4 100644 (file)
@@ -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 @@ error:
     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)