diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 2bdfb337f02056..58bd1a4df0e4ca 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -11,6 +11,26 @@ 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_features + + A frozen set of strings that represent ABI features. + Currently supported features are: + + ``free-threading`` or ``gil-enabled`` + The Python interpreter is free-threaded. On POSIX systems, this corresponds + to ``"t" in sys.abiflags``. + + ``debug`` + The Python interpreter has debugging capabilities. On POSIX systems, this + corresponds to ``"d" in sys.abiflags``. + + ``32-bit`` or ``64-bit`` + The bitness of the interpreter, that is, whether it is a 32-bit or 64-bit + build. + + .. versionadded:: 3.14 + + .. data:: abiflags On POSIX systems where Python was built with the standard ``configure`` diff --git a/Python/sysmodule.c b/Python/sysmodule.c index adaa5ee1c74aa5..21d6a880c42dde 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3479,6 +3479,71 @@ make_impl_info(PyObject *version_info) return NULL; } +static PyObject* +make_abi_features(void) +{ + int res; + PyObject *features = PyFrozenSet_New(NULL); + if (features == NULL) { + goto error; + } + +#ifdef Py_GIL_DISABLED + PyObject *threading_feature = PyUnicode_FromString("free-threading"); +#else + PyObject *threading_feature = PyUnicode_FromString("gil-enabled"); +#endif + if (threading_feature == NULL) { + goto error; + } + res = PySet_Add(features, threading_feature); + Py_DECREF(threading_feature); + if (res < 0) { + goto error; + } + +#ifdef Py_DEBUG + PyObject *debug = PyUnicode_FromString("debug"); + if (debug == NULL) { + goto error; + } + res = PySet_Add(features, debug); + Py_DECREF(debug); + if (res < 0) { + goto error; + } +#endif + + PyObject *bitness; + switch (PY_SSIZE_T_MAX) { + case 0x7FFFFFFFL: + bitness = PyUnicode_FromString("32-bit"); + break; + case 0x7FFFFFFFFFFFFFFFL: + bitness = PyUnicode_FromString("64-bit"); + break; + default: + bitness = Py_NewRef(Py_None); + break; + } + if (bitness == NULL) { + goto error; + } + if (bitness != Py_None) { + res = PySet_Add(features, bitness); + } + Py_DECREF(bitness); + if (res < 0) { + goto error; + } + + return features; + +error: + Py_XDECREF(features); + return NULL; +} + #ifdef __EMSCRIPTEN__ PyDoc_STRVAR(emscripten_info__doc__, @@ -3665,6 +3730,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) #ifdef ABIFLAGS SET_SYS_FROM_STRING("abiflags", ABIFLAGS); #endif + SET_SYS("abi_features", make_abi_features()); #define ENSURE_INFO_TYPE(TYPE, DESC) \ do { \