[Python-checkins] bpo-43931: Export Python version as API data (GH-25577)

miss-islington webhook-mailer at python.org
Thu Dec 9 20:52:20 EST 2021


https://github.com/python/cpython/commit/50669083fe16a42cba90b5dd8c1a017751f69fd8
commit: 50669083fe16a42cba90b5dd8c1a017751f69fd8
branch: main
author: Gabriele N. Tornetta <P403n1x87 at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2021-12-09T17:52:05-08:00
summary:

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

files:
A Misc/NEWS.d/next/Core and Builtins/2021-04-24-15-39-23.bpo-43931.zpChDi.rst
M Doc/c-api/apiabiversion.rst
M Doc/c-api/init.rst
M Doc/data/stable_abi.dat
M Doc/whatsnew/3.11.rst
M Include/pylifecycle.h
M Lib/test/test_capi.py
M Lib/test/test_stable_abi_ctypes.py
M Misc/stable_abi.txt
M Modules/_testcapimodule.c
M PC/python3dll.c
M Python/getversion.c

diff --git a/Doc/c-api/apiabiversion.rst b/Doc/c-api/apiabiversion.rst
index 04050f7dabe17..53a42e7f28ef1 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 09dfc68fee57d..322b9e4d251e7 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 64a0a2a247cd2..02e54e5d7f14a 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 7a828663e7f34..8d1f4eba36eb2 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 4aecda235abf7..e4c3b09c963fe 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 d51247003ded1..ecf3aa34ede7c 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 d0cd5c20dd5f4..9fd6b14b0232a 100644
--- a/Lib/test/test_stable_abi_ctypes.py
+++ b/Lib/test/test_stable_abi_ctypes.py
@@ -808,6 +808,7 @@ def test_available_symbols(self):
     "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 0000000000000..037512916878c
--- /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 de6caa8c80746..9cb210c60cf24 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 56d394985eb7c..6116365b2c0f7 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 6e469357ede50..b2bb1706c4a2e 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 c32b6f9d60d4b..46910451fdf85 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;



More information about the Python-checkins mailing list