]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-95991: Add some infrastructure for testing Limited API in _testcapi (GH-95992)
authorPetr Viktorin <encukou@gmail.com>
Wed, 17 Aug 2022 11:48:43 +0000 (13:48 +0200)
committerGitHub <noreply@github.com>
Wed, 17 Aug 2022 11:48:43 +0000 (13:48 +0200)
- Limited API needs to be enabled per source file
- Some builds don't support Limited API, so Limited API tests must be skipped on those builds
  (currently this is `Py_TRACE_REFS`, but that may change.)
- `Py_LIMITED_API` must be defined before `<Python.h>` is included.

This puts the hoop-jumping in `testcapi/parts.h`, so individual
test files can be relatively simple. (Currently that's only
`vectorcall_limited.c`, imagine more.)

Doc/library/test.rst
Lib/test/support/__init__.py
Lib/test/test_call.py
Modules/_testcapi/parts.h
Modules/_testcapi/vectorcall_limited.c
Modules/_testcapimodule.c
PCbuild/_testcapi.vcxproj

index e255952d4570ef09211ca2d7fc25d98a221a717c..f3bc7e7560a66c64f891ca46adac10db2ec4166b 100644 (file)
@@ -794,6 +794,12 @@ The :mod:`test.support` module defines the following functions:
    Decorator for only running the test if :data:`HAVE_DOCSTRINGS`.
 
 
+.. decorator:: requires_limited_api
+
+   Decorator for only running the test if :ref:`Limited C API <stable>`
+   is available.
+
+
 .. decorator:: cpython_only
 
    Decorator for tests only applicable to CPython.
index c51a1f26f29a6b246ba06ba8b4b3126a43b647ac..2409fb05d728917ab8dd9b955fea71afd2264e06 100644 (file)
@@ -46,6 +46,7 @@ __all__ = [
     "anticipate_failure", "load_package_tests", "detect_api_mismatch",
     "check__all__", "skip_if_buggy_ucrt_strfptime",
     "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer",
+    "requires_limited_api",
     # sys
     "is_jython", "is_android", "is_emscripten", "is_wasi",
     "check_impl_detail", "unix_shell", "setswitchinterval",
@@ -1069,6 +1070,15 @@ def refcount_test(test):
     return no_tracing(cpython_only(test))
 
 
+def requires_limited_api(test):
+    try:
+        import _testcapi
+    except ImportError:
+        return unittest.skip('needs _testcapi module')(test)
+    return unittest.skipUnless(
+        _testcapi.LIMITED_API_AVAILABLE, 'needs Limited API support')(test)
+
+
 def _filter_suite(suite, pred):
     """Recursively filter test cases in a suite based on a predicate."""
     newtests = []
index 131b45e6caaab34dd2484faa29344005590372f1..c00de27b265d2734d403212089bd03dd15071cdd 100644 (file)
@@ -1,5 +1,5 @@
 import unittest
-from test.support import cpython_only
+from test.support import cpython_only, requires_limited_api
 try:
     import _testcapi
 except ImportError:
@@ -760,9 +760,7 @@ class TestPEP590(unittest.TestCase):
                 self.assertEqual(expected, meth(*args1, **kwargs))
                 self.assertEqual(expected, wrapped(*args, **kwargs))
 
-    @unittest.skipIf(
-        hasattr(sys, 'getobjects'),
-        "Limited API is not compatible with Py_TRACE_REFS")
+    @requires_limited_api
     def test_vectorcall_limited(self):
         from _testcapi import pyobject_vectorcall
         obj = _testcapi.LimitedVectorCallClass()
index a76ddd93c0efb90620ee57c8222734729d84d2ed..304e5922c0d50b32d1d1712cd6e417d01f5cf5d0 100644 (file)
@@ -1,9 +1,36 @@
-#include "Python.h"
+#ifndef Py_TESTCAPI_PARTS_H
+#define Py_TESTCAPI_PARTS_H
+
+#include "pyconfig.h"  // for Py_TRACE_REFS
+
+// Figure out if Limited API is available for this build. If it isn't we won't
+// build tests for it.
+// Currently, only Py_TRACE_REFS disables Limited API.
+#ifdef Py_TRACE_REFS
+#undef LIMITED_API_AVAILABLE
+#else
+#define LIMITED_API_AVAILABLE 1
+#endif
 
-/* Always enable assertions */
+// Always enable assertions
 #undef NDEBUG
 
+#if !defined(LIMITED_API_AVAILABLE) && defined(Py_LIMITED_API)
+// Limited API being unavailable means that with Py_LIMITED_API defined
+// we can't even include Python.h.
+// Do nothing; the .c file that defined Py_LIMITED_API should also do nothing.
+
+#else
+
+#include "Python.h"
+
 int _PyTestCapi_Init_Vectorcall(PyObject *module);
-int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
 int _PyTestCapi_Init_Heaptype(PyObject *module);
 int _PyTestCapi_Init_Unicode(PyObject *module);
+
+#ifdef LIMITED_API_AVAILABLE
+int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
+#endif // LIMITED_API_AVAILABLE
+
+#endif
+#endif // Py_TESTCAPI_PARTS_H
index c5184318e292e6cadd8d02520b5b4413333323b0..ee57af84b1bb5fb33e2988a72c70d2a9def50338 100644 (file)
@@ -1,18 +1,8 @@
-#include "pyconfig.h"  // Py_TRACE_REFS
-
-#ifdef Py_TRACE_REFS
-
-// Py_TRACE_REFS is incompatible with Limited API
+#define Py_LIMITED_API 0x030c0000 // 3.12
 #include "parts.h"
-int
-_PyTestCapi_Init_VectorcallLimited(PyObject *m) {
-    return 0;
-}
 
-#else
+#ifdef LIMITED_API_AVAILABLE
 
-#define Py_LIMITED_API 0x030c0000 // 3.12
-#include "parts.h"
 #include "structmember.h"         // PyMemberDef
 
 /* Test Vectorcall in the limited API */
@@ -89,4 +79,4 @@ _PyTestCapi_Init_VectorcallLimited(PyObject *m) {
     return 0;
 }
 
-#endif // Py_TRACE_REFS
+#endif // LIMITED_API_AVAILABLE
index 8d9a0c15b1b0234331cf5813bc4889a3145db20e..2d4c73cfe97097bb13f0c7007216a0feb6824ca3 100644 (file)
@@ -6544,9 +6544,6 @@ PyInit__testcapi(void)
     if (_PyTestCapi_Init_Vectorcall(m) < 0) {
         return NULL;
     }
-    if (_PyTestCapi_Init_VectorcallLimited(m) < 0) {
-        return NULL;
-    }
     if (_PyTestCapi_Init_Heaptype(m) < 0) {
         return NULL;
     }
@@ -6554,6 +6551,15 @@ PyInit__testcapi(void)
         return NULL;
     }
 
+#ifndef LIMITED_API_AVAILABLE
+    PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False);
+#else
+    PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_True);
+    if (_PyTestCapi_Init_VectorcallLimited(m) < 0) {
+        return NULL;
+    }
+#endif
+
     PyState_AddModule(m, &_testcapimodule);
     return m;
 }
index 23bb5ec85274aefa00cb3b1a520778b20c36a1f0..b7d40c8cdc30eb332f3e9f637f9971b8b30707d1 100644 (file)
       <Project>{cf7ac3d1-e2df-41d2-bea6-1e2556cdea26}</Project>
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
     </ProjectReference>
+    <ProjectReference Include="python3dll.vcxproj">
+      <Project>{885d4898-d08d-4091-9c40-c700cfe3fc5a}</Project>
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">