Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbe862b4

Browse files
authored
gh-93649: Split vectorcall testing from _testcapimodule.c (GH-94549)
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
1 parentefb20a9 commitbe862b4

File tree

9 files changed

+292
-253
lines changed

9 files changed

+292
-253
lines changed

‎Makefile.pre.in‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2568,7 +2568,7 @@ MODULE__SHA3_DEPS=$(srcdir)/Modules/_sha3/sha3.c $(srcdir)/Modules/_sha3/sha3.h
25682568
MODULE__SHA512_DEPS=$(srcdir)/Modules/hashlib.h
25692569
MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h
25702570
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
2571-
MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/testcapi_long.h
2571+
MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/testcapi_long.h Modules/_testcapi/parts.h $(srcdir)/Modules/_testcapi/vectorcall.c
25722572
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
25732573

25742574
# IF YOU PUT ANYTHING HERE IT WILL GO AWAY

‎Modules/Setup.stdlib.in‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
169169
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
170170
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
171-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c
171+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c
172172

173173
# Some testing modules MUST be built as shared libraries.
174174
*shared*

‎Modules/_testcapi/README.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Tests in this directory are compiled into the _testcapi extension.
2+
The main file for the extension is Modules/_testcapimodule.c, which
3+
calls `_PyTestCapi_Init_*` from these functions.

‎Modules/_testcapi/parts.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include"Python.h"
2+
3+
PyAPI_FUNC(int)_PyTestCapi_Init_Vectorcall(PyObject*module);

‎Modules/_testcapi/vectorcall.c‎

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
#include"parts.h"
2+
#include<stddef.h>// offsetof
3+
4+
5+
/* Test PEP 590 - Vectorcall */
6+
7+
staticint
8+
fastcall_args(PyObject*args,PyObject***stack,Py_ssize_t*nargs)
9+
{
10+
if (args==Py_None) {
11+
*stack=NULL;
12+
*nargs=0;
13+
}
14+
elseif (PyTuple_Check(args)) {
15+
*stack= ((PyTupleObject*)args)->ob_item;
16+
*nargs=PyTuple_GET_SIZE(args);
17+
}
18+
else {
19+
PyErr_SetString(PyExc_TypeError,"args must be None or a tuple");
20+
return-1;
21+
}
22+
return0;
23+
}
24+
25+
26+
staticPyObject*
27+
test_pyobject_fastcall(PyObject*self,PyObject*args)
28+
{
29+
PyObject*func,*func_args;
30+
PyObject**stack;
31+
Py_ssize_tnargs;
32+
33+
if (!PyArg_ParseTuple(args,"OO",&func,&func_args)) {
34+
returnNULL;
35+
}
36+
37+
if (fastcall_args(func_args,&stack,&nargs)<0) {
38+
returnNULL;
39+
}
40+
return_PyObject_FastCall(func,stack,nargs);
41+
}
42+
43+
staticPyObject*
44+
test_pyobject_fastcalldict(PyObject*self,PyObject*args)
45+
{
46+
PyObject*func,*func_args,*kwargs;
47+
PyObject**stack;
48+
Py_ssize_tnargs;
49+
50+
if (!PyArg_ParseTuple(args,"OOO",&func,&func_args,&kwargs)) {
51+
returnNULL;
52+
}
53+
54+
if (fastcall_args(func_args,&stack,&nargs)<0) {
55+
returnNULL;
56+
}
57+
58+
if (kwargs==Py_None) {
59+
kwargs=NULL;
60+
}
61+
elseif (!PyDict_Check(kwargs)) {
62+
PyErr_SetString(PyExc_TypeError,"kwnames must be None or a dict");
63+
returnNULL;
64+
}
65+
66+
returnPyObject_VectorcallDict(func,stack,nargs,kwargs);
67+
}
68+
69+
staticPyObject*
70+
test_pyobject_vectorcall(PyObject*self,PyObject*args)
71+
{
72+
PyObject*func,*func_args,*kwnames=NULL;
73+
PyObject**stack;
74+
Py_ssize_tnargs,nkw;
75+
76+
if (!PyArg_ParseTuple(args,"OOO",&func,&func_args,&kwnames)) {
77+
returnNULL;
78+
}
79+
80+
if (fastcall_args(func_args,&stack,&nargs)<0) {
81+
returnNULL;
82+
}
83+
84+
if (kwnames==Py_None) {
85+
kwnames=NULL;
86+
}
87+
elseif (PyTuple_Check(kwnames)) {
88+
nkw=PyTuple_GET_SIZE(kwnames);
89+
if (nargs<nkw) {
90+
PyErr_SetString(PyExc_ValueError,"kwnames longer than args");
91+
returnNULL;
92+
}
93+
nargs-=nkw;
94+
}
95+
else {
96+
PyErr_SetString(PyExc_TypeError,"kwnames must be None or a tuple");
97+
returnNULL;
98+
}
99+
returnPyObject_Vectorcall(func,stack,nargs,kwnames);
100+
}
101+
102+
staticPyObject*
103+
test_pyvectorcall_call(PyObject*self,PyObject*args)
104+
{
105+
PyObject*func;
106+
PyObject*argstuple;
107+
PyObject*kwargs=NULL;
108+
109+
if (!PyArg_ParseTuple(args,"OO|O",&func,&argstuple,&kwargs)) {
110+
returnNULL;
111+
}
112+
113+
if (!PyTuple_Check(argstuple)) {
114+
PyErr_SetString(PyExc_TypeError,"args must be a tuple");
115+
returnNULL;
116+
}
117+
if (kwargs!=NULL&& !PyDict_Check(kwargs)) {
118+
PyErr_SetString(PyExc_TypeError,"kwargs must be a dict");
119+
returnNULL;
120+
}
121+
122+
returnPyVectorcall_Call(func,argstuple,kwargs);
123+
}
124+
125+
staticPyMethodDefTestMethods[]= {
126+
{"pyobject_fastcall",test_pyobject_fastcall,METH_VARARGS},
127+
{"pyobject_fastcalldict",test_pyobject_fastcalldict,METH_VARARGS},
128+
{"pyobject_vectorcall",test_pyobject_vectorcall,METH_VARARGS},
129+
{"pyvectorcall_call",test_pyvectorcall_call,METH_VARARGS},
130+
{NULL},
131+
};
132+
133+
134+
typedefstruct {
135+
PyObject_HEAD
136+
vectorcallfuncvectorcall;
137+
}MethodDescriptorObject;
138+
139+
staticPyObject*
140+
MethodDescriptor_vectorcall(PyObject*callable,PyObject*const*args,
141+
size_tnargsf,PyObject*kwnames)
142+
{
143+
/* True if using the vectorcall function in MethodDescriptorObject
144+
* but False for MethodDescriptor2Object */
145+
MethodDescriptorObject*md= (MethodDescriptorObject*)callable;
146+
returnPyBool_FromLong(md->vectorcall!=NULL);
147+
}
148+
149+
staticPyObject*
150+
MethodDescriptor_new(PyTypeObject*type,PyObject*args,PyObject*kw)
151+
{
152+
MethodDescriptorObject*op= (MethodDescriptorObject*)type->tp_alloc(type,0);
153+
op->vectorcall=MethodDescriptor_vectorcall;
154+
return (PyObject*)op;
155+
}
156+
157+
staticPyObject*
158+
func_descr_get(PyObject*func,PyObject*obj,PyObject*type)
159+
{
160+
if (obj==Py_None||obj==NULL) {
161+
Py_INCREF(func);
162+
returnfunc;
163+
}
164+
returnPyMethod_New(func,obj);
165+
}
166+
167+
staticPyObject*
168+
nop_descr_get(PyObject*func,PyObject*obj,PyObject*type)
169+
{
170+
Py_INCREF(func);
171+
returnfunc;
172+
}
173+
174+
staticPyObject*
175+
call_return_args(PyObject*self,PyObject*args,PyObject*kwargs)
176+
{
177+
Py_INCREF(args);
178+
returnargs;
179+
}
180+
181+
staticPyTypeObjectMethodDescriptorBase_Type= {
182+
PyVarObject_HEAD_INIT(NULL,0)
183+
"MethodDescriptorBase",
184+
sizeof(MethodDescriptorObject),
185+
.tp_new=MethodDescriptor_new,
186+
.tp_call=PyVectorcall_Call,
187+
.tp_vectorcall_offset= offsetof(MethodDescriptorObject,vectorcall),
188+
.tp_flags=Py_TPFLAGS_DEFAULT |Py_TPFLAGS_BASETYPE |
189+
Py_TPFLAGS_METHOD_DESCRIPTOR |Py_TPFLAGS_HAVE_VECTORCALL,
190+
.tp_descr_get=func_descr_get,
191+
};
192+
193+
staticPyTypeObjectMethodDescriptorDerived_Type= {
194+
PyVarObject_HEAD_INIT(NULL,0)
195+
"MethodDescriptorDerived",
196+
.tp_flags=Py_TPFLAGS_DEFAULT |Py_TPFLAGS_BASETYPE,
197+
};
198+
199+
staticPyTypeObjectMethodDescriptorNopGet_Type= {
200+
PyVarObject_HEAD_INIT(NULL,0)
201+
"MethodDescriptorNopGet",
202+
.tp_flags=Py_TPFLAGS_DEFAULT |Py_TPFLAGS_BASETYPE,
203+
.tp_call=call_return_args,
204+
.tp_descr_get=nop_descr_get,
205+
};
206+
207+
typedefstruct {
208+
MethodDescriptorObjectbase;
209+
vectorcallfuncvectorcall;
210+
}MethodDescriptor2Object;
211+
212+
staticPyObject*
213+
MethodDescriptor2_new(PyTypeObject*type,PyObject*args,PyObject*kw)
214+
{
215+
MethodDescriptor2Object*op=PyObject_New(MethodDescriptor2Object,type);
216+
op->base.vectorcall=NULL;
217+
op->vectorcall=MethodDescriptor_vectorcall;
218+
return (PyObject*)op;
219+
}
220+
221+
staticPyTypeObjectMethodDescriptor2_Type= {
222+
PyVarObject_HEAD_INIT(NULL,0)
223+
"MethodDescriptor2",
224+
sizeof(MethodDescriptor2Object),
225+
.tp_new=MethodDescriptor2_new,
226+
.tp_call=PyVectorcall_Call,
227+
.tp_vectorcall_offset= offsetof(MethodDescriptor2Object,vectorcall),
228+
.tp_flags=Py_TPFLAGS_DEFAULT |Py_TPFLAGS_BASETYPE |Py_TPFLAGS_HAVE_VECTORCALL,
229+
};
230+
231+
232+
int
233+
_PyTestCapi_Init_Vectorcall(PyObject*m) {
234+
if (PyModule_AddFunctions(m,TestMethods)<0) {
235+
return-1;
236+
}
237+
238+
if (PyType_Ready(&MethodDescriptorBase_Type)<0) {
239+
return-1;
240+
}
241+
if (PyModule_AddType(m,&MethodDescriptorBase_Type)<0) {
242+
return-1;
243+
}
244+
245+
MethodDescriptorDerived_Type.tp_base=&MethodDescriptorBase_Type;
246+
if (PyType_Ready(&MethodDescriptorDerived_Type)<0) {
247+
return-1;
248+
}
249+
if (PyModule_AddType(m,&MethodDescriptorDerived_Type)<0) {
250+
return-1;
251+
}
252+
253+
MethodDescriptorNopGet_Type.tp_base=&MethodDescriptorBase_Type;
254+
if (PyType_Ready(&MethodDescriptorNopGet_Type)<0) {
255+
return-1;
256+
}
257+
if (PyModule_AddType(m,&MethodDescriptorNopGet_Type)<0) {
258+
return-1;
259+
}
260+
261+
MethodDescriptor2_Type.tp_base=&MethodDescriptorBase_Type;
262+
if (PyType_Ready(&MethodDescriptor2_Type)<0) {
263+
return-1;
264+
}
265+
if (PyModule_AddType(m,&MethodDescriptor2_Type)<0) {
266+
return-1;
267+
}
268+
269+
return0;
270+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp