]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-135906: Test the internal C API in test_cext (#136247)
authorVictor Stinner <vstinner@python.org>
Fri, 11 Jul 2025 14:48:43 +0000 (16:48 +0200)
committerGitHub <noreply@github.com>
Fri, 11 Jul 2025 14:48:43 +0000 (16:48 +0200)
Remove duplicated definition: atexit_datacallbackfunc type
is already defined by Include/cpython/pylifecycle.h.

Include/internal/pycore_interp_structs.h
Lib/test/test_cext/__init__.py
Lib/test/test_cext/extension.c
Lib/test/test_cext/setup.py
Lib/test/test_cppext/__init__.py
Lib/test/test_cppext/extension.cpp
Lib/test/test_cppext/setup.py

index 8c3946cd462ce6214ac82ee698a30abb9745f68c..542a75617b4d3cf925ced6348332b5f39a6047c7 100644 (file)
@@ -130,8 +130,6 @@ struct _atexit_runtime_state {
 //###################
 // interpreter atexit
 
-typedef void (*atexit_datacallbackfunc)(void *);
-
 typedef struct atexit_callback {
     atexit_datacallbackfunc func;
     void *data;
index 46fde541494aa309a27a758312aa93dcad6cfb6b..93e7b2043d397a8a961611db1592c0f34edc5f43 100644 (file)
@@ -28,29 +28,13 @@ SETUP = os.path.join(os.path.dirname(__file__), 'setup.py')
 @support.requires_venv_with_pip()
 @support.requires_subprocess()
 @support.requires_resource('cpu')
-class TestExt(unittest.TestCase):
+class BaseTests:
+    TEST_INTERNAL_C_API = False
+
     # Default build with no options
     def test_build(self):
         self.check_build('_test_cext')
 
-    def test_build_c11(self):
-        self.check_build('_test_c11_cext', std='c11')
-
-    @unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c99")
-    def test_build_c99(self):
-        # In public docs, we say C API is compatible with C11. However,
-        # in practice we do maintain C99 compatibility in public headers.
-        # Please ask the C API WG before adding a new C11-only feature.
-        self.check_build('_test_c99_cext', std='c99')
-
-    @support.requires_gil_enabled('incompatible with Free Threading')
-    def test_build_limited(self):
-        self.check_build('_test_limited_cext', limited=True)
-
-    @support.requires_gil_enabled('broken for now with Free Threading')
-    def test_build_limited_c11(self):
-        self.check_build('_test_limited_c11_cext', limited=True, std='c11')
-
     def check_build(self, extension_name, std=None, limited=False):
         venv_dir = 'env'
         with support.setup_venv_with_pip_setuptools(venv_dir) as python_exe:
@@ -70,6 +54,7 @@ class TestExt(unittest.TestCase):
             if limited:
                 env['CPYTHON_TEST_LIMITED'] = '1'
             env['CPYTHON_TEST_EXT_NAME'] = extension_name
+            env['TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API))
             if support.verbose:
                 print('Run:', ' '.join(map(shlex.quote, cmd)))
                 subprocess.run(cmd, check=True, env=env)
@@ -110,5 +95,29 @@ class TestExt(unittest.TestCase):
         run_cmd('Import', cmd)
 
 
+class TestPublicCAPI(BaseTests, unittest.TestCase):
+    @support.requires_gil_enabled('incompatible with Free Threading')
+    def test_build_limited(self):
+        self.check_build('_test_limited_cext', limited=True)
+
+    @support.requires_gil_enabled('broken for now with Free Threading')
+    def test_build_limited_c11(self):
+        self.check_build('_test_limited_c11_cext', limited=True, std='c11')
+
+    def test_build_c11(self):
+        self.check_build('_test_c11_cext', std='c11')
+
+    @unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c99")
+    def test_build_c99(self):
+        # In public docs, we say C API is compatible with C11. However,
+        # in practice we do maintain C99 compatibility in public headers.
+        # Please ask the C API WG before adding a new C11-only feature.
+        self.check_build('_test_c99_cext', std='c99')
+
+
+class TestInteralCAPI(BaseTests, unittest.TestCase):
+    TEST_INTERNAL_C_API = True
+
+
 if __name__ == "__main__":
     unittest.main()
index 64629c5a6da8cd26d2208170ac1befd87920464a..4be2f24c60d44b5cb3d1eacad9ff086074f318bb 100644 (file)
@@ -1,11 +1,31 @@
 // gh-116869: Basic C test extension to check that the Python C API
 // does not emit C compiler warnings.
+//
+// Test also the internal C API if the TEST_INTERNAL_C_API macro is defined.
 
 // Always enable assertions
 #undef NDEBUG
 
+#ifdef TEST_INTERNAL_C_API
+#  define Py_BUILD_CORE_MODULE 1
+#endif
+
 #include "Python.h"
 
+#ifdef TEST_INTERNAL_C_API
+   // gh-135906: Check for compiler warnings in the internal C API.
+   // - Cython uses pycore_frame.h.
+   // - greenlet uses pycore_frame.h, pycore_interpframe_structs.h and
+   //   pycore_interpframe.h.
+#  include "internal/pycore_frame.h"
+#  include "internal/pycore_gc.h"
+#  include "internal/pycore_interp.h"
+#  include "internal/pycore_interpframe.h"
+#  include "internal/pycore_interpframe_structs.h"
+#  include "internal/pycore_object.h"
+#  include "internal/pycore_pystate.h"
+#endif
+
 #ifndef MODULE_NAME
 #  error "MODULE_NAME macro must be defined"
 #endif
index 1275282983f7ffd700f7cbbf423f9e172eb81f5d..587585e8086e926540ac2a0cb8bab0714b325356 100644 (file)
@@ -14,10 +14,15 @@ SOURCE = 'extension.c'
 
 if not support.MS_WINDOWS:
     # C compiler flags for GCC and clang
-    CFLAGS = [
+    BASE_CFLAGS = [
         # The purpose of test_cext extension is to check that building a C
         # extension using the Python C API does not emit C compiler warnings.
         '-Werror',
+    ]
+
+    # C compiler flags for GCC and clang
+    PUBLIC_CFLAGS = [
+        *BASE_CFLAGS,
 
         # gh-120593: Check the 'const' qualifier
         '-Wcast-qual',
@@ -26,27 +31,40 @@ if not support.MS_WINDOWS:
         '-pedantic-errors',
     ]
     if not support.Py_GIL_DISABLED:
-        CFLAGS.append(
+        PUBLIC_CFLAGS.append(
             # gh-116869: The Python C API must be compatible with building
             # with the -Werror=declaration-after-statement compiler flag.
             '-Werror=declaration-after-statement',
         )
+    INTERNAL_CFLAGS = [*BASE_CFLAGS]
 else:
     # MSVC compiler flags
-    CFLAGS = [
-        # Display warnings level 1 to 4
-        '/W4',
+    BASE_CFLAGS = [
         # Treat all compiler warnings as compiler errors
         '/WX',
     ]
+    PUBLIC_CFLAGS = [
+        *BASE_CFLAGS,
+        # Display warnings level 1 to 4
+        '/W4',
+    ]
+    INTERNAL_CFLAGS = [
+        *BASE_CFLAGS,
+        # Display warnings level 1 to 3
+        '/W3',
+    ]
 
 
 def main():
     std = os.environ.get("CPYTHON_TEST_STD", "")
     module_name = os.environ["CPYTHON_TEST_EXT_NAME"]
     limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", ""))
+    internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0")))
 
-    cflags = list(CFLAGS)
+    if not internal:
+        cflags = list(PUBLIC_CFLAGS)
+    else:
+        cflags = list(INTERNAL_CFLAGS)
     cflags.append(f'-DMODULE_NAME={module_name}')
 
     # Add -std=STD or /std:STD (MSVC) compiler flag
@@ -75,6 +93,9 @@ def main():
         version = sys.hexversion
         cflags.append(f'-DPy_LIMITED_API={version:#x}')
 
+    if internal:
+        cflags.append('-DTEST_INTERNAL_C_API=1')
+
     # On Windows, add PCbuild\amd64\ to include and library directories
     include_dirs = []
     library_dirs = []
index 2b7adac4bccd1513da9c3a927f1b90f1373488b5..2f54b3ccb35cc4ef8c3e3de80e7bcff06dc31201 100644 (file)
@@ -24,7 +24,7 @@ SETUP = os.path.join(os.path.dirname(__file__), 'setup.py')
 @support.requires_venv_with_pip()
 @support.requires_subprocess()
 @support.requires_resource('cpu')
-class TestCPPExt(unittest.TestCase):
+class BaseTests:
     def test_build(self):
         self.check_build('_testcppext')
 
@@ -34,10 +34,6 @@ class TestCPPExt(unittest.TestCase):
         # Please ask the C API WG before adding a new C++11-only feature.
         self.check_build('_testcpp03ext', std='c++03')
 
-    @support.requires_gil_enabled('incompatible with Free Threading')
-    def test_build_limited_cpp03(self):
-        self.check_build('_test_limited_cpp03ext', std='c++03', limited=True)
-
     @unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c++11")
     def test_build_cpp11(self):
         self.check_build('_testcpp11ext', std='c++11')
@@ -48,10 +44,6 @@ class TestCPPExt(unittest.TestCase):
     def test_build_cpp14(self):
         self.check_build('_testcpp14ext', std='c++14')
 
-    @support.requires_gil_enabled('incompatible with Free Threading')
-    def test_build_limited(self):
-        self.check_build('_testcppext_limited', limited=True)
-
     def check_build(self, extension_name, std=None, limited=False):
         venv_dir = 'env'
         with support.setup_venv_with_pip_setuptools(venv_dir) as python_exe:
@@ -111,5 +103,19 @@ class TestCPPExt(unittest.TestCase):
         run_cmd('Import', cmd)
 
 
+class TestPublicCAPI(BaseTests, unittest.TestCase):
+    @support.requires_gil_enabled('incompatible with Free Threading')
+    def test_build_limited_cpp03(self):
+        self.check_build('_test_limited_cpp03ext', std='c++03', limited=True)
+
+    @support.requires_gil_enabled('incompatible with Free Threading')
+    def test_build_limited(self):
+        self.check_build('_testcppext_limited', limited=True)
+
+
+class TestInteralCAPI(BaseTests, unittest.TestCase):
+    TEST_INTERNAL_C_API = True
+
+
 if __name__ == "__main__":
     unittest.main()
index 5b3571b295bec3bf897938975d479cf8c3092be3..1affa176088d578de9ef77ae02c7ddd0c979a495 100644 (file)
@@ -6,8 +6,17 @@
 // Always enable assertions
 #undef NDEBUG
 
+#ifdef TEST_INTERNAL_C_API
+#  define Py_BUILD_CORE 1
+#endif
+
 #include "Python.h"
 
+#ifdef TEST_INTERNAL_C_API
+   // gh-135906: Check for compiler warnings in the internal C API
+#  include "internal/pycore_frame.h"
+#endif
+
 #ifndef MODULE_NAME
 #  error "MODULE_NAME macro must be defined"
 #endif
index ea1ed64bf7ab0a22495cfd78f2054deaf0840f6f..98442b106b611335389cbb9ff4e2cfcda8327e8c 100644 (file)
@@ -47,6 +47,7 @@ def main():
     std = os.environ.get("CPYTHON_TEST_CPP_STD", "")
     module_name = os.environ["CPYTHON_TEST_EXT_NAME"]
     limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", ""))
+    internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0")))
 
     cppflags = list(CPPFLAGS)
     cppflags.append(f'-DMODULE_NAME={module_name}')
@@ -82,6 +83,9 @@ def main():
         version = sys.hexversion
         cppflags.append(f'-DPy_LIMITED_API={version:#x}')
 
+    if internal:
+        cppflags.append('-DTEST_INTERNAL_C_API=1')
+
     # On Windows, add PCbuild\amd64\ to include and library directories
     include_dirs = []
     library_dirs = []