blob: 451a7170c304dec91f45983b51991051453e2dbc [file] [log] [blame]
Jeremy Hyltonbea39472001-05-29 16:26:20 +00001import unittest
Serhiy Storchaka5eb788b2017-06-06 18:45:22 +03002from test.support import cpython_only
Victor Stinner3b5cf852017-06-09 16:48:45 +02003try:
4 import _testcapi
5except ImportError:
6 _testcapi = None
Sylvain96c7c062017-06-15 17:05:23 +02007import struct
8import collections
Oren Milmanbf9075a2017-08-23 21:16:48 +03009import itertools
Jeroen Demeyer77aa3962019-05-22 13:09:35 +020010import gc
Jeremy Hyltonbea39472001-05-29 16:26:20 +000011
INADA Naoki2aaf98c2018-09-26 12:59:00 +090012
13class FunctionCalls(unittest.TestCase):
14
15 def test_kwargs_order(self):
16 # bpo-34320: **kwargs should preserve order of passed OrderedDict
17 od = collections.OrderedDict([('a', 1), ('b', 2)])
18 od.move_to_end('a')
19 expected = list(od.items())
20
21 def fn(**kw):
22 return kw
23
24 res = fn(**od)
25 self.assertIsInstance(res, dict)
26 self.assertEqual(list(res.items()), expected)
27
28
Serhiy Storchaka5eb788b2017-06-06 18:45:22 +030029@cpython_only
30class CFunctionCallsErrorMessages(unittest.TestCase):
31
32 def test_varargs0(self):
33 msg = r"__contains__\(\) takes exactly one argument \(0 given\)"
34 self.assertRaisesRegex(TypeError, msg, {}.__contains__)
35
36 def test_varargs2(self):
37 msg = r"__contains__\(\) takes exactly one argument \(2 given\)"
38 self.assertRaisesRegex(TypeError, msg, {}.__contains__, 0, 1)
39
Serhiy Storchakaf9f1cca2017-06-09 19:27:06 +030040 def test_varargs3(self):
Serhiy Storchakaf2f55e72019-03-13 23:03:22 +020041 msg = r"^from_bytes\(\) takes exactly 2 positional arguments \(3 given\)"
Serhiy Storchakaf9f1cca2017-06-09 19:27:06 +030042 self.assertRaisesRegex(TypeError, msg, int.from_bytes, b'a', 'little', False)
43
Xtreak63262782018-12-21 20:15:13 +053044 def test_varargs1min(self):
Xtreak1426daa2018-07-23 01:43:26 +053045 msg = r"get expected at least 1 argument, got 0"
46 self.assertRaisesRegex(TypeError, msg, {}.get)
47
Xtreak63262782018-12-21 20:15:13 +053048 msg = r"expected 1 argument, got 0"
49 self.assertRaisesRegex(TypeError, msg, {}.__delattr__)
50
51 def test_varargs2min(self):
Xtreak1426daa2018-07-23 01:43:26 +053052 msg = r"getattr expected at least 2 arguments, got 0"
53 self.assertRaisesRegex(TypeError, msg, getattr)
54
Xtreak63262782018-12-21 20:15:13 +053055 def test_varargs1max(self):
Xtreak1426daa2018-07-23 01:43:26 +053056 msg = r"input expected at most 1 argument, got 2"
57 self.assertRaisesRegex(TypeError, msg, input, 1, 2)
58
Xtreak63262782018-12-21 20:15:13 +053059 def test_varargs2max(self):
Xtreak1426daa2018-07-23 01:43:26 +053060 msg = r"get expected at most 2 arguments, got 3"
61 self.assertRaisesRegex(TypeError, msg, {}.get, 1, 2, 3)
62
Serhiy Storchaka5eb788b2017-06-06 18:45:22 +030063 def test_varargs1_kw(self):
64 msg = r"__contains__\(\) takes no keyword arguments"
65 self.assertRaisesRegex(TypeError, msg, {}.__contains__, x=2)
66
67 def test_varargs2_kw(self):
68 msg = r"__contains__\(\) takes no keyword arguments"
69 self.assertRaisesRegex(TypeError, msg, {}.__contains__, x=2, y=2)
70
Sylvain74453812017-06-10 06:51:48 +020071 def test_varargs3_kw(self):
72 msg = r"bool\(\) takes no keyword arguments"
73 self.assertRaisesRegex(TypeError, msg, bool, x=2)
74
75 def test_varargs4_kw(self):
Jeroen Demeyerbf17d412019-11-05 16:48:04 +010076 msg = r"^list[.]index\(\) takes no keyword arguments$"
Sylvain74453812017-06-10 06:51:48 +020077 self.assertRaisesRegex(TypeError, msg, [].index, x=2)
78
79 def test_varargs5_kw(self):
80 msg = r"^hasattr\(\) takes no keyword arguments$"
81 self.assertRaisesRegex(TypeError, msg, hasattr, x=2)
82
Sylvain96c7c062017-06-15 17:05:23 +020083 def test_varargs6_kw(self):
84 msg = r"^getattr\(\) takes no keyword arguments$"
85 self.assertRaisesRegex(TypeError, msg, getattr, x=2)
86
87 def test_varargs7_kw(self):
88 msg = r"^next\(\) takes no keyword arguments$"
89 self.assertRaisesRegex(TypeError, msg, next, x=2)
90
91 def test_varargs8_kw(self):
Jeroen Demeyerbf17d412019-11-05 16:48:04 +010092 msg = r"^_struct[.]pack\(\) takes no keyword arguments$"
Sylvain96c7c062017-06-15 17:05:23 +020093 self.assertRaisesRegex(TypeError, msg, struct.pack, x=2)
94
95 def test_varargs9_kw(self):
Jeroen Demeyerbf17d412019-11-05 16:48:04 +010096 msg = r"^_struct[.]pack_into\(\) takes no keyword arguments$"
Sylvain96c7c062017-06-15 17:05:23 +020097 self.assertRaisesRegex(TypeError, msg, struct.pack_into, x=2)
98
99 def test_varargs10_kw(self):
Jeroen Demeyerbf17d412019-11-05 16:48:04 +0100100 msg = r"^deque[.]index\(\) takes no keyword arguments$"
Sylvain96c7c062017-06-15 17:05:23 +0200101 self.assertRaisesRegex(TypeError, msg, collections.deque().index, x=2)
102
103 def test_varargs11_kw(self):
Jeroen Demeyerbf17d412019-11-05 16:48:04 +0100104 msg = r"^Struct[.]pack\(\) takes no keyword arguments$"
Sylvain96c7c062017-06-15 17:05:23 +0200105 self.assertRaisesRegex(TypeError, msg, struct.Struct.pack, struct.Struct(""), x=2)
106
Sylvain96480882017-07-09 05:45:06 +0200107 def test_varargs12_kw(self):
108 msg = r"^staticmethod\(\) takes no keyword arguments$"
109 self.assertRaisesRegex(TypeError, msg, staticmethod, func=id)
110
111 def test_varargs13_kw(self):
112 msg = r"^classmethod\(\) takes no keyword arguments$"
113 self.assertRaisesRegex(TypeError, msg, classmethod, func=id)
114
Oren Milmanbf9075a2017-08-23 21:16:48 +0300115 def test_varargs14_kw(self):
116 msg = r"^product\(\) takes at most 1 keyword argument \(2 given\)$"
117 self.assertRaisesRegex(TypeError, msg,
118 itertools.product, 0, repeat=1, foo=2)
119
120 def test_varargs15_kw(self):
121 msg = r"^ImportError\(\) takes at most 2 keyword arguments \(3 given\)$"
122 self.assertRaisesRegex(TypeError, msg,
123 ImportError, 0, name=1, path=2, foo=3)
124
125 def test_varargs16_kw(self):
126 msg = r"^min\(\) takes at most 2 keyword arguments \(3 given\)$"
127 self.assertRaisesRegex(TypeError, msg,
128 min, 0, default=1, key=2, foo=3)
129
130 def test_varargs17_kw(self):
131 msg = r"^print\(\) takes at most 4 keyword arguments \(5 given\)$"
132 self.assertRaisesRegex(TypeError, msg,
133 print, 0, sep=1, end=2, file=3, flush=4, foo=5)
134
Serhiy Storchaka5eb788b2017-06-06 18:45:22 +0300135 def test_oldargs0_1(self):
136 msg = r"keys\(\) takes no arguments \(1 given\)"
137 self.assertRaisesRegex(TypeError, msg, {}.keys, 0)
138
139 def test_oldargs0_2(self):
140 msg = r"keys\(\) takes no arguments \(2 given\)"
141 self.assertRaisesRegex(TypeError, msg, {}.keys, 0, 1)
142
143 def test_oldargs0_1_kw(self):
144 msg = r"keys\(\) takes no keyword arguments"
145 self.assertRaisesRegex(TypeError, msg, {}.keys, x=2)
146
147 def test_oldargs0_2_kw(self):
148 msg = r"keys\(\) takes no keyword arguments"
149 self.assertRaisesRegex(TypeError, msg, {}.keys, x=2, y=2)
150
151 def test_oldargs1_0(self):
152 msg = r"count\(\) takes exactly one argument \(0 given\)"
153 self.assertRaisesRegex(TypeError, msg, [].count)
154
155 def test_oldargs1_2(self):
156 msg = r"count\(\) takes exactly one argument \(2 given\)"
157 self.assertRaisesRegex(TypeError, msg, [].count, 1, 2)
158
159 def test_oldargs1_0_kw(self):
160 msg = r"count\(\) takes no keyword arguments"
161 self.assertRaisesRegex(TypeError, msg, [].count, x=2)
162
163 def test_oldargs1_1_kw(self):
164 msg = r"count\(\) takes no keyword arguments"
165 self.assertRaisesRegex(TypeError, msg, [].count, {}, x=2)
166
167 def test_oldargs1_2_kw(self):
168 msg = r"count\(\) takes no keyword arguments"
169 self.assertRaisesRegex(TypeError, msg, [].count, x=2, y=2)
170
171
Petr Viktorinf9583772019-09-10 12:21:09 +0100172
173class TestCallingConventions(unittest.TestCase):
174 """Test calling using various C calling conventions (METH_*) from Python
175
176 Subclasses test several kinds of functions (module-level, methods,
177 class methods static methods) using these attributes:
178 obj: the object that contains tested functions (as attributes)
179 expected_self: expected "self" argument to the C function
180
181 The base class tests module-level functions.
182 """
183
184 def setUp(self):
185 self.obj = self.expected_self = _testcapi
186
187 def test_varargs(self):
188 self.assertEqual(
189 self.obj.meth_varargs(1, 2, 3),
190 (self.expected_self, (1, 2, 3)),
191 )
192
193 def test_varargs_ext(self):
194 self.assertEqual(
195 self.obj.meth_varargs(*(1, 2, 3)),
196 (self.expected_self, (1, 2, 3)),
197 )
198
199 def test_varargs_error_kw(self):
200 msg = r"meth_varargs\(\) takes no keyword arguments"
201 self.assertRaisesRegex(
202 TypeError, msg, lambda: self.obj.meth_varargs(k=1),
203 )
204
205 def test_varargs_keywords(self):
206 self.assertEqual(
207 self.obj.meth_varargs_keywords(1, 2, a=3, b=4),
208 (self.expected_self, (1, 2), {'a': 3, 'b': 4})
209 )
210
211 def test_varargs_keywords_ext(self):
212 self.assertEqual(
213 self.obj.meth_varargs_keywords(*[1, 2], **{'a': 3, 'b': 4}),
214 (self.expected_self, (1, 2), {'a': 3, 'b': 4})
215 )
216
217 def test_o(self):
218 self.assertEqual(self.obj.meth_o(1), (self.expected_self, 1))
219
220 def test_o_ext(self):
221 self.assertEqual(self.obj.meth_o(*[1]), (self.expected_self, 1))
222
223 def test_o_error_no_arg(self):
224 msg = r"meth_o\(\) takes exactly one argument \(0 given\)"
225 self.assertRaisesRegex(TypeError, msg, self.obj.meth_o)
226
227 def test_o_error_two_args(self):
228 msg = r"meth_o\(\) takes exactly one argument \(2 given\)"
229 self.assertRaisesRegex(
230 TypeError, msg, lambda: self.obj.meth_o(1, 2),
231 )
232
233 def test_o_error_ext(self):
234 msg = r"meth_o\(\) takes exactly one argument \(3 given\)"
235 self.assertRaisesRegex(
236 TypeError, msg, lambda: self.obj.meth_o(*(1, 2, 3)),
237 )
238
239 def test_o_error_kw(self):
240 msg = r"meth_o\(\) takes no keyword arguments"
241 self.assertRaisesRegex(
242 TypeError, msg, lambda: self.obj.meth_o(k=1),
243 )
244
245 def test_o_error_arg_kw(self):
246 msg = r"meth_o\(\) takes no keyword arguments"
247 self.assertRaisesRegex(
248 TypeError, msg, lambda: self.obj.meth_o(k=1),
249 )
250
251 def test_noargs(self):
252 self.assertEqual(self.obj.meth_noargs(), self.expected_self)
253
254 def test_noargs_ext(self):
255 self.assertEqual(self.obj.meth_noargs(*[]), self.expected_self)
256
257 def test_noargs_error_arg(self):
258 msg = r"meth_noargs\(\) takes no arguments \(1 given\)"
259 self.assertRaisesRegex(
260 TypeError, msg, lambda: self.obj.meth_noargs(1),
261 )
262
263 def test_noargs_error_arg2(self):
264 msg = r"meth_noargs\(\) takes no arguments \(2 given\)"
265 self.assertRaisesRegex(
266 TypeError, msg, lambda: self.obj.meth_noargs(1, 2),
267 )
268
269 def test_noargs_error_ext(self):
270 msg = r"meth_noargs\(\) takes no arguments \(3 given\)"
271 self.assertRaisesRegex(
272 TypeError, msg, lambda: self.obj.meth_noargs(*(1, 2, 3)),
273 )
274
275 def test_noargs_error_kw(self):
276 msg = r"meth_noargs\(\) takes no keyword arguments"
277 self.assertRaisesRegex(
278 TypeError, msg, lambda: self.obj.meth_noargs(k=1),
279 )
280
281 def test_fastcall(self):
282 self.assertEqual(
283 self.obj.meth_fastcall(1, 2, 3),
284 (self.expected_self, (1, 2, 3)),
285 )
286
287 def test_fastcall_ext(self):
288 self.assertEqual(
289 self.obj.meth_fastcall(*(1, 2, 3)),
290 (self.expected_self, (1, 2, 3)),
291 )
292
293 def test_fastcall_error_kw(self):
294 msg = r"meth_fastcall\(\) takes no keyword arguments"
295 self.assertRaisesRegex(
296 TypeError, msg, lambda: self.obj.meth_fastcall(k=1),
297 )
298
299 def test_fastcall_keywords(self):
300 self.assertEqual(
301 self.obj.meth_fastcall_keywords(1, 2, a=3, b=4),
302 (self.expected_self, (1, 2), {'a': 3, 'b': 4})
303 )
304
305 def test_fastcall_keywords_ext(self):
306 self.assertEqual(
307 self.obj.meth_fastcall_keywords(*(1, 2), **{'a': 3, 'b': 4}),
308 (self.expected_self, (1, 2), {'a': 3, 'b': 4})
309 )
310
311
312class TestCallingConventionsInstance(TestCallingConventions):
313 """Test calling instance methods using various calling conventions"""
314
315 def setUp(self):
316 self.obj = self.expected_self = _testcapi.MethInstance()
317
318
319class TestCallingConventionsClass(TestCallingConventions):
320 """Test calling class methods using various calling conventions"""
321
322 def setUp(self):
323 self.obj = self.expected_self = _testcapi.MethClass
324
325
326class TestCallingConventionsClassInstance(TestCallingConventions):
327 """Test calling class methods on instance"""
328
329 def setUp(self):
330 self.obj = _testcapi.MethClass()
331 self.expected_self = _testcapi.MethClass
332
333
334class TestCallingConventionsStatic(TestCallingConventions):
335 """Test calling static methods using various calling conventions"""
336
337 def setUp(self):
338 self.obj = _testcapi.MethStatic()
339 self.expected_self = None
340
341
Victor Stinner3b5cf852017-06-09 16:48:45 +0200342def pyfunc(arg1, arg2):
343 return [arg1, arg2]
344
345
346def pyfunc_noarg():
347 return "noarg"
348
349
350class PythonClass:
351 def method(self, arg1, arg2):
352 return [arg1, arg2]
353
354 def method_noarg(self):
355 return "noarg"
356
357 @classmethod
358 def class_method(cls):
359 return "classmethod"
360
361 @staticmethod
362 def static_method():
363 return "staticmethod"
364
365
366PYTHON_INSTANCE = PythonClass()
367
Petr Viktorinf9583772019-09-10 12:21:09 +0100368NULL_OR_EMPTY = object()
Victor Stinner3b5cf852017-06-09 16:48:45 +0200369
Victor Stinner3b5cf852017-06-09 16:48:45 +0200370class FastCallTests(unittest.TestCase):
Petr Viktorinf9583772019-09-10 12:21:09 +0100371 """Test calling using various callables from C
372 """
373
Victor Stinner3b5cf852017-06-09 16:48:45 +0200374 # Test calls with positional arguments
Petr Viktorinf9583772019-09-10 12:21:09 +0100375 CALLS_POSARGS = [
Victor Stinner3b5cf852017-06-09 16:48:45 +0200376 # (func, args: tuple, result)
377
378 # Python function with 2 arguments
379 (pyfunc, (1, 2), [1, 2]),
380
381 # Python function without argument
382 (pyfunc_noarg, (), "noarg"),
383
384 # Python class methods
385 (PythonClass.class_method, (), "classmethod"),
386 (PythonClass.static_method, (), "staticmethod"),
387
388 # Python instance methods
389 (PYTHON_INSTANCE.method, (1, 2), [1, 2]),
390 (PYTHON_INSTANCE.method_noarg, (), "noarg"),
391 (PYTHON_INSTANCE.class_method, (), "classmethod"),
392 (PYTHON_INSTANCE.static_method, (), "staticmethod"),
393
Petr Viktorinf9583772019-09-10 12:21:09 +0100394 # C callables are added later
395 ]
Victor Stinner3b5cf852017-06-09 16:48:45 +0200396
397 # Test calls with positional and keyword arguments
Petr Viktorinf9583772019-09-10 12:21:09 +0100398 CALLS_KWARGS = [
Victor Stinner3b5cf852017-06-09 16:48:45 +0200399 # (func, args: tuple, kwargs: dict, result)
400
401 # Python function with 2 arguments
402 (pyfunc, (1,), {'arg2': 2}, [1, 2]),
403 (pyfunc, (), {'arg1': 1, 'arg2': 2}, [1, 2]),
404
405 # Python instance methods
406 (PYTHON_INSTANCE.method, (1,), {'arg2': 2}, [1, 2]),
407 (PYTHON_INSTANCE.method, (), {'arg1': 1, 'arg2': 2}, [1, 2]),
408
Petr Viktorinf9583772019-09-10 12:21:09 +0100409 # C callables are added later
410 ]
Victor Stinner3b5cf852017-06-09 16:48:45 +0200411
Petr Viktorinf9583772019-09-10 12:21:09 +0100412 # Add all the calling conventions and variants of C callables
413 _instance = _testcapi.MethInstance()
414 for obj, expected_self in (
415 (_testcapi, _testcapi), # module-level function
416 (_instance, _instance), # bound method
417 (_testcapi.MethClass, _testcapi.MethClass), # class method on class
418 (_testcapi.MethClass(), _testcapi.MethClass), # class method on inst.
419 (_testcapi.MethStatic, None), # static method
420 ):
421 CALLS_POSARGS.extend([
422 (obj.meth_varargs, (1, 2), (expected_self, (1, 2))),
423 (obj.meth_varargs_keywords,
424 (1, 2), (expected_self, (1, 2), NULL_OR_EMPTY)),
425 (obj.meth_fastcall, (1, 2), (expected_self, (1, 2))),
426 (obj.meth_fastcall, (), (expected_self, ())),
427 (obj.meth_fastcall_keywords,
428 (1, 2), (expected_self, (1, 2), NULL_OR_EMPTY)),
429 (obj.meth_fastcall_keywords,
430 (), (expected_self, (), NULL_OR_EMPTY)),
431 (obj.meth_noargs, (), expected_self),
432 (obj.meth_o, (123, ), (expected_self, 123)),
433 ])
434
435 CALLS_KWARGS.extend([
436 (obj.meth_varargs_keywords,
437 (1, 2), {'x': 'y'}, (expected_self, (1, 2), {'x': 'y'})),
438 (obj.meth_varargs_keywords,
439 (), {'x': 'y'}, (expected_self, (), {'x': 'y'})),
440 (obj.meth_varargs_keywords,
441 (1, 2), {}, (expected_self, (1, 2), NULL_OR_EMPTY)),
442 (obj.meth_fastcall_keywords,
443 (1, 2), {'x': 'y'}, (expected_self, (1, 2), {'x': 'y'})),
444 (obj.meth_fastcall_keywords,
445 (), {'x': 'y'}, (expected_self, (), {'x': 'y'})),
446 (obj.meth_fastcall_keywords,
447 (1, 2), {}, (expected_self, (1, 2), NULL_OR_EMPTY)),
448 ])
Victor Stinner3b5cf852017-06-09 16:48:45 +0200449
450 def check_result(self, result, expected):
Petr Viktorinf9583772019-09-10 12:21:09 +0100451 if isinstance(expected, tuple) and expected[-1] is NULL_OR_EMPTY:
452 if result[-1] in ({}, None):
453 expected = (*expected[:-1], result[-1])
Victor Stinner3b5cf852017-06-09 16:48:45 +0200454 self.assertEqual(result, expected)
455
456 def test_fastcall(self):
457 # Test _PyObject_FastCall()
458
459 for func, args, expected in self.CALLS_POSARGS:
460 with self.subTest(func=func, args=args):
461 result = _testcapi.pyobject_fastcall(func, args)
462 self.check_result(result, expected)
463
464 if not args:
465 # args=NULL, nargs=0
466 result = _testcapi.pyobject_fastcall(func, None)
467 self.check_result(result, expected)
468
Jeroen Demeyeraacc77f2019-05-29 20:31:52 +0200469 def test_vectorcall_dict(self):
Petr Viktorinffd97532020-02-11 17:46:57 +0100470 # Test PyObject_VectorcallDict()
Victor Stinner3b5cf852017-06-09 16:48:45 +0200471
472 for func, args, expected in self.CALLS_POSARGS:
473 with self.subTest(func=func, args=args):
474 # kwargs=NULL
475 result = _testcapi.pyobject_fastcalldict(func, args, None)
476 self.check_result(result, expected)
477
Victor Stinner3b5cf852017-06-09 16:48:45 +0200478 if not args:
479 # args=NULL, nargs=0, kwargs=NULL
480 result = _testcapi.pyobject_fastcalldict(func, None, None)
481 self.check_result(result, expected)
482
Victor Stinner3b5cf852017-06-09 16:48:45 +0200483 for func, args, kwargs, expected in self.CALLS_KWARGS:
484 with self.subTest(func=func, args=args, kwargs=kwargs):
485 result = _testcapi.pyobject_fastcalldict(func, args, kwargs)
486 self.check_result(result, expected)
487
Jeroen Demeyeraacc77f2019-05-29 20:31:52 +0200488 def test_vectorcall(self):
Petr Viktorinffd97532020-02-11 17:46:57 +0100489 # Test PyObject_Vectorcall()
Victor Stinner3b5cf852017-06-09 16:48:45 +0200490
491 for func, args, expected in self.CALLS_POSARGS:
492 with self.subTest(func=func, args=args):
493 # kwnames=NULL
Jeroen Demeyeraacc77f2019-05-29 20:31:52 +0200494 result = _testcapi.pyobject_vectorcall(func, args, None)
Victor Stinner3b5cf852017-06-09 16:48:45 +0200495 self.check_result(result, expected)
496
497 # kwnames=()
Jeroen Demeyeraacc77f2019-05-29 20:31:52 +0200498 result = _testcapi.pyobject_vectorcall(func, args, ())
Victor Stinner3b5cf852017-06-09 16:48:45 +0200499 self.check_result(result, expected)
500
501 if not args:
502 # kwnames=NULL
Jeroen Demeyeraacc77f2019-05-29 20:31:52 +0200503 result = _testcapi.pyobject_vectorcall(func, None, None)
Victor Stinner3b5cf852017-06-09 16:48:45 +0200504 self.check_result(result, expected)
505
506 # kwnames=()
Jeroen Demeyeraacc77f2019-05-29 20:31:52 +0200507 result = _testcapi.pyobject_vectorcall(func, None, ())
Victor Stinner3b5cf852017-06-09 16:48:45 +0200508 self.check_result(result, expected)
509
510 for func, args, kwargs, expected in self.CALLS_KWARGS:
511 with self.subTest(func=func, args=args, kwargs=kwargs):
512 kwnames = tuple(kwargs.keys())
513 args = args + tuple(kwargs.values())
Jeroen Demeyeraacc77f2019-05-29 20:31:52 +0200514 result = _testcapi.pyobject_vectorcall(func, args, kwnames)
Victor Stinner3b5cf852017-06-09 16:48:45 +0200515 self.check_result(result, expected)
516
Jeroen Demeyer77aa3962019-05-22 13:09:35 +0200517 def test_fastcall_clearing_dict(self):
518 # Test bpo-36907: the point of the test is just checking that this
519 # does not crash.
520 class IntWithDict:
521 __slots__ = ["kwargs"]
522 def __init__(self, **kwargs):
523 self.kwargs = kwargs
524 def __index__(self):
525 self.kwargs.clear()
526 gc.collect()
527 return 0
528 x = IntWithDict(dont_inherit=IntWithDict())
529 # We test the argument handling of "compile" here, the compilation
530 # itself is not relevant. When we pass flags=x below, x.__index__() is
531 # called, which changes the keywords dict.
532 compile("pass", "", "exec", x, **x.kwargs)
Victor Stinner3b5cf852017-06-09 16:48:45 +0200533
Victor Stinner740a84d2019-06-07 17:51:28 +0200534
535Py_TPFLAGS_HAVE_VECTORCALL = 1 << 11
536Py_TPFLAGS_METHOD_DESCRIPTOR = 1 << 17
537
538
539def testfunction(self):
540 """some doc"""
541 return self
542
543
544def testfunction_kw(self, *, kw):
545 """some doc"""
546 return self
547
548
549class TestPEP590(unittest.TestCase):
550
551 def test_method_descriptor_flag(self):
552 import functools
553 cached = functools.lru_cache(1)(testfunction)
554
555 self.assertFalse(type(repr).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
556 self.assertTrue(type(list.append).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
557 self.assertTrue(type(list.__add__).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
558 self.assertTrue(type(testfunction).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
559 self.assertTrue(type(cached).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
560
561 self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
562 self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
563 self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
564
565 # Heap type should not inherit Py_TPFLAGS_METHOD_DESCRIPTOR
566 class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
567 pass
568 self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
569
570 def test_vectorcall_flag(self):
571 self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
572 self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
573 self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
574 self.assertTrue(_testcapi.MethodDescriptor2.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
575
576 # Heap type should not inherit Py_TPFLAGS_HAVE_VECTORCALL
577 class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
578 pass
579 self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
580
581 def test_vectorcall_override(self):
582 # Check that tp_call can correctly override vectorcall.
583 # MethodDescriptorNopGet implements tp_call but it inherits from
584 # MethodDescriptorBase, which implements vectorcall. Since
585 # MethodDescriptorNopGet returns the args tuple when called, we check
586 # additionally that no new tuple is created for this call.
587 args = tuple(range(5))
588 f = _testcapi.MethodDescriptorNopGet()
589 self.assertIs(f(*args), args)
590
591 def test_vectorcall(self):
592 # Test a bunch of different ways to call objects:
593 # 1. vectorcall using PyVectorcall_Call()
594 # (only for objects that support vectorcall directly)
595 # 2. normal call
Petr Viktorinffd97532020-02-11 17:46:57 +0100596 # 3. vectorcall using PyObject_Vectorcall()
Victor Stinner740a84d2019-06-07 17:51:28 +0200597 # 4. call as bound method
598 # 5. call using functools.partial
599
600 # A list of (function, args, kwargs, result) calls to test
601 calls = [(len, (range(42),), {}, 42),
602 (list.append, ([], 0), {}, None),
603 ([].append, (0,), {}, None),
604 (sum, ([36],), {"start":6}, 42),
605 (testfunction, (42,), {}, 42),
606 (testfunction_kw, (42,), {"kw":None}, 42),
607 (_testcapi.MethodDescriptorBase(), (0,), {}, True),
608 (_testcapi.MethodDescriptorDerived(), (0,), {}, True),
609 (_testcapi.MethodDescriptor2(), (0,), {}, False)]
610
611 from _testcapi import pyobject_vectorcall, pyvectorcall_call
612 from types import MethodType
613 from functools import partial
614
615 def vectorcall(func, args, kwargs):
616 args = *args, *kwargs.values()
617 kwnames = tuple(kwargs)
618 return pyobject_vectorcall(func, args, kwnames)
619
620 for (func, args, kwargs, expected) in calls:
621 with self.subTest(str(func)):
622 if not kwargs:
623 self.assertEqual(expected, pyvectorcall_call(func, args))
624 self.assertEqual(expected, pyvectorcall_call(func, args, kwargs))
625
626 # Add derived classes (which do not support vectorcall directly,
627 # but do support all other ways of calling).
628
629 class MethodDescriptorHeap(_testcapi.MethodDescriptorBase):
630 pass
631
632 class MethodDescriptorOverridden(_testcapi.MethodDescriptorBase):
633 def __call__(self, n):
634 return 'new'
635
Jeroen Demeyera8b27e62019-06-24 12:41:05 +0200636 class SuperBase:
637 def __call__(self, *args):
638 return super().__call__(*args)
639
640 class MethodDescriptorSuper(SuperBase, _testcapi.MethodDescriptorBase):
641 def __call__(self, *args):
642 return super().__call__(*args)
643
Victor Stinner740a84d2019-06-07 17:51:28 +0200644 calls += [
Jeroen Demeyer0d722f32019-07-05 14:48:24 +0200645 (dict.update, ({},), {"key":True}, None),
646 ({}.update, ({},), {"key":True}, None),
Victor Stinner740a84d2019-06-07 17:51:28 +0200647 (MethodDescriptorHeap(), (0,), {}, True),
648 (MethodDescriptorOverridden(), (0,), {}, 'new'),
Jeroen Demeyera8b27e62019-06-24 12:41:05 +0200649 (MethodDescriptorSuper(), (0,), {}, True),
Victor Stinner740a84d2019-06-07 17:51:28 +0200650 ]
651
652 for (func, args, kwargs, expected) in calls:
653 with self.subTest(str(func)):
654 args1 = args[1:]
655 meth = MethodType(func, args[0])
656 wrapped = partial(func)
657 if not kwargs:
658 self.assertEqual(expected, func(*args))
659 self.assertEqual(expected, pyobject_vectorcall(func, args, None))
660 self.assertEqual(expected, meth(*args1))
661 self.assertEqual(expected, wrapped(*args))
662 self.assertEqual(expected, func(*args, **kwargs))
663 self.assertEqual(expected, vectorcall(func, args, kwargs))
664 self.assertEqual(expected, meth(*args1, **kwargs))
665 self.assertEqual(expected, wrapped(*args, **kwargs))
666
667
Fred Drake2e2be372001-09-20 21:33:42 +0000668if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500669 unittest.main()