diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index f8cae78b909a00..f7b4cdcda826c0 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1078,6 +1078,14 @@ sys.monitoring * Two new events are added: :monitoring-event:`BRANCH_LEFT` and :monitoring-event:`BRANCH_RIGHT`. The ``BRANCH`` event is deprecated. + +sysconfig +--------- + +* Add ``ABIFLAGS`` key to :func:`sysconfig.get_config_vars` on Windows. + (Contributed by Xuehai Pan in :gh:`131799`.) + + threading --------- @@ -1085,6 +1093,7 @@ threading to :attr:`threading.Thread.name`. (Contributed by Victor Stinner in :gh:`59705`.) + tkinter ------- diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py index 18e6b8d25e5b56..dad715eb087387 100644 --- a/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py @@ -401,9 +401,20 @@ def _init_non_posix(vars): vars['BINLIBDEST'] = get_path('platstdlib') vars['INCLUDEPY'] = get_path('include') - # Add EXT_SUFFIX, SOABI, and Py_GIL_DISABLED + # 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 + # empty string. + vars['ABIFLAGS'] = ''.join( + ( + 't' if vars['Py_GIL_DISABLED'] else '', + '_d' if vars['Py_DEBUG'] else '', + ), + ) + vars['LIBDIR'] = _safe_realpath(os.path.join(get_config_var('installed_base'), 'libs')) if hasattr(sys, 'dllhandle'): dllhandle = _winapi.GetModuleFileName(sys.dllhandle) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index f1cfff68ad6105..44e6bdf5f00712 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -724,6 +724,8 @@ def test_attributes(self): self.assertIn(sys.float_repr_style, ('short', 'legacy')) if not sys.platform.startswith('win'): self.assertIsInstance(sys.abiflags, str) + else: + self.assertFalse(hasattr(sys, 'abiflags')) def test_thread_info(self): info = sys.thread_info diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index cc11eade2e3426..53e55383bf9c72 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -9,6 +9,7 @@ import textwrap from copy import copy +from test import support from test.support import ( captured_stdout, is_android, @@ -455,20 +456,20 @@ def test_library(self): library = sysconfig.get_config_var('LIBRARY') ldlibrary = sysconfig.get_config_var('LDLIBRARY') major, minor = sys.version_info[:2] - if sys.platform == 'win32': - self.assertTrue(library.startswith(f'python{major}{minor}')) - self.assertTrue(library.endswith('.dll')) + abiflags = sysconfig.get_config_var('ABIFLAGS') + if sys.platform.startswith('win'): + self.assertEqual(library, f'python{major}{minor}{abiflags}.dll') self.assertEqual(library, ldlibrary) elif is_apple_mobile: framework = sysconfig.get_config_var('PYTHONFRAMEWORK') self.assertEqual(ldlibrary, f"{framework}.framework/{framework}") else: - self.assertTrue(library.startswith(f'libpython{major}.{minor}')) - self.assertTrue(library.endswith('.a')) + self.assertStartsWith(library, f'libpython{major}.{minor}') + self.assertEndsWith(library, '.a') if sys.platform == 'darwin' and sys._framework: self.skipTest('gh-110824: skip LDLIBRARY test for framework build') else: - self.assertTrue(ldlibrary.startswith(f'libpython{major}.{minor}')) + self.assertStartsWith(ldlibrary, f'libpython{major}.{minor}') @unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX") @requires_subprocess() @@ -592,6 +593,63 @@ def test_osx_ext_suffix(self): suffix = sysconfig.get_config_var('EXT_SUFFIX') self.assertTrue(suffix.endswith('-darwin.so'), suffix) + def test_always_set_py_debug(self): + self.assertIn('Py_DEBUG', sysconfig.get_config_vars()) + Py_DEBUG = sysconfig.get_config_var('Py_DEBUG') + self.assertIn(Py_DEBUG, (0, 1)) + self.assertEqual(Py_DEBUG, support.Py_DEBUG) + + def test_always_set_py_gil_disabled(self): + self.assertIn('Py_GIL_DISABLED', sysconfig.get_config_vars()) + Py_GIL_DISABLED = sysconfig.get_config_var('Py_GIL_DISABLED') + self.assertIn(Py_GIL_DISABLED, (0, 1)) + self.assertEqual(Py_GIL_DISABLED, support.Py_GIL_DISABLED) + + def test_abiflags(self): + # If this test fails on some platforms, maintainers should update the + # test to make it pass, rather than changing the definition of ABIFLAGS. + self.assertIn('abiflags', sysconfig.get_config_vars()) + self.assertIn('ABIFLAGS', sysconfig.get_config_vars()) + abiflags = sysconfig.get_config_var('abiflags') + ABIFLAGS = sysconfig.get_config_var('ABIFLAGS') + self.assertIsInstance(abiflags, str) + self.assertIsInstance(ABIFLAGS, str) + self.assertIn(abiflags, ABIFLAGS) + if os.name == 'nt': + self.assertEqual(abiflags, '') + + if not sys.platform.startswith('win'): + valid_abiflags = ('', 't', 'd', 'td') + else: + # Windows uses '_d' rather than 'd'; see also test_abi_debug below + valid_abiflags = ('', 't', '_d', 't_d') + + self.assertIn(ABIFLAGS, valid_abiflags) + + def test_abi_debug(self): + ABIFLAGS = sysconfig.get_config_var('ABIFLAGS') + if support.Py_DEBUG: + self.assertIn('d', ABIFLAGS) + else: + self.assertNotIn('d', ABIFLAGS) + + # The 'd' flag should always be the last one on Windows. + # On Windows, the debug flag is used differently with a underscore prefix. + # For example, `python{X}.{Y}td` on Unix and `python{X}.{Y}t_d.exe` on Windows. + if support.Py_DEBUG and sys.platform.startswith('win'): + self.assertEndsWith(ABIFLAGS, '_d') + + def test_abi_thread(self): + abi_thread = sysconfig.get_config_var('abi_thread') + ABIFLAGS = sysconfig.get_config_var('ABIFLAGS') + self.assertIsInstance(abi_thread, str) + if support.Py_GIL_DISABLED: + self.assertEqual(abi_thread, 't') + self.assertIn('t', ABIFLAGS) + else: + self.assertEqual(abi_thread, '') + self.assertNotIn('t', ABIFLAGS) + @requires_subprocess() def test_makefile_overwrites_config_vars(self): script = textwrap.dedent(""" diff --git a/Misc/ACKS b/Misc/ACKS index 814a530f7b79d4..c3e8530d5b36c2 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1402,6 +1402,7 @@ Todd R. Palmer Juan David Ibáñez Palomar Nicola Palumbo Jan Palus +Xuehai Pan Yongzhi Pan Martin Panter Mathias Panzenböck diff --git a/Misc/NEWS.d/next/Windows/2025-03-27-16-22-58.gh-issue-127405.aASs2Z.rst b/Misc/NEWS.d/next/Windows/2025-03-27-16-22-58.gh-issue-127405.aASs2Z.rst new file mode 100644 index 00000000000000..a6d5985ff4c7b8 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2025-03-27-16-22-58.gh-issue-127405.aASs2Z.rst @@ -0,0 +1 @@ +Add ``ABIFLAGS`` to :func:`sysconfig.get_config_vars` on Windows. Patch by Xuehai Pan. diff --git a/Modules/_sysconfig.c b/Modules/_sysconfig.c index c50c5cfabc2f1f..e2d141b5910b6d 100644 --- a/Modules/_sysconfig.c +++ b/Modules/_sysconfig.c @@ -67,6 +67,16 @@ _sysconfig_config_vars_impl(PyObject *module) return NULL; } +#ifdef Py_DEBUG + PyObject *py_debug = _PyLong_GetOne(); +#else + PyObject *py_debug = _PyLong_GetZero(); +#endif + if (PyDict_SetItemString(config, "Py_DEBUG", py_debug) < 0) { + Py_DECREF(config); + return NULL; + } + return config; }