From c394c9225087a4a624cdb9c62149dc7cca8c315f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 12 Feb 2026 15:57:55 +0100 Subject: [PATCH 1/3] Tests C11, C23, C++17 and C++20 --- tests/setup.py | 57 +++++++++++++++++------------ tests/test_pythoncapi_compat.py | 53 +++++++++++++++------------ tests/test_pythoncapi_compat_cext.c | 14 ++++++- 3 files changed, 76 insertions(+), 48 deletions(-) diff --git a/tests/setup.py b/tests/setup.py index 33a0e66..356c907 100755 --- a/tests/setup.py +++ b/tests/setup.py @@ -40,11 +40,7 @@ '-Wformat-nonliteral', '-Wformat-security', )) - CFLAGS = COMMON_FLAGS + [ - # Use C99 for pythoncapi_compat.c which initializes PyModuleDef with a - # mixture of designated and non-designated initializers - '-std=c99', - ] + CFLAGS = COMMON_FLAGS else: # C compiler flags for MSVC COMMON_FLAGS.extend(( @@ -54,6 +50,27 @@ CFLAGS = list(COMMON_FLAGS) CXXFLAGS = list(COMMON_FLAGS) +if not MSVC: + C_VERSIONS = ('c99', 'c11', 'c23') +else: + # MSVC doesn't support /std:c99 flag + C_VERSIONS = ('c11', 'c23') + +if not MSVC: + CXX_VERSIONS = [ + ('test_pythoncapi_compat_cpp03ext', ['-std=c++03']), + ('test_pythoncapi_compat_cpp11ext', ['-std=c++11']), + ('test_pythoncapi_compat_cpp14ext', ['-std=c++14']), + ('test_pythoncapi_compat_cpp17ext', ['-std=c++17']), + ('test_pythoncapi_compat_cpp20ext', ['-std=c++20']), + ] +else: + # MSVC doesn't support /std:c++11 + CXX_VERSIONS = [ + ('test_pythoncapi_compat_cppext', None), + ('test_pythoncapi_compat_cpp14ext', ['/std:c++14', '/Zc:__cplusplus']), + ] + def main(): # gh-105776: When "gcc -std=11" is used as the C++ compiler, -std=c11 @@ -75,27 +92,21 @@ def main(): os.environ['CC'] = cmd # C extension - c_ext = Extension( - 'test_pythoncapi_compat_cext', - sources=['test_pythoncapi_compat_cext.c'], - extra_compile_args=CFLAGS) - extensions = [c_ext] + extensions = [] + for std in C_VERSIONS: + if not MSVC: + cflags = CFLAGS + ['-std=%s' % std] + else: + cflags = CFLAGS + ['/std:%s' % std] + c_ext = Extension( + 'test_pythoncapi_compat_cext_%s' % std, + sources=['test_pythoncapi_compat_cext.c'], + extra_compile_args=cflags) + extensions.append(c_ext) if TEST_CXX: # C++ extension - - # MSVC has /std flag but doesn't support /std:c++11 - if not MSVC: - versions = [ - ('test_pythoncapi_compat_cpp03ext', ['-std=c++03']), - ('test_pythoncapi_compat_cpp11ext', ['-std=c++11']), - ] - else: - versions = [ - ('test_pythoncapi_compat_cppext', None), - ('test_pythoncapi_compat_cpp14ext', ['/std:c++14', '/Zc:__cplusplus']), - ] - for name, std_flags in versions: + for name, std_flags in CXX_VERSIONS: flags = list(CXXFLAGS) if std_flags is not None: flags.extend(std_flags) diff --git a/tests/test_pythoncapi_compat.py b/tests/test_pythoncapi_compat.py index 47ffd9b..58ea62f 100644 --- a/tests/test_pythoncapi_compat.py +++ b/tests/test_pythoncapi_compat.py @@ -32,19 +32,31 @@ # Windows uses MSVC compiler MSVC = (os.name == "nt") -TESTS = [ - ("test_pythoncapi_compat_cext", "C"), -] +# C++ is only supported on Python 3.6 and newer +TEST_CXX = (sys.version_info >= (3, 6)) + if not MSVC: - TESTS.extend(( + C_TESTS = [ + ("test_pythoncapi_compat_cext_c99", "C99"), + ("test_pythoncapi_compat_cext_c11", "C11"), + ("test_pythoncapi_compat_cext_c23", "C23"), + ] + CXX_TESTS = [ ("test_pythoncapi_compat_cpp03ext", "C++03"), ("test_pythoncapi_compat_cpp11ext", "C++11"), - )) + ("test_pythoncapi_compat_cpp14ext", "C++14"), + ("test_pythoncapi_compat_cpp17ext", "C++17"), + ("test_pythoncapi_compat_cpp20ext", "C++20"), + ] else: - TESTS.extend(( + C_TESTS = [ + ("test_pythoncapi_compat_cext_c11", "C11"), + ("test_pythoncapi_compat_cext_c23", "C23"), + ] + CXX_TESTS = [ ("test_pythoncapi_compat_cppext", "C++"), ("test_pythoncapi_compat_cpp14ext", "C++14"), - )) + ] VERBOSE = False @@ -84,9 +96,12 @@ def import_tests(module_name): if not pythonpath: raise Exception("Failed to find the build directory") - sys.path.append(pythonpath) - - return __import__(module_name) + old_sys_path = list(sys.path) + try: + sys.path.append(pythonpath) + return __import__(module_name) + finally: + sys.path[:] = old_sys_path def _run_tests(tests, verbose): @@ -155,18 +170,7 @@ def run_tests(module_name, lang): title = "Test %s (%s)" % (module_name, lang) display_title(title) - try: - testmod = import_tests(module_name) - except ImportError: - # The C extension must always be available - if lang == "C": - raise - - if VERBOSE: - print("%s: skip %s, missing %s extension" - % (python_version(), lang, module_name)) - print() - return + testmod = import_tests(module_name) if VERBOSE: empty_line = False @@ -226,7 +230,10 @@ def main(): build_ext() - for module_name, lang in TESTS: + tests = C_TESTS + if TEST_CXX: + tests += CXX_TESTS + for module_name, lang in tests: run_tests(module_name, lang) diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index 132708d..19db02e 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -16,14 +16,24 @@ # define PYTHON3 1 #endif -#if defined(__cplusplus) && __cplusplus >= 201402 +#if defined(__cplusplus) && __cplusplus >= 202002L +# define MODULE_NAME test_pythoncapi_compat_cpp20ext +#elif defined(__cplusplus) && __cplusplus >= 201703L +# define MODULE_NAME test_pythoncapi_compat_cpp17ext +#elif defined(__cplusplus) && __cplusplus >= 201402L # define MODULE_NAME test_pythoncapi_compat_cpp14ext -#elif defined(__cplusplus) && __cplusplus >= 201103 +#elif defined(__cplusplus) && __cplusplus >= 201103L # define MODULE_NAME test_pythoncapi_compat_cpp11ext #elif defined(__cplusplus) && !defined(_MSC_VER) # define MODULE_NAME test_pythoncapi_compat_cpp03ext #elif defined(__cplusplus) # define MODULE_NAME test_pythoncapi_compat_cppext +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define MODULE_NAME test_pythoncapi_compat_cext_c23 +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define MODULE_NAME test_pythoncapi_compat_cext_c11 +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define MODULE_NAME test_pythoncapi_compat_cext_c99 #else # define MODULE_NAME test_pythoncapi_compat_cext #endif From 36276518c85d4f121ecd9d5a1e24821e91b5dfc2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 12 Feb 2026 16:26:52 +0100 Subject: [PATCH 2/3] Remove C23 --- tests/setup.py | 4 ++-- tests/test_pythoncapi_compat.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/setup.py b/tests/setup.py index 356c907..e394bce 100755 --- a/tests/setup.py +++ b/tests/setup.py @@ -51,10 +51,10 @@ CXXFLAGS = list(COMMON_FLAGS) if not MSVC: - C_VERSIONS = ('c99', 'c11', 'c23') + C_VERSIONS = ('c99', 'c11') else: # MSVC doesn't support /std:c99 flag - C_VERSIONS = ('c11', 'c23') + C_VERSIONS = ('c11',) if not MSVC: CXX_VERSIONS = [ diff --git a/tests/test_pythoncapi_compat.py b/tests/test_pythoncapi_compat.py index 58ea62f..f0dec39 100644 --- a/tests/test_pythoncapi_compat.py +++ b/tests/test_pythoncapi_compat.py @@ -39,7 +39,6 @@ C_TESTS = [ ("test_pythoncapi_compat_cext_c99", "C99"), ("test_pythoncapi_compat_cext_c11", "C11"), - ("test_pythoncapi_compat_cext_c23", "C23"), ] CXX_TESTS = [ ("test_pythoncapi_compat_cpp03ext", "C++03"), @@ -51,7 +50,6 @@ else: C_TESTS = [ ("test_pythoncapi_compat_cext_c11", "C11"), - ("test_pythoncapi_compat_cext_c23", "C23"), ] CXX_TESTS = [ ("test_pythoncapi_compat_cppext", "C++"), From 251f637a99e29dbafdbb6046605acdcc7aa17731 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 12 Feb 2026 16:31:46 +0100 Subject: [PATCH 3/3] copy C_TESTS --- tests/test_pythoncapi_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_pythoncapi_compat.py b/tests/test_pythoncapi_compat.py index f0dec39..93005cd 100644 --- a/tests/test_pythoncapi_compat.py +++ b/tests/test_pythoncapi_compat.py @@ -228,7 +228,7 @@ def main(): build_ext() - tests = C_TESTS + tests = list(C_TESTS) if TEST_CXX: tests += CXX_TESTS for module_name, lang in tests: