mirror of https://github.com/python/cpython
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
This commit is contained in:
parent
da3cf4304f
commit
50669083fe
|
@ -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
|
Thus ``3.4.1a2`` is hexversion ``0x030401a2`` and ``3.10.0`` is
|
||||||
hexversion ``0x030a00f0``.
|
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`.
|
All the given macros are defined in :source:`Include/patchlevel.h`.
|
||||||
|
|
|
@ -553,6 +553,8 @@ Process-wide parameters
|
||||||
period. The returned string points into static storage; the caller should not
|
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`.
|
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()
|
.. c:function:: const char* Py_GetPlatform()
|
||||||
|
|
||||||
|
|
|
@ -830,6 +830,7 @@ type,Py_UCS4,3.2,
|
||||||
macro,Py_UNBLOCK_THREADS,3.2,
|
macro,Py_UNBLOCK_THREADS,3.2,
|
||||||
var,Py_UTF8Mode,3.8,
|
var,Py_UTF8Mode,3.8,
|
||||||
function,Py_VaBuildValue,3.2,
|
function,Py_VaBuildValue,3.2,
|
||||||
|
var,Py_Version,3.11,
|
||||||
function,Py_XNewRef,3.10,
|
function,Py_XNewRef,3.10,
|
||||||
type,Py_intptr_t,3.2,
|
type,Py_intptr_t,3.2,
|
||||||
type,Py_ssize_t,3.2,
|
type,Py_ssize_t,3.2,
|
||||||
|
|
|
@ -626,6 +626,10 @@ New Features
|
||||||
fields of the result from the exception instance (the ``value`` field).
|
fields of the result from the exception instance (the ``value`` field).
|
||||||
(Contributed by Irit Katriel in :issue:`45711`.)
|
(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
|
Porting to Python 3.11
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -62,6 +62,10 @@ typedef void (*PyOS_sighandler_t)(int);
|
||||||
PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int);
|
PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int);
|
||||||
PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t);
|
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
|
#ifndef Py_LIMITED_API
|
||||||
# define Py_CPYTHON_PYLIFECYCLE_H
|
# define Py_CPYTHON_PYLIFECYCLE_H
|
||||||
# include "cpython/pylifecycle.h"
|
# include "cpython/pylifecycle.h"
|
||||||
|
|
|
@ -840,6 +840,9 @@ class Test_testcapi(unittest.TestCase):
|
||||||
def test_widechar(self):
|
def test_widechar(self):
|
||||||
_testcapi.test_widechar()
|
_testcapi.test_widechar()
|
||||||
|
|
||||||
|
def test_version_api_data(self):
|
||||||
|
self.assertEqual(_testcapi.Py_Version, sys.hexversion)
|
||||||
|
|
||||||
|
|
||||||
class Test_testinternalcapi(unittest.TestCase):
|
class Test_testinternalcapi(unittest.TestCase):
|
||||||
locals().update((name, getattr(_testinternalcapi, name))
|
locals().update((name, getattr(_testinternalcapi, name))
|
||||||
|
|
|
@ -808,6 +808,7 @@ SYMBOL_NAMES = (
|
||||||
"Py_SetRecursionLimit",
|
"Py_SetRecursionLimit",
|
||||||
"Py_UTF8Mode",
|
"Py_UTF8Mode",
|
||||||
"Py_VaBuildValue",
|
"Py_VaBuildValue",
|
||||||
|
"Py_Version",
|
||||||
"Py_XNewRef",
|
"Py_XNewRef",
|
||||||
"_PyArg_ParseTupleAndKeywords_SizeT",
|
"_PyArg_ParseTupleAndKeywords_SizeT",
|
||||||
"_PyArg_ParseTuple_SizeT",
|
"_PyArg_ParseTuple_SizeT",
|
||||||
|
|
|
@ -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.
|
|
@ -2153,3 +2153,6 @@ data PyStructSequence_UnnamedField
|
||||||
|
|
||||||
# (Detailed comments aren't really needed for further entries: from here on
|
# (Detailed comments aren't really needed for further entries: from here on
|
||||||
# we can use version control logs.)
|
# we can use version control logs.)
|
||||||
|
|
||||||
|
data Py_Version
|
||||||
|
added 3.11
|
||||||
|
|
|
@ -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_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, "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, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t)));
|
||||||
|
PyModule_AddObject(m, "Py_Version", PyLong_FromUnsignedLong(Py_Version));
|
||||||
Py_INCREF(&PyInstanceMethod_Type);
|
Py_INCREF(&PyInstanceMethod_Type);
|
||||||
PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);
|
PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);
|
||||||
|
|
||||||
|
|
|
@ -725,6 +725,7 @@ EXPORT_DATA(Py_FileSystemDefaultEncoding)
|
||||||
EXPORT_DATA(Py_GenericAliasType)
|
EXPORT_DATA(Py_GenericAliasType)
|
||||||
EXPORT_DATA(Py_HasFileSystemDefaultEncoding)
|
EXPORT_DATA(Py_HasFileSystemDefaultEncoding)
|
||||||
EXPORT_DATA(Py_UTF8Mode)
|
EXPORT_DATA(Py_UTF8Mode)
|
||||||
|
EXPORT_DATA(Py_Version)
|
||||||
EXPORT_DATA(PyBaseObject_Type)
|
EXPORT_DATA(PyBaseObject_Type)
|
||||||
EXPORT_DATA(PyBool_Type)
|
EXPORT_DATA(PyBool_Type)
|
||||||
EXPORT_DATA(PyByteArray_Type)
|
EXPORT_DATA(PyByteArray_Type)
|
||||||
|
|
|
@ -13,3 +13,6 @@ Py_GetVersion(void)
|
||||||
PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler());
|
PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler());
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export the Python hex version as a constant.
|
||||||
|
const unsigned long Py_Version = PY_VERSION_HEX;
|
||||||
|
|
Loading…
Reference in New Issue