From: Gabriele N. Tornetta Date: Fri, 10 Dec 2021 01:52:05 +0000 (+0000) Subject: bpo-43931: Export Python version as API data (GH-25577) X-Git-Tag: v3.11.0a4~240 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=50669083fe16a42cba90b5dd8c1a017751f69fd8;p=thirdparty%2FPython%2Fcpython.git bpo-43931: Export Python version as API data (GH-25577) When Python is embedded in other applications, it is not easy to determine which version of Python is being used. This change exposes the Python version as part of the API data. Tools like Austin (https://github.com/P403n1x87/austin) can benefit from this data when targeting applications like uWSGI, as the Python version can then be inferred systematically by looking at the exported symbols rather than relying on unreliable pattern matching or other hacks (like remote code execution etc...). Automerge-Triggered-By: GH:pablogsal --- diff --git a/Doc/c-api/apiabiversion.rst b/Doc/c-api/apiabiversion.rst index 04050f7dabe1..53a42e7f28ef 100644 --- a/Doc/c-api/apiabiversion.rst +++ b/Doc/c-api/apiabiversion.rst @@ -58,5 +58,14 @@ See :ref:`stable` for a discussion of API and ABI stability across versions. Thus ``3.4.1a2`` is hexversion ``0x030401a2`` and ``3.10.0`` is hexversion ``0x030a00f0``. + This version is also available via the symbol :data:`Py_Version`. + +.. c:var:: const unsigned long Py_Version + + The Python runtime version number encoded in a single constant integer, with + the same format as the c:macro:`PY_VERSION_HEX` macro. + This contains the Python version used at run time. + + .. versionadded:: 3.11 All the given macros are defined in :source:`Include/patchlevel.h`. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 09dfc68fee57..322b9e4d251e 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -553,6 +553,8 @@ Process-wide parameters period. The returned string points into static storage; the caller should not modify its value. The value is available to Python code as :data:`sys.version`. + See also the :data:`Py_Version` constant. + .. c:function:: const char* Py_GetPlatform() diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 64a0a2a247cd..02e54e5d7f14 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -830,6 +830,7 @@ type,Py_UCS4,3.2, macro,Py_UNBLOCK_THREADS,3.2, var,Py_UTF8Mode,3.8, function,Py_VaBuildValue,3.2, +var,Py_Version,3.11, function,Py_XNewRef,3.10, type,Py_intptr_t,3.2, type,Py_ssize_t,3.2, diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 7a828663e7f3..8d1f4eba36eb 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -626,6 +626,10 @@ New Features fields of the result from the exception instance (the ``value`` field). (Contributed by Irit Katriel in :issue:`45711`.) +* Added the :c:data:`Py_Version` constant which bears the same value as + :c:macro:`PY_VERSION_HEX`. + (Contributed by Gabriele N. Tornetta in :issue:`43931`.) + Porting to Python 3.11 ---------------------- diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index 4aecda235abf..e4c3b09c963f 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -62,6 +62,10 @@ typedef void (*PyOS_sighandler_t)(int); PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030B0000 +PyAPI_DATA(const unsigned long) Py_Version; +#endif + #ifndef Py_LIMITED_API # define Py_CPYTHON_PYLIFECYCLE_H # include "cpython/pylifecycle.h" diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index d51247003ded..ecf3aa34ede7 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -840,6 +840,9 @@ class Test_testcapi(unittest.TestCase): def test_widechar(self): _testcapi.test_widechar() + def test_version_api_data(self): + self.assertEqual(_testcapi.Py_Version, sys.hexversion) + class Test_testinternalcapi(unittest.TestCase): locals().update((name, getattr(_testinternalcapi, name)) diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index d0cd5c20dd5f..9fd6b14b0232 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -808,6 +808,7 @@ SYMBOL_NAMES = ( "Py_SetRecursionLimit", "Py_UTF8Mode", "Py_VaBuildValue", + "Py_Version", "Py_XNewRef", "_PyArg_ParseTupleAndKeywords_SizeT", "_PyArg_ParseTuple_SizeT", diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-04-24-15-39-23.bpo-43931.zpChDi.rst b/Misc/NEWS.d/next/Core and Builtins/2021-04-24-15-39-23.bpo-43931.zpChDi.rst new file mode 100644 index 000000000000..037512916878 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-04-24-15-39-23.bpo-43931.zpChDi.rst @@ -0,0 +1,2 @@ +Added the :c:data:`Py_Version` constant which bears the same value as +:c:macro:`PY_VERSION_HEX`. Patch by Gabriele N. Tornetta. \ No newline at end of file diff --git a/Misc/stable_abi.txt b/Misc/stable_abi.txt index de6caa8c8074..9cb210c60cf2 100644 --- a/Misc/stable_abi.txt +++ b/Misc/stable_abi.txt @@ -2153,3 +2153,6 @@ data PyStructSequence_UnnamedField # (Detailed comments aren't really needed for further entries: from here on # we can use version control logs.) + +data Py_Version + added 3.11 diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 56d394985eb7..6116365b2c0f 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -7525,6 +7525,7 @@ PyInit__testcapi(void) PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyLong_FromSsize_t(PY_SSIZE_T_MAX)); PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyLong_FromSsize_t(PY_SSIZE_T_MIN)); PyModule_AddObject(m, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t))); + PyModule_AddObject(m, "Py_Version", PyLong_FromUnsignedLong(Py_Version)); Py_INCREF(&PyInstanceMethod_Type); PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type); diff --git a/PC/python3dll.c b/PC/python3dll.c index 6e469357ede5..b2bb1706c4a2 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -725,6 +725,7 @@ EXPORT_DATA(Py_FileSystemDefaultEncoding) EXPORT_DATA(Py_GenericAliasType) EXPORT_DATA(Py_HasFileSystemDefaultEncoding) EXPORT_DATA(Py_UTF8Mode) +EXPORT_DATA(Py_Version) EXPORT_DATA(PyBaseObject_Type) EXPORT_DATA(PyBool_Type) EXPORT_DATA(PyByteArray_Type) diff --git a/Python/getversion.c b/Python/getversion.c index c32b6f9d60d4..46910451fdf8 100644 --- a/Python/getversion.c +++ b/Python/getversion.c @@ -13,3 +13,6 @@ Py_GetVersion(void) PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler()); return version; } + +// Export the Python hex version as a constant. +const unsigned long Py_Version = PY_VERSION_HEX;