]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-93649: Split vectorcall testing from _testcapimodule.c (GH-94549)
authorPetr Viktorin <encukou@gmail.com>
Fri, 8 Jul 2022 15:56:26 +0000 (17:56 +0200)
committerGitHub <noreply@github.com>
Fri, 8 Jul 2022 15:56:26 +0000 (08:56 -0700)
The `_testcapimodule.c` file is getting too large to work with effectively.
This PR lays out a general structure of how tests can be split up, with more splitting to come later if the structure is OK.

Vectorcall tests aren't the biggest issue -- it's just an area I want to work on next, so I'm starting here.
An issue specific to vectorcall tests is that it wasn't clear that e.g. `MethodDescriptor2` is related to testing vectorcall: the `/* Test PEP 590 */` section had an ambiguous end. Separate file should make things like this much clearer.
OTOH, for some pieces it might not be clear where they should be -- I left `meth_fastcall` with tests of the other calling conventions. IMO, even with the ambiguity it's still worth it to split the huge file up.

I'm not sure about the buildsystem changes, hopefully CI will tell me what's wrong.

@vstinner, @markshannon: Do you think this is a good idea?

Automerge-Triggered-By: GH:encukou
Makefile.pre.in
Modules/Setup.stdlib.in
Modules/_testcapi/README.txt [new file with mode: 0644]
Modules/_testcapi/parts.h [new file with mode: 0644]
Modules/_testcapi/vectorcall.c [new file with mode: 0644]
Modules/_testcapimodule.c
PCbuild/_testcapi.vcxproj
PCbuild/_testcapi.vcxproj.filters
setup.py

index 84c783327edd8dbdd7e4aef482e777a0873923e8..c17c3d6067d977c5e77fd225ca99a647e09adee0 100644 (file)
@@ -2568,7 +2568,7 @@ MODULE__SHA3_DEPS=$(srcdir)/Modules/_sha3/sha3.c $(srcdir)/Modules/_sha3/sha3.h
 MODULE__SHA512_DEPS=$(srcdir)/Modules/hashlib.h
 MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h
 MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c $(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c $(srcdir)/Modules/_ssl_data.h $(srcdir)/Modules/_ssl_data_111.h $(srcdir)/Modules/_ssl_data_300.h $(srcdir)/Modules/socketmodule.h
-MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/testcapi_long.h
+MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/testcapi_long.h Modules/_testcapi/parts.h $(srcdir)/Modules/_testcapi/vectorcall.c
 MODULE__SQLITE3_DEPS=$(srcdir)/Modules/_sqlite/connection.h $(srcdir)/Modules/_sqlite/cursor.h $(srcdir)/Modules/_sqlite/microprotocols.h $(srcdir)/Modules/_sqlite/module.h $(srcdir)/Modules/_sqlite/prepare_protocol.h $(srcdir)/Modules/_sqlite/row.h $(srcdir)/Modules/_sqlite/util.h
 
 # IF YOU PUT ANYTHING HERE IT WILL GO AWAY
index 7357aacd7267ae6a8987b7e32f44dfa031eb2062..581a5c7f979d11f95598bf0e99509dd577a36af6 100644 (file)
 @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
 @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
 @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
-@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c
+@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c
 
 # Some testing modules MUST be built as shared libraries.
 *shared*
diff --git a/Modules/_testcapi/README.txt b/Modules/_testcapi/README.txt
new file mode 100644 (file)
index 0000000..134b6ef
--- /dev/null
@@ -0,0 +1,3 @@
+Tests in this directory are compiled into the _testcapi extension.
+The main file for the extension is Modules/_testcapimodule.c, which
+calls `_PyTestCapi_Init_*` from these functions.
diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h
new file mode 100644 (file)
index 0000000..1111021
--- /dev/null
@@ -0,0 +1,3 @@
+#include "Python.h"
+
+PyAPI_FUNC(int) _PyTestCapi_Init_Vectorcall(PyObject *module);
diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c
new file mode 100644 (file)
index 0000000..9bc7029
--- /dev/null
@@ -0,0 +1,270 @@
+#include "parts.h"
+#include <stddef.h>  // offsetof
+
+
+/* Test PEP 590 - Vectorcall */
+
+static int
+fastcall_args(PyObject *args, PyObject ***stack, Py_ssize_t *nargs)
+{
+    if (args == Py_None) {
+        *stack = NULL;
+        *nargs = 0;
+    }
+    else if (PyTuple_Check(args)) {
+        *stack = ((PyTupleObject *)args)->ob_item;
+        *nargs = PyTuple_GET_SIZE(args);
+    }
+    else {
+        PyErr_SetString(PyExc_TypeError, "args must be None or a tuple");
+        return -1;
+    }
+    return 0;
+}
+
+
+static PyObject *
+test_pyobject_fastcall(PyObject *self, PyObject *args)
+{
+    PyObject *func, *func_args;
+    PyObject **stack;
+    Py_ssize_t nargs;
+
+    if (!PyArg_ParseTuple(args, "OO", &func, &func_args)) {
+        return NULL;
+    }
+
+    if (fastcall_args(func_args, &stack, &nargs) < 0) {
+        return NULL;
+    }
+    return _PyObject_FastCall(func, stack, nargs);
+}
+
+static PyObject *
+test_pyobject_fastcalldict(PyObject *self, PyObject *args)
+{
+    PyObject *func, *func_args, *kwargs;
+    PyObject **stack;
+    Py_ssize_t nargs;
+
+    if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwargs)) {
+        return NULL;
+    }
+
+    if (fastcall_args(func_args, &stack, &nargs) < 0) {
+        return NULL;
+    }
+
+    if (kwargs == Py_None) {
+        kwargs = NULL;
+    }
+    else if (!PyDict_Check(kwargs)) {
+        PyErr_SetString(PyExc_TypeError, "kwnames must be None or a dict");
+        return NULL;
+    }
+
+    return PyObject_VectorcallDict(func, stack, nargs, kwargs);
+}
+
+static PyObject *
+test_pyobject_vectorcall(PyObject *self, PyObject *args)
+{
+    PyObject *func, *func_args, *kwnames = NULL;
+    PyObject **stack;
+    Py_ssize_t nargs, nkw;
+
+    if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwnames)) {
+        return NULL;
+    }
+
+    if (fastcall_args(func_args, &stack, &nargs) < 0) {
+        return NULL;
+    }
+
+    if (kwnames == Py_None) {
+        kwnames = NULL;
+    }
+    else if (PyTuple_Check(kwnames)) {
+        nkw = PyTuple_GET_SIZE(kwnames);
+        if (nargs < nkw) {
+            PyErr_SetString(PyExc_ValueError, "kwnames longer than args");
+            return NULL;
+        }
+        nargs -= nkw;
+    }
+    else {
+        PyErr_SetString(PyExc_TypeError, "kwnames must be None or a tuple");
+        return NULL;
+    }
+    return PyObject_Vectorcall(func, stack, nargs, kwnames);
+}
+
+static PyObject *
+test_pyvectorcall_call(PyObject *self, PyObject *args)
+{
+    PyObject *func;
+    PyObject *argstuple;
+    PyObject *kwargs = NULL;
+
+    if (!PyArg_ParseTuple(args, "OO|O", &func, &argstuple, &kwargs)) {
+        return NULL;
+    }
+
+    if (!PyTuple_Check(argstuple)) {
+        PyErr_SetString(PyExc_TypeError, "args must be a tuple");
+        return NULL;
+    }
+    if (kwargs != NULL && !PyDict_Check(kwargs)) {
+        PyErr_SetString(PyExc_TypeError, "kwargs must be a dict");
+        return NULL;
+    }
+
+    return PyVectorcall_Call(func, argstuple, kwargs);
+}
+
+static PyMethodDef TestMethods[] = {
+    {"pyobject_fastcall", test_pyobject_fastcall, METH_VARARGS},
+    {"pyobject_fastcalldict", test_pyobject_fastcalldict, METH_VARARGS},
+    {"pyobject_vectorcall", test_pyobject_vectorcall, METH_VARARGS},
+    {"pyvectorcall_call", test_pyvectorcall_call, METH_VARARGS},
+    {NULL},
+};
+
+
+typedef struct {
+    PyObject_HEAD
+    vectorcallfunc vectorcall;
+} MethodDescriptorObject;
+
+static PyObject *
+MethodDescriptor_vectorcall(PyObject *callable, PyObject *const *args,
+                            size_t nargsf, PyObject *kwnames)
+{
+    /* True if using the vectorcall function in MethodDescriptorObject
+     * but False for MethodDescriptor2Object */
+    MethodDescriptorObject *md = (MethodDescriptorObject *)callable;
+    return PyBool_FromLong(md->vectorcall != NULL);
+}
+
+static PyObject *
+MethodDescriptor_new(PyTypeObject* type, PyObject* args, PyObject *kw)
+{
+    MethodDescriptorObject *op = (MethodDescriptorObject *)type->tp_alloc(type, 0);
+    op->vectorcall = MethodDescriptor_vectorcall;
+    return (PyObject *)op;
+}
+
+static PyObject *
+func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
+{
+    if (obj == Py_None || obj == NULL) {
+        Py_INCREF(func);
+        return func;
+    }
+    return PyMethod_New(func, obj);
+}
+
+static PyObject *
+nop_descr_get(PyObject *func, PyObject *obj, PyObject *type)
+{
+    Py_INCREF(func);
+    return func;
+}
+
+static PyObject *
+call_return_args(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    Py_INCREF(args);
+    return args;
+}
+
+static PyTypeObject MethodDescriptorBase_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "MethodDescriptorBase",
+    sizeof(MethodDescriptorObject),
+    .tp_new = MethodDescriptor_new,
+    .tp_call = PyVectorcall_Call,
+    .tp_vectorcall_offset = offsetof(MethodDescriptorObject, vectorcall),
+    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+                Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_HAVE_VECTORCALL,
+    .tp_descr_get = func_descr_get,
+};
+
+static PyTypeObject MethodDescriptorDerived_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "MethodDescriptorDerived",
+    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+};
+
+static PyTypeObject MethodDescriptorNopGet_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "MethodDescriptorNopGet",
+    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    .tp_call = call_return_args,
+    .tp_descr_get = nop_descr_get,
+};
+
+typedef struct {
+    MethodDescriptorObject base;
+    vectorcallfunc vectorcall;
+} MethodDescriptor2Object;
+
+static PyObject *
+MethodDescriptor2_new(PyTypeObject* type, PyObject* args, PyObject *kw)
+{
+    MethodDescriptor2Object *op = PyObject_New(MethodDescriptor2Object, type);
+    op->base.vectorcall = NULL;
+    op->vectorcall = MethodDescriptor_vectorcall;
+    return (PyObject *)op;
+}
+
+static PyTypeObject MethodDescriptor2_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "MethodDescriptor2",
+    sizeof(MethodDescriptor2Object),
+    .tp_new = MethodDescriptor2_new,
+    .tp_call = PyVectorcall_Call,
+    .tp_vectorcall_offset = offsetof(MethodDescriptor2Object, vectorcall),
+    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
+};
+
+
+int
+_PyTestCapi_Init_Vectorcall(PyObject *m) {
+    if (PyModule_AddFunctions(m, TestMethods) < 0) {
+        return -1;
+    }
+
+    if (PyType_Ready(&MethodDescriptorBase_Type) < 0) {
+        return -1;
+    }
+    if (PyModule_AddType(m, &MethodDescriptorBase_Type) < 0) {
+        return -1;
+    }
+
+    MethodDescriptorDerived_Type.tp_base = &MethodDescriptorBase_Type;
+    if (PyType_Ready(&MethodDescriptorDerived_Type) < 0) {
+        return -1;
+    }
+    if (PyModule_AddType(m, &MethodDescriptorDerived_Type) < 0) {
+        return -1;
+    }
+
+    MethodDescriptorNopGet_Type.tp_base = &MethodDescriptorBase_Type;
+    if (PyType_Ready(&MethodDescriptorNopGet_Type) < 0) {
+        return -1;
+    }
+    if (PyModule_AddType(m, &MethodDescriptorNopGet_Type) < 0) {
+        return -1;
+    }
+
+    MethodDescriptor2_Type.tp_base = &MethodDescriptorBase_Type;
+    if (PyType_Ready(&MethodDescriptor2_Type) < 0) {
+        return -1;
+    }
+    if (PyModule_AddType(m, &MethodDescriptor2_Type) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
index 7d88f4f51f8313541e5781b9bfa21c8ad660d2e4..436c701a7a3faf23d94217a032b249a64ee8badb 100644 (file)
 #  error "The public headers should not include <stdbool.h>, see bpo-46748"
 #endif
 
+// Several parts of this module are broken out into files in _testcapi/.
+// Include definitions from there.
+#include "_testcapi/parts.h"
+
 // Forward declarations
 static struct PyModuleDef _testcapimodule;
 static PyType_Spec HeapTypeNameType_Spec;
@@ -5299,128 +5303,6 @@ raise_SIGINT_then_send_None(PyObject *self, PyObject *args)
 }
 
 
-static int
-fastcall_args(PyObject *args, PyObject ***stack, Py_ssize_t *nargs)
-{
-    if (args == Py_None) {
-        *stack = NULL;
-        *nargs = 0;
-    }
-    else if (PyTuple_Check(args)) {
-        *stack = ((PyTupleObject *)args)->ob_item;
-        *nargs = PyTuple_GET_SIZE(args);
-    }
-    else {
-        PyErr_SetString(PyExc_TypeError, "args must be None or a tuple");
-        return -1;
-    }
-    return 0;
-}
-
-
-static PyObject *
-test_pyobject_fastcall(PyObject *self, PyObject *args)
-{
-    PyObject *func, *func_args;
-    PyObject **stack;
-    Py_ssize_t nargs;
-
-    if (!PyArg_ParseTuple(args, "OO", &func, &func_args)) {
-        return NULL;
-    }
-
-    if (fastcall_args(func_args, &stack, &nargs) < 0) {
-        return NULL;
-    }
-    return _PyObject_FastCall(func, stack, nargs);
-}
-
-
-static PyObject *
-test_pyobject_fastcalldict(PyObject *self, PyObject *args)
-{
-    PyObject *func, *func_args, *kwargs;
-    PyObject **stack;
-    Py_ssize_t nargs;
-
-    if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwargs)) {
-        return NULL;
-    }
-
-    if (fastcall_args(func_args, &stack, &nargs) < 0) {
-        return NULL;
-    }
-
-    if (kwargs == Py_None) {
-        kwargs = NULL;
-    }
-    else if (!PyDict_Check(kwargs)) {
-        PyErr_SetString(PyExc_TypeError, "kwnames must be None or a dict");
-        return NULL;
-    }
-
-    return PyObject_VectorcallDict(func, stack, nargs, kwargs);
-}
-
-
-static PyObject *
-test_pyobject_vectorcall(PyObject *self, PyObject *args)
-{
-    PyObject *func, *func_args, *kwnames = NULL;
-    PyObject **stack;
-    Py_ssize_t nargs, nkw;
-
-    if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwnames)) {
-        return NULL;
-    }
-
-    if (fastcall_args(func_args, &stack, &nargs) < 0) {
-        return NULL;
-    }
-
-    if (kwnames == Py_None) {
-        kwnames = NULL;
-    }
-    else if (PyTuple_Check(kwnames)) {
-        nkw = PyTuple_GET_SIZE(kwnames);
-        if (nargs < nkw) {
-            PyErr_SetString(PyExc_ValueError, "kwnames longer than args");
-            return NULL;
-        }
-        nargs -= nkw;
-    }
-    else {
-        PyErr_SetString(PyExc_TypeError, "kwnames must be None or a tuple");
-        return NULL;
-    }
-    return PyObject_Vectorcall(func, stack, nargs, kwnames);
-}
-
-
-static PyObject *
-test_pyvectorcall_call(PyObject *self, PyObject *args)
-{
-    PyObject *func;
-    PyObject *argstuple;
-    PyObject *kwargs = NULL;
-
-    if (!PyArg_ParseTuple(args, "OO|O", &func, &argstuple, &kwargs)) {
-        return NULL;
-    }
-
-    if (!PyTuple_Check(argstuple)) {
-        PyErr_SetString(PyExc_TypeError, "args must be a tuple");
-        return NULL;
-    }
-    if (kwargs != NULL && !PyDict_Check(kwargs)) {
-        PyErr_SetString(PyExc_TypeError, "kwargs must be a dict");
-        return NULL;
-    }
-
-    return PyVectorcall_Call(func, argstuple, kwargs);
-}
-
-
 static PyObject*
 stack_pointer(PyObject *self, PyObject *args)
 {
@@ -6403,10 +6285,6 @@ static PyMethodDef TestMethods[] = {
     {"tracemalloc_get_traceback", tracemalloc_get_traceback, METH_VARARGS},
     {"dict_get_version", dict_get_version, METH_VARARGS},
     {"raise_SIGINT_then_send_None", raise_SIGINT_then_send_None, METH_VARARGS},
-    {"pyobject_fastcall", test_pyobject_fastcall, METH_VARARGS},
-    {"pyobject_fastcalldict", test_pyobject_fastcalldict, METH_VARARGS},
-    {"pyobject_vectorcall", test_pyobject_vectorcall, METH_VARARGS},
-    {"pyvectorcall_call", test_pyvectorcall_call, METH_VARARGS},
     {"stack_pointer", stack_pointer, METH_NOARGS},
 #ifdef W_STOPCODE
     {"W_STOPCODE", py_w_stopcode, METH_VARARGS},
@@ -7009,106 +6887,6 @@ static PyTypeObject Generic_Type = {
     .tp_methods = generic_methods,
 };
 
-
-/* Test PEP 590 */
-
-typedef struct {
-    PyObject_HEAD
-    vectorcallfunc vectorcall;
-} MethodDescriptorObject;
-
-static PyObject *
-MethodDescriptor_vectorcall(PyObject *callable, PyObject *const *args,
-                            size_t nargsf, PyObject *kwnames)
-{
-    /* True if using the vectorcall function in MethodDescriptorObject
-     * but False for MethodDescriptor2Object */
-    MethodDescriptorObject *md = (MethodDescriptorObject *)callable;
-    return PyBool_FromLong(md->vectorcall != NULL);
-}
-
-static PyObject *
-MethodDescriptor_new(PyTypeObject* type, PyObject* args, PyObject *kw)
-{
-    MethodDescriptorObject *op = (MethodDescriptorObject *)type->tp_alloc(type, 0);
-    op->vectorcall = MethodDescriptor_vectorcall;
-    return (PyObject *)op;
-}
-
-static PyObject *
-func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
-{
-    if (obj == Py_None || obj == NULL) {
-        Py_INCREF(func);
-        return func;
-    }
-    return PyMethod_New(func, obj);
-}
-
-static PyObject *
-nop_descr_get(PyObject *func, PyObject *obj, PyObject *type)
-{
-    Py_INCREF(func);
-    return func;
-}
-
-static PyObject *
-call_return_args(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-    Py_INCREF(args);
-    return args;
-}
-
-static PyTypeObject MethodDescriptorBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "MethodDescriptorBase",
-    sizeof(MethodDescriptorObject),
-    .tp_new = MethodDescriptor_new,
-    .tp_call = PyVectorcall_Call,
-    .tp_vectorcall_offset = offsetof(MethodDescriptorObject, vectorcall),
-    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
-                Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_HAVE_VECTORCALL,
-    .tp_descr_get = func_descr_get,
-};
-
-static PyTypeObject MethodDescriptorDerived_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "MethodDescriptorDerived",
-    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-};
-
-static PyTypeObject MethodDescriptorNopGet_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "MethodDescriptorNopGet",
-    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    .tp_call = call_return_args,
-    .tp_descr_get = nop_descr_get,
-};
-
-typedef struct {
-    MethodDescriptorObject base;
-    vectorcallfunc vectorcall;
-} MethodDescriptor2Object;
-
-static PyObject *
-MethodDescriptor2_new(PyTypeObject* type, PyObject* args, PyObject *kw)
-{
-    MethodDescriptor2Object *op = PyObject_New(MethodDescriptor2Object, type);
-    op->base.vectorcall = NULL;
-    op->vectorcall = MethodDescriptor_vectorcall;
-    return (PyObject *)op;
-}
-
-static PyTypeObject MethodDescriptor2_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "MethodDescriptor2",
-    sizeof(MethodDescriptor2Object),
-    .tp_new = MethodDescriptor2_new,
-    .tp_call = PyVectorcall_Call,
-    .tp_vectorcall_offset = offsetof(MethodDescriptor2Object, vectorcall),
-    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
-};
-
 PyDoc_STRVAR(heapdocctype__doc__,
 "HeapDocCType(arg1, arg2)\n"
 "--\n"
@@ -7778,29 +7556,6 @@ PyInit__testcapi(void)
     Py_INCREF(&MyList_Type);
     PyModule_AddObject(m, "MyList", (PyObject *)&MyList_Type);
 
-    if (PyType_Ready(&MethodDescriptorBase_Type) < 0)
-        return NULL;
-    Py_INCREF(&MethodDescriptorBase_Type);
-    PyModule_AddObject(m, "MethodDescriptorBase", (PyObject *)&MethodDescriptorBase_Type);
-
-    MethodDescriptorDerived_Type.tp_base = &MethodDescriptorBase_Type;
-    if (PyType_Ready(&MethodDescriptorDerived_Type) < 0)
-        return NULL;
-    Py_INCREF(&MethodDescriptorDerived_Type);
-    PyModule_AddObject(m, "MethodDescriptorDerived", (PyObject *)&MethodDescriptorDerived_Type);
-
-    MethodDescriptorNopGet_Type.tp_base = &MethodDescriptorBase_Type;
-    if (PyType_Ready(&MethodDescriptorNopGet_Type) < 0)
-        return NULL;
-    Py_INCREF(&MethodDescriptorNopGet_Type);
-    PyModule_AddObject(m, "MethodDescriptorNopGet", (PyObject *)&MethodDescriptorNopGet_Type);
-
-    MethodDescriptor2_Type.tp_base = &MethodDescriptorBase_Type;
-    if (PyType_Ready(&MethodDescriptor2_Type) < 0)
-        return NULL;
-    Py_INCREF(&MethodDescriptor2_Type);
-    PyModule_AddObject(m, "MethodDescriptor2", (PyObject *)&MethodDescriptor2_Type);
-
     if (PyType_Ready(&GenericAlias_Type) < 0)
         return NULL;
     Py_INCREF(&GenericAlias_Type);
@@ -7973,6 +7728,11 @@ PyInit__testcapi(void)
                            (PyObject *) &ContainerNoGC_type) < 0)
         return NULL;
 
+    /* Include tests from the _testcapi/ directory */
+    if (_PyTestCapi_Init_Vectorcall(m) < 0) {
+        return NULL;
+    }
+
     PyState_AddModule(m, &_testcapimodule);
     return m;
 }
@@ -8024,7 +7784,6 @@ test_buildvalue_issue38913(PyObject *self, PyObject *Py_UNUSED(ignored))
     }
     PyErr_Clear();
 
-
     Py_RETURN_NONE;
 }
 
index c1a19437253b7e8d73b0e13dcc14cf83f1975667..07e23557e1dba38be7ad7eee5557fee8330f788b 100644 (file)
@@ -94,6 +94,7 @@
   </PropertyGroup>
   <ItemGroup>
     <ClCompile Include="..\Modules\_testcapimodule.c" />
+    <ClCompile Include="..\Modules\_testcapi\vectorcall.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\PC\python_nt.rc" />
index 53f64b7aa1e1a20dd7326f324c4beb545159a9db..82fce057e2e27b6463fd7447c3f9be4bdfe7895e 100644 (file)
@@ -12,6 +12,9 @@
     <ClCompile Include="..\Modules\_testcapimodule.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\Modules\_testcapi\vectorcall.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\PC\python_nt.rc">
index 2edcb08b4fd7f82e573321e1f0288fb73c4a42bc..7c71ac6ec64141e2d22e3cdea57e3eacfd045016 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -994,7 +994,7 @@ class PyBuildExt(build_ext):
 
     def detect_test_extensions(self):
         # Python C API test module
-        self.addext(Extension('_testcapi', ['_testcapimodule.c']))
+        self.addext(Extension('_testcapi', ['_testcapimodule.c', '_testcapi/vectorcall.c']))
 
         # Python Internal C API test module
         self.addext(Extension('_testinternalcapi', ['_testinternalcapi.c']))