Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/c-api/interp-lifecycle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ Process-wide parameters
Return the version of this Python interpreter. This is a string that looks
something like ::
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
"3.15.0rc2 (3.15.0~rc2-1.fc44.x86_64, Sep 3 2026, 00:00:00) [GCC 16.2.1 20260819 (Red Hat 16.2.1-2)]"
.. index:: single: version (in module sys)
Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extern int _Py_IsLocaleCoercionTarget(const char *ctype_loc);

/* Various one-time initializers */

extern void _Py_InitVersion(void);
extern PyStatus _Py_GetVersion_Init(void);
extern PyStatus _PyFaulthandler_Init(int enable);
extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp);
extern int _PyBuiltin_InitPythonFunctions(PyObject *dict);
Expand All @@ -43,6 +43,7 @@ extern PyStatus _PyDateTime_InitTypes(PyInterpreterState *interp);

/* Various internal finalizers */

extern void _Py_GetVersion_Fini(void);
extern int _PySignal_Init(int install_signal_handlers);
extern void _PySignal_Fini(void);

Expand Down
8 changes: 2 additions & 6 deletions Lib/test/test_capi/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,11 @@ def test_getcopyright(self):

# Test Py_GetCompiler()
def test_getcompiler(self):
compiler = _testlimitedcapi.py_getcompiler()
self.assertIsInstance(compiler, str)
self.assertNotEqual(compiler, '')
self.assertIn(_testlimitedcapi.py_getcompiler(), sys.version)

# Test Py_GetBuildInfo()
def test_getbuildinfo(self):
buildinfo = _testlimitedcapi.py_getbuildinfo()
self.assertIsInstance(buildinfo, str)
self.assertNotEqual(buildinfo, '')
self.assertIn(_testlimitedcapi.py_getbuildinfo(), sys.version)

# Test internal _Py_GetBuiltWithAssert()
def test__getbuiltwithassert(self):
Expand Down
1 change: 1 addition & 0 deletions Modules/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ pymain_free(void)
_PyPathConfig_ClearGlobal();
_Py_ClearArgcArgv();
_PyRuntime_Finalize();
_Py_GetVersion_Fini();
}


Expand Down
9 changes: 5 additions & 4 deletions Python/getcompiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "Python.h"

// PC/pyconfig.h defines _Py_COMPILER
#ifdef _Py_COMPILER
# define COMPILER _Py_COMPILER
#endif
Expand All @@ -12,14 +13,14 @@
// Note the __clang__ conditional has to come before the __GNUC__ one because
// clang pretends to be GCC.
#if defined(__clang__)
#define COMPILER "[Clang " __clang_version__ "]"
# define COMPILER "[Clang " __clang_version__ "]"
#elif defined(__GNUC__)
#define COMPILER "[GCC " __VERSION__ "]"
# define COMPILER "[GCC " __VERSION__ "]"
// Generic fallbacks.
#elif defined(__cplusplus)
#define COMPILER "[C++]"
# define COMPILER "[C++]"
#else
#define COMPILER "[C]"
# define COMPILER "[C]"
#endif

#endif /* !COMPILER */
Expand Down
67 changes: 56 additions & 11 deletions Python/getversion.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,77 @@
/* Return the full version string. */

#include "Python.h"
#include "pycore_initconfig.h" // _PyStatus_NO_MEMORY()

#include "patchlevel.h"

static int initialized = 0;
static char version[300];
// Use the smallest possible buffer: it's only needed if malloc() fails *and*
// Py_GetVersion() is called before Py_Initialize(). The buffer should be big
// enough to store "3.16.0a0 " string.
static char static_version[20];
static char *heap_version = NULL;

void _Py_InitVersion(void)

PyStatus
_Py_GetVersion_Init(void)
{
if (initialized) {
return;
return _PyStatus_OK();
}
initialized = 1;

#ifdef Py_GIL_DISABLED
const char *buildinfo_format = "%.80s free-threading build (%.80s) %.80s";
const char *format = "%s free-threading build (%s) %s";
size_t format_len = strlen(" free-threading build () ");
#else
const char *buildinfo_format = "%.80s (%.80s) %.80s";
const char *format = "%s (%s) %s";
size_t format_len = strlen(" () ");
#endif
PyOS_snprintf(version, sizeof(version), buildinfo_format,
PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler());
const char *version_str = PY_VERSION;
const char *buildinfo = Py_GetBuildInfo();
const char *compiler = Py_GetCompiler();
// +1 for the trailing NUL byte
size_t len = (format_len + strlen(version_str) + strlen(buildinfo)
+ strlen(compiler) + 1);

// Always format the static version
PyOS_snprintf(static_version, sizeof(static_version), format,
version_str, buildinfo, compiler);

heap_version = malloc(len);
if (heap_version == NULL) {
// If malloc() failed, don't set initialized to 1, so next
// Py_GetVersion() will try again to allocate memory.
return _PyStatus_NO_MEMORY();
}

PyOS_snprintf(heap_version, len, format,
version_str, buildinfo, compiler);
initialized = 1;
return _PyStatus_OK();
}

void
_Py_GetVersion_Fini(void)
{
if (heap_version) {
free(heap_version);
heap_version = NULL;
}
}

const char *
Py_GetVersion(void)
{
_Py_InitVersion();
return version;
PyStatus status = _Py_GetVersion_Init();
// Ignore error: Py_GetVersion() API cannot report error
(void)status;

if (heap_version) {
return heap_version;
}
else {
return static_version;
}
}

// Export the Python hex version as a constant.
Expand Down
6 changes: 5 additions & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,11 @@ pycore_init_runtime(_PyRuntimeState *runtime,
*/
_PyRuntimeState_SetFinalizing(runtime, NULL);

_Py_InitVersion();
status = _Py_GetVersion_Init();
if (_PyStatus_EXCEPTION(status)) {
return status;
}

_Py_DumpTraceback_Init();

status = _Py_HashRandomization_Init(config);
Expand Down
3 changes: 2 additions & 1 deletion Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ Objects/unicodeobject.c _init_global_state initialized -
Modules/getbuildinfo.c - buildinfo -
Modules/getbuildinfo.c - initialized -
Python/getversion.c - initialized -
Python/getversion.c - version -
Python/getversion.c - static_version -
Python/getversion.c - heap_version -

## public C-API - set during first init
Python/bootstrap_hash.c - _Py_HashSecret_Initialized -
Expand Down
Loading