Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-95991: Add some infrastructure for testing Limited API in _testcapi #95992

Merged
merged 5 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Doc/library/test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 10 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"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",
Expand Down Expand Up @@ -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 = []
Expand Down
6 changes: 2 additions & 4 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -760,9 +760,7 @@ def __call__(self, *args):
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()
Expand Down
33 changes: 30 additions & 3 deletions Modules/_testcapi/parts.h
Original file line number Diff line number Diff line change
@@ -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
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
#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
16 changes: 3 additions & 13 deletions Modules/_testcapi/vectorcall_limited.c
Original file line number Diff line number Diff line change
@@ -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 */
Expand Down Expand Up @@ -89,4 +79,4 @@ _PyTestCapi_Init_VectorcallLimited(PyObject *m) {
return 0;
}

#endif // Py_TRACE_REFS
#endif // LIMITED_API_AVAILABLE
12 changes: 9 additions & 3 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -6544,16 +6544,22 @@ 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;
}
if (_PyTestCapi_Init_Unicode(m) < 0) {
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;
}
Expand Down
4 changes: 4 additions & 0 deletions PCbuild/_testcapi.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@
<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">
Expand Down