Skip to content

Commit 4ad753f

Browse files
committed
add testcases to test_capi
1 parent 7acde40 commit 4ad753f

File tree

2 files changed

+149
-1
lines changed

2 files changed

+149
-1
lines changed

Lib/test/test_call.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,11 +812,61 @@ def get_a(x):
812812
assert_equal("overridden", get_a(x))
813813

814814
@requires_limited_api
815-
def test_vectorcall_limited(self):
815+
def test_vectorcall_limited_incoming(self):
816816
from _testcapi import pyobject_vectorcall
817817
obj = _testcapi.LimitedVectorCallClass()
818818
self.assertEqual(pyobject_vectorcall(obj, (), ()), "vectorcall called")
819819

820+
@requires_limited_api
821+
def test_vectorcall_limited_outgoing(self):
822+
from _testcapi import test_vectorcall
823+
824+
args_captured = []
825+
kwargs_captured = []
826+
827+
def f(*args, **kwargs):
828+
args_captured.append(args)
829+
kwargs_captured.append(kwargs)
830+
return "success"
831+
832+
self.assertEqual(test_vectorcall(f), "success")
833+
self.assertEqual(args_captured, [("foo",)])
834+
self.assertEqual(kwargs_captured, [{"baz": "bar"}])
835+
836+
@requires_limited_api
837+
def test_vectorcall_limited_outgoing_dict(self):
838+
from _testcapi import test_vectorcall_dict
839+
840+
args_captured = []
841+
kwargs_captured = []
842+
843+
def f(*args, **kwargs):
844+
args_captured.append(args)
845+
kwargs_captured.append(kwargs)
846+
return "success"
847+
848+
self.assertEqual(test_vectorcall_dict(f), "success")
849+
self.assertEqual(args_captured, [("foo",)])
850+
self.assertEqual(kwargs_captured, [{"baz": "bar"}])
851+
852+
@requires_limited_api
853+
def test_vectorcall_limited_outgoing_method(self):
854+
from _testcapi import test_vectorcall_method
855+
856+
args_captured = []
857+
kwargs_captured = []
858+
859+
class TestInstance:
860+
def f(self, *args, **kwargs):
861+
nonlocal args_captured, kwargs_captured
862+
print('got here')
863+
args_captured.append(args)
864+
kwargs_captured.append(kwargs)
865+
return "success"
866+
867+
self.assertEqual(test_vectorcall_method(TestInstance()), "success")
868+
self.assertEqual(args_captured, [("foo",)])
869+
self.assertEqual(kwargs_captured, [{"baz": "bar"}])
820870

821871
class A:
822872
def method_two_args(self, x, y):

Modules/_testcapi/vectorcall_limited.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,101 @@ LimitedVectorCallClass_new(PyTypeObject *tp, PyTypeObject *a, PyTypeObject *kw)
3232
return self;
3333
}
3434

35+
static PyObject *test_vectorcall(PyObject* self, PyObject *callable) {
36+
PyObject *args[3], *kwname, *kwnames;
37+
38+
args[0] = NULL;
39+
args[1] = PyUnicode_FromString("foo");
40+
args[2] = PyUnicode_FromString("bar");
41+
kwname = PyUnicode_InternFromString("baz");
42+
kwnames = PyTuple_New(1);
43+
44+
if (!args[1] || !args[2] || !kwname || !kwnames ||
45+
PyTuple_SetItem(kwnames, 0, kwname)) {
46+
Py_XDECREF(args[1]);
47+
Py_XDECREF(args[2]);
48+
Py_XDECREF(kwnames);
49+
return NULL;
50+
}
51+
52+
PyObject *result = PyObject_Vectorcall(
53+
callable,
54+
args + 1,
55+
1 | PY_VECTORCALL_ARGUMENTS_OFFSET,
56+
kwnames
57+
);
58+
59+
Py_DECREF(args[1]);
60+
Py_DECREF(args[2]);
61+
Py_DECREF(kwnames);
62+
63+
return result;
64+
}
65+
66+
static PyObject *test_vectorcall_dict(PyObject* self, PyObject *callable) {
67+
PyObject *args[2], *kwargs, *kwarg;
68+
69+
args[0] = NULL;
70+
args[1] = PyUnicode_FromString("foo");
71+
kwarg = PyUnicode_FromString("bar");
72+
kwargs = PyDict_New();
73+
74+
if (!args[1] || !kwarg || !kwargs ||
75+
PyDict_SetItemString(kwargs, "baz", kwarg)) {
76+
Py_XDECREF(args[1]);
77+
Py_XDECREF(kwarg);
78+
Py_XDECREF(kwargs);
79+
return NULL;
80+
}
81+
82+
PyObject *result = PyObject_VectorcallDict(
83+
callable,
84+
args + 1,
85+
1 | PY_VECTORCALL_ARGUMENTS_OFFSET,
86+
kwargs
87+
);
88+
89+
Py_DECREF(args[1]);
90+
Py_DECREF(kwarg);
91+
Py_DECREF(kwargs);
92+
93+
return result;
94+
}
95+
96+
static PyObject *test_vectorcall_method(PyObject* self, PyObject *callable) {
97+
PyObject *name, *args[3], *kwname, *kwnames;
98+
99+
name = PyUnicode_FromString("f");
100+
args[0] = callable;
101+
args[1] = PyUnicode_FromString("foo");
102+
args[2] = PyUnicode_FromString("bar");
103+
kwname = PyUnicode_InternFromString("baz");
104+
kwnames = PyTuple_New(1);
105+
106+
if (!name || !args[1] || !args[2] || !kwname || !kwnames ||
107+
PyTuple_SetItem(kwnames, 0, kwname)) {
108+
Py_XDECREF(name);
109+
Py_XDECREF(args[1]);
110+
Py_XDECREF(args[2]);
111+
Py_XDECREF(kwnames);
112+
return NULL;
113+
}
114+
115+
PyObject *result = PyObject_VectorcallMethod(
116+
name,
117+
args,
118+
2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
119+
kwnames
120+
);
121+
122+
Py_DECREF(name);
123+
Py_DECREF(args[1]);
124+
Py_DECREF(args[2]);
125+
Py_DECREF(kwnames);
126+
127+
return result;
128+
}
129+
35130
static PyMemberDef LimitedVectorCallClass_members[] = {
36131
{"__vectorcalloffset__", T_PYSSIZET, sizeof(PyObject), READONLY},
37132
{NULL}
@@ -58,6 +153,9 @@ static PyMethodDef TestMethods[] = {
58153
* (Empty list left here as template/example, since using
59154
* PyModule_AddFunctions isn't very common.)
60155
*/
156+
{"test_vectorcall", test_vectorcall, METH_O},
157+
{"test_vectorcall_method", test_vectorcall_method, METH_O},
158+
{"test_vectorcall_dict", test_vectorcall_dict, METH_O},
61159
{NULL},
62160
};
63161

0 commit comments

Comments
 (0)