diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 2078c201b4558d..ad65d1fda18e3b 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -984,6 +984,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format_spec)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(frame_buffer)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(free_threaded)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(from_param)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromlist)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromtimestamp)); @@ -1182,6 +1183,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(person)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pi_factory)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pid)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pointer_bits)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(policy)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos1)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index a7ebaf76c908c8..88283fa625706f 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -475,6 +475,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(format) STRUCT_FOR_ID(format_spec) STRUCT_FOR_ID(frame_buffer) + STRUCT_FOR_ID(free_threaded) STRUCT_FOR_ID(from_param) STRUCT_FOR_ID(fromlist) STRUCT_FOR_ID(fromtimestamp) @@ -673,6 +674,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(person) STRUCT_FOR_ID(pi_factory) STRUCT_FOR_ID(pid) + STRUCT_FOR_ID(pointer_bits) STRUCT_FOR_ID(policy) STRUCT_FOR_ID(pos) STRUCT_FOR_ID(pos1) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 27669c50cd6101..a08d77ab0a06b9 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -982,6 +982,7 @@ extern "C" { INIT_ID(format), \ INIT_ID(format_spec), \ INIT_ID(frame_buffer), \ + INIT_ID(free_threaded), \ INIT_ID(from_param), \ INIT_ID(fromlist), \ INIT_ID(fromtimestamp), \ @@ -1180,6 +1181,7 @@ extern "C" { INIT_ID(person), \ INIT_ID(pi_factory), \ INIT_ID(pid), \ + INIT_ID(pointer_bits), \ INIT_ID(policy), \ INIT_ID(pos), \ INIT_ID(pos1), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index c9b8a8b50510a2..57c0a7d51f89f3 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1688,6 +1688,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(free_threaded); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(from_param); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2480,6 +2484,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(pointer_bits); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(policy); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 42672eb7912eba..1198c6d35113c8 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -741,17 +741,15 @@ def test_thread_info(self): def test_abi_info(self): info = sys.abi_info - self.assertEqual(len(info.__dict__), 4) + info_keys = {'pointer_bits', 'free_threaded', 'debug', 'byteorder'} + self.assertEqual(set(vars(info)), info_keys) pointer_bits = 64 if sys.maxsize > 2**32 else 32 self.assertEqual(info.pointer_bits, pointer_bits) + self.assertEqual(info.free_threaded, + bool(sysconfig.get_config_var('Py_GIL_DISABLED'))) + self.assertEqual(info.debug, + bool(sysconfig.get_config_var('Py_DEBUG'))) 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): 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 index eaffb4022c6770..b357fbcdb9fbd0 100644 --- 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 @@ -1 +1 @@ -Add ``sys.abi_info`` object to make ABI information more easily accessible. +Add :data:`sys.abi_info` object to make ABI information more easily accessible. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 95ab87589718ce..a5b42d48e432d7 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3643,33 +3643,30 @@ make_impl_info(PyObject *version_info) 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(); + // New entries should be added when needed for a supported platform, + // or by core dev consensus for enabling an unsupported one. + + PyObject *value; + PyObject *abi_info = PyDict_New(); if (abi_info == NULL) { - goto error; + return NULL; } 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) { + if (PyDict_SetItem(abi_info, &_Py_ID(pointer_bits), value) < 0) { goto error; } + Py_DECREF(value); #ifdef Py_GIL_DISABLED value = Py_True; #else value = Py_False; #endif - res = PyDict_SetItemString(abi_info, "free_threaded", value); - if (res < 0) { + if (PyDict_SetItem(abi_info, &_Py_ID(free_threaded), value) < 0) { goto error; } @@ -3678,34 +3675,30 @@ make_abi_info(void) #else value = Py_False; #endif - res = PyDict_SetItemString(abi_info, "debug", value); - if (res < 0) { + if (PyDict_SetItem(abi_info, &_Py_ID(debug), value) < 0) { goto error; } #if PY_BIG_ENDIAN - value = PyUnicode_FromString("big"); + value = &_Py_ID(big); #else - value = PyUnicode_FromString("little"); + value = &_Py_ID(little); #endif - if (value == NULL) { - goto error; - } - res = PyDict_SetItemString(abi_info, "byteorder", value); - Py_DECREF(value); - if (res < 0) { + if (PyDict_SetItem(abi_info, &_Py_ID(byteorder), value) < 0) { goto error; } - ns = _PyNamespace_New(abi_info); + PyObject *ns = _PyNamespace_New(abi_info); Py_DECREF(abi_info); return ns; error: Py_DECREF(abi_info); + Py_XDECREF(value); return NULL; } + #ifdef __EMSCRIPTEN__ PyDoc_STRVAR(emscripten_info__doc__,