diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py index 6507a7b5b0f695..c2adbf7cd4ae4a 100644 --- a/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py @@ -1,5 +1,6 @@ """Access to Python's configuration information.""" +import _sysconfig import os import sys import threading @@ -172,9 +173,6 @@ def joinuser(*args): _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include', 'scripts', 'data') -_PY_VERSION = sys.version.split()[0] -_PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}' -_PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}' _BASE_PREFIX = os.path.normpath(sys.base_prefix) _BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) # Mutex guarding initialization of _CONFIG_VARS. @@ -323,7 +321,8 @@ def get_makefile_filename(): return os.path.join(_PROJECT_BASE, "Makefile") if hasattr(sys, 'abiflags'): - config_dir_name = f'config-{_PY_VERSION_SHORT}{sys.abiflags}' + py_version_short = f'{sys.version_info[0]}.{sys.version_info[1]}' + config_dir_name = f'config-{py_version_short}{sys.abiflags}' else: config_dir_name = 'config' @@ -385,14 +384,10 @@ def _init_non_posix(vars): """Initialize the module as appropriate for NT""" # set basic install directories import _winapi - import _sysconfig vars['LIBDEST'] = get_path('stdlib') vars['BINLIBDEST'] = get_path('platstdlib') vars['INCLUDEPY'] = get_path('include') - # Add EXT_SUFFIX, SOABI, Py_DEBUG, and Py_GIL_DISABLED - vars.update(_sysconfig.config_vars()) - # NOTE: ABIFLAGS is only an emulated value. It is not present during build # on Windows. sys.abiflags is absent on Windows and vars['abiflags'] # is already widely used to calculate paths, so it should remain an @@ -410,7 +405,7 @@ def _init_non_posix(vars): vars['LIBRARY'] = os.path.basename(_safe_realpath(dllhandle)) vars['LDLIBRARY'] = vars['LIBRARY'] vars['EXE'] = '.exe' - vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT + vars['VERSION'] = vars['py_version_nodot'] vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable)) # No standard path exists on Windows for this, but we'll check # whether someone is imitating a POSIX-like layout @@ -505,6 +500,10 @@ def _init_config_vars(): global _CONFIG_VARS _CONFIG_VARS = {} + # Add py_version, Py_DEBUG, and Py_GIL_DISABLED. + # On Windows, add also EXT_SUFFIX and SOABI. + _CONFIG_VARS.update(_sysconfig.config_vars()) + prefix = os.path.normpath(sys.prefix) exec_prefix = os.path.normpath(sys.exec_prefix) base_prefix = _BASE_PREFIX @@ -530,9 +529,6 @@ def _init_config_vars(): # Distutils. _CONFIG_VARS['prefix'] = prefix _CONFIG_VARS['exec_prefix'] = exec_prefix - _CONFIG_VARS['py_version'] = _PY_VERSION - _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT - _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT _CONFIG_VARS['installed_base'] = base_prefix _CONFIG_VARS['base'] = prefix _CONFIG_VARS['installed_platbase'] = base_exec_prefix @@ -665,7 +661,6 @@ def get_platform(): For other non-POSIX platforms, currently just returns :data:`sys.platform`.""" if os.name == 'nt': - import _sysconfig platform = _sysconfig.get_platform() if platform: return platform @@ -740,11 +735,11 @@ def get_platform(): def get_python_version(): - return _PY_VERSION_SHORT + return get_config_var('py_version_short') def _get_python_version_abi(): - return _PY_VERSION_SHORT + get_config_var("abi_thread") + return get_config_var('py_version_short') + get_config_var('abi_thread') def expand_makefile_vars(s, vars): diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index e43f91eb9238f9..16a43848602f85 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -741,6 +741,27 @@ def test_sysconfig_config_vars_no_prefix_cache(self): self.assertEqual(config_vars['exec_prefix'], sys.exec_prefix) self.assertEqual(config_vars['platbase'], sys.exec_prefix) + def test_py_version(self): + # Test py_version + config_vars = sysconfig.get_config_vars() + self.assertIsInstance(config_vars['py_version'], str) + ver = sys.version_info + version = f'{ver.major}.{ver.minor}.{ver.micro}' + # py_version can be longer such as "3.15.0a7+" instead of "3.15.0" + self.assertStartsWith(config_vars['py_version'], version) + + # Test py_version_short and get_python_version() + self.assertIsInstance(config_vars['py_version_short'], str) + self.assertEqual(config_vars['py_version_short'], + f'{ver.major}.{ver.minor}') + self.assertEqual(sysconfig.get_python_version(), + config_vars['py_version_short']) + + # Test py_version_nodot + self.assertIsInstance(config_vars['py_version_nodot'], str) + self.assertEqual(config_vars['py_version_nodot'], + f'{ver.major}{ver.minor}') + class MakefileTests(unittest.TestCase): diff --git a/Modules/_sysconfig.c b/Modules/_sysconfig.c index bcb9d108174f43..a5574fd506c340 100644 --- a/Modules/_sysconfig.c +++ b/Modules/_sysconfig.c @@ -17,7 +17,13 @@ module _sysconfig #include "clinic/_sysconfig.c.h" -#ifdef MS_WINDOWS + +#define py_version_short() \ + (Py_STRINGIFY(PY_MAJOR_VERSION) "." Py_STRINGIFY(PY_MINOR_VERSION)) +#define py_version_nodot() \ + (Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION)) + + static int add_string_value(PyObject *dict, const char *key, const char *str_value) { @@ -29,7 +35,7 @@ add_string_value(PyObject *dict, const char *key, const char *str_value) Py_DECREF(value); return err; } -#endif + /*[clinic input] @permit_long_summary @@ -47,14 +53,23 @@ _sysconfig_config_vars_impl(PyObject *module) return NULL; } + // Python version + if (add_string_value(config, "py_version", PY_VERSION) < 0) { + goto error; + } + if (add_string_value(config, "py_version_short", py_version_short()) < 0) { + goto error; + } + if (add_string_value(config, "py_version_nodot", py_version_nodot()) < 0) { + goto error; + } + #ifdef MS_WINDOWS if (add_string_value(config, "EXT_SUFFIX", PYD_TAGGED_SUFFIX) < 0) { - Py_DECREF(config); - return NULL; + goto error; } if (add_string_value(config, "SOABI", PYD_SOABI) < 0) { - Py_DECREF(config); - return NULL; + goto error; } #endif @@ -64,8 +79,7 @@ _sysconfig_config_vars_impl(PyObject *module) PyObject *py_gil_disabled = _PyLong_GetZero(); #endif if (PyDict_SetItemString(config, "Py_GIL_DISABLED", py_gil_disabled) < 0) { - Py_DECREF(config); - return NULL; + goto error; } #ifdef Py_DEBUG @@ -74,11 +88,14 @@ _sysconfig_config_vars_impl(PyObject *module) PyObject *py_debug = _PyLong_GetZero(); #endif if (PyDict_SetItemString(config, "Py_DEBUG", py_debug) < 0) { - Py_DECREF(config); - return NULL; + goto error; } return config; + +error: + Py_DECREF(config); + return NULL; } #ifdef MS_WINDOWS