| 
									
										
										
										
											2001-05-29 16:26:20 +00:00
										 |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2024-01-12 16:29:16 -08:00
										 |  |  | from test.support import (cpython_only, is_wasi, requires_limited_api, Py_DEBUG, | 
					
						
							| 
									
										
										
										
											2025-03-13 10:55:23 +01:00
										 |  |  |                           set_recursion_limit, skip_on_s390x, | 
					
						
							|  |  |  |                           skip_emscripten_stack_overflow, | 
					
						
							|  |  |  |                           skip_wasi_stack_overflow, skip_if_sanitizer, | 
					
						
							|  |  |  |                           import_helper) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | try: | 
					
						
							|  |  |  |     import _testcapi | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     _testcapi = None | 
					
						
							| 
									
										
										
										
											2024-03-07 19:31:12 +01:00
										 |  |  | try: | 
					
						
							|  |  |  |     import _testlimitedcapi | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     _testlimitedcapi = None | 
					
						
							| 
									
										
										
										
											2017-06-15 17:05:23 +02:00
										 |  |  | import struct | 
					
						
							|  |  |  | import collections | 
					
						
							| 
									
										
										
										
											2017-08-23 21:16:48 +03:00
										 |  |  | import itertools | 
					
						
							| 
									
										
										
										
											2019-05-22 13:09:35 +02:00
										 |  |  | import gc | 
					
						
							| 
									
										
										
										
											2020-05-22 16:40:17 -04:00
										 |  |  | import contextlib | 
					
						
							| 
									
										
										
										
											2023-05-04 15:07:42 -07:00
										 |  |  | import types | 
					
						
							| 
									
										
										
										
											2001-05-29 16:26:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 12:59:00 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 07:40:36 +03:00
										 |  |  | class BadStr(str): | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         # Guaranteed different hash | 
					
						
							|  |  |  |         return str.__hash__(self) ^ 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 12:59:00 +09:00
										 |  |  | class FunctionCalls(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_kwargs_order(self): | 
					
						
							|  |  |  |         # bpo-34320:  **kwargs should preserve order of passed OrderedDict | 
					
						
							|  |  |  |         od = collections.OrderedDict([('a', 1), ('b', 2)]) | 
					
						
							|  |  |  |         od.move_to_end('a') | 
					
						
							|  |  |  |         expected = list(od.items()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def fn(**kw): | 
					
						
							|  |  |  |             return kw | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res = fn(**od) | 
					
						
							|  |  |  |         self.assertIsInstance(res, dict) | 
					
						
							|  |  |  |         self.assertEqual(list(res.items()), expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-08 18:52:26 -07:00
										 |  |  |     def test_frames_are_popped_after_failed_calls(self): | 
					
						
							|  |  |  |         # GH-93252: stuff blows up if we don't pop the new frame after | 
					
						
							|  |  |  |         # recovering from failed calls: | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2024-05-04 12:11:11 +01:00
										 |  |  |         class C: | 
					
						
							|  |  |  |             def m(self): | 
					
						
							| 
									
										
										
										
											2022-07-08 18:52:26 -07:00
										 |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2024-05-04 12:11:11 +01:00
										 |  |  |         callables = [f, C.m, [].__len__] | 
					
						
							|  |  |  |         for c in callables: | 
					
						
							|  |  |  |             for _ in range(1000): | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     c(None) | 
					
						
							|  |  |  |                 except TypeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							| 
									
										
										
										
											2022-07-08 18:52:26 -07:00
										 |  |  |         # BOOM! | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 12:59:00 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 18:45:22 +03:00
										 |  |  | @cpython_only | 
					
						
							|  |  |  | class CFunctionCallsErrorMessages(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs0(self): | 
					
						
							|  |  |  |         msg = r"__contains__\(\) takes exactly one argument \(0 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.__contains__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs2(self): | 
					
						
							|  |  |  |         msg = r"__contains__\(\) takes exactly one argument \(2 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.__contains__, 0, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 19:27:06 +03:00
										 |  |  |     def test_varargs3(self): | 
					
						
							| 
									
										
										
										
											2021-09-15 19:55:24 -07:00
										 |  |  |         msg = r"^from_bytes\(\) takes at most 2 positional arguments \(3 given\)" | 
					
						
							| 
									
										
										
										
											2017-06-09 19:27:06 +03:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, int.from_bytes, b'a', 'little', False) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 20:15:13 +05:30
										 |  |  |     def test_varargs1min(self): | 
					
						
							| 
									
										
										
										
											2023-08-28 16:04:27 +03:00
										 |  |  |         msg = (r"get\(\) takes at least 1 argument \(0 given\)|" | 
					
						
							|  |  |  |                r"get expected at least 1 argument, got 0") | 
					
						
							| 
									
										
										
										
											2018-07-23 01:43:26 +05:30
										 |  |  |         self.assertRaisesRegex(TypeError, msg, {}.get) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 20:15:13 +05:30
										 |  |  |         msg = r"expected 1 argument, got 0" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.__delattr__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs2min(self): | 
					
						
							| 
									
										
										
										
											2018-07-23 01:43:26 +05:30
										 |  |  |         msg = r"getattr expected at least 2 arguments, got 0" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, getattr) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 20:15:13 +05:30
										 |  |  |     def test_varargs1max(self): | 
					
						
							| 
									
										
										
										
											2023-08-28 16:04:27 +03:00
										 |  |  |         msg = (r"input\(\) takes at most 1 argument \(2 given\)|" | 
					
						
							|  |  |  |                r"input expected at most 1 argument, got 2") | 
					
						
							| 
									
										
										
										
											2018-07-23 01:43:26 +05:30
										 |  |  |         self.assertRaisesRegex(TypeError, msg, input, 1, 2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 20:15:13 +05:30
										 |  |  |     def test_varargs2max(self): | 
					
						
							| 
									
										
										
										
											2023-08-28 16:04:27 +03:00
										 |  |  |         msg = (r"get\(\) takes at most 2 arguments \(3 given\)|" | 
					
						
							|  |  |  |                r"get expected at most 2 arguments, got 3") | 
					
						
							| 
									
										
										
										
											2018-07-23 01:43:26 +05:30
										 |  |  |         self.assertRaisesRegex(TypeError, msg, {}.get, 1, 2, 3) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 18:45:22 +03:00
										 |  |  |     def test_varargs1_kw(self): | 
					
						
							|  |  |  |         msg = r"__contains__\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.__contains__, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs2_kw(self): | 
					
						
							|  |  |  |         msg = r"__contains__\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.__contains__, x=2, y=2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-10 06:51:48 +02:00
										 |  |  |     def test_varargs3_kw(self): | 
					
						
							|  |  |  |         msg = r"bool\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, bool, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs4_kw(self): | 
					
						
							| 
									
										
										
										
											2023-08-28 16:04:27 +03:00
										 |  |  |         msg = r"^(list[.])?index\(\) takes no keyword arguments$" | 
					
						
							| 
									
										
										
										
											2017-06-10 06:51:48 +02:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, [].index, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs5_kw(self): | 
					
						
							|  |  |  |         msg = r"^hasattr\(\) takes no keyword arguments$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, hasattr, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-15 17:05:23 +02:00
										 |  |  |     def test_varargs6_kw(self): | 
					
						
							|  |  |  |         msg = r"^getattr\(\) takes no keyword arguments$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, getattr, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs7_kw(self): | 
					
						
							|  |  |  |         msg = r"^next\(\) takes no keyword arguments$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, next, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs8_kw(self): | 
					
						
							| 
									
										
										
										
											2019-11-05 16:48:04 +01:00
										 |  |  |         msg = r"^_struct[.]pack\(\) takes no keyword arguments$" | 
					
						
							| 
									
										
										
										
											2017-06-15 17:05:23 +02:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, struct.pack, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs9_kw(self): | 
					
						
							| 
									
										
										
										
											2019-11-05 16:48:04 +01:00
										 |  |  |         msg = r"^_struct[.]pack_into\(\) takes no keyword arguments$" | 
					
						
							| 
									
										
										
										
											2017-06-15 17:05:23 +02:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, struct.pack_into, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs10_kw(self): | 
					
						
							| 
									
										
										
										
											2019-11-05 16:48:04 +01:00
										 |  |  |         msg = r"^deque[.]index\(\) takes no keyword arguments$" | 
					
						
							| 
									
										
										
										
											2017-06-15 17:05:23 +02:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, collections.deque().index, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs11_kw(self): | 
					
						
							| 
									
										
										
										
											2019-11-05 16:48:04 +01:00
										 |  |  |         msg = r"^Struct[.]pack\(\) takes no keyword arguments$" | 
					
						
							| 
									
										
										
										
											2017-06-15 17:05:23 +02:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, struct.Struct.pack, struct.Struct(""), x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-09 05:45:06 +02:00
										 |  |  |     def test_varargs12_kw(self): | 
					
						
							|  |  |  |         msg = r"^staticmethod\(\) takes no keyword arguments$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, staticmethod, func=id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs13_kw(self): | 
					
						
							|  |  |  |         msg = r"^classmethod\(\) takes no keyword arguments$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, classmethod, func=id) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 21:16:48 +03:00
										 |  |  |     def test_varargs14_kw(self): | 
					
						
							|  |  |  |         msg = r"^product\(\) takes at most 1 keyword argument \(2 given\)$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, | 
					
						
							|  |  |  |                                itertools.product, 0, repeat=1, foo=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs15_kw(self): | 
					
						
							| 
									
										
										
										
											2022-10-25 23:56:59 +01:00
										 |  |  |         msg = r"^ImportError\(\) takes at most 3 keyword arguments \(4 given\)$" | 
					
						
							| 
									
										
										
										
											2017-08-23 21:16:48 +03:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, | 
					
						
							| 
									
										
										
										
											2022-10-25 23:56:59 +01:00
										 |  |  |                                ImportError, 0, name=1, path=2, name_from=3, foo=3) | 
					
						
							| 
									
										
										
										
											2017-08-23 21:16:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs16_kw(self): | 
					
						
							|  |  |  |         msg = r"^min\(\) takes at most 2 keyword arguments \(3 given\)$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, | 
					
						
							|  |  |  |                                min, 0, default=1, key=2, foo=3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs17_kw(self): | 
					
						
							| 
									
										
										
										
											2024-02-08 01:04:41 -08:00
										 |  |  |         msg = r"print\(\) got an unexpected keyword argument 'foo'$" | 
					
						
							| 
									
										
										
										
											2017-08-23 21:16:48 +03:00
										 |  |  |         self.assertRaisesRegex(TypeError, msg, | 
					
						
							|  |  |  |                                print, 0, sep=1, end=2, file=3, flush=4, foo=5) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 07:40:36 +03:00
										 |  |  |     def test_varargs18_kw(self): | 
					
						
							| 
									
										
										
										
											2024-11-08 14:23:50 +02:00
										 |  |  |         # _PyArg_UnpackKeywords() with varpos | 
					
						
							| 
									
										
										
										
											2022-07-28 07:40:36 +03:00
										 |  |  |         msg = r"invalid keyword argument for print\(\)$" | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, msg): | 
					
						
							|  |  |  |             print(0, 1, **{BadStr('foo'): ','}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs19_kw(self): | 
					
						
							|  |  |  |         # _PyArg_UnpackKeywords() | 
					
						
							|  |  |  |         msg = r"invalid keyword argument for round\(\)$" | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, msg): | 
					
						
							|  |  |  |             round(1.75, **{BadStr('foo'): 1}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 18:45:22 +03:00
										 |  |  |     def test_oldargs0_1(self): | 
					
						
							|  |  |  |         msg = r"keys\(\) takes no arguments \(1 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.keys, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs0_2(self): | 
					
						
							|  |  |  |         msg = r"keys\(\) takes no arguments \(2 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.keys, 0, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs0_1_kw(self): | 
					
						
							|  |  |  |         msg = r"keys\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.keys, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs0_2_kw(self): | 
					
						
							|  |  |  |         msg = r"keys\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, {}.keys, x=2, y=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs1_0(self): | 
					
						
							|  |  |  |         msg = r"count\(\) takes exactly one argument \(0 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, [].count) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs1_2(self): | 
					
						
							|  |  |  |         msg = r"count\(\) takes exactly one argument \(2 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, [].count, 1, 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs1_0_kw(self): | 
					
						
							|  |  |  |         msg = r"count\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, [].count, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs1_1_kw(self): | 
					
						
							|  |  |  |         msg = r"count\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, [].count, {}, x=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_oldargs1_2_kw(self): | 
					
						
							|  |  |  |         msg = r"count\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, [].count, x=2, y=2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 15:07:42 -07:00
										 |  |  |     def test_object_not_callable(self): | 
					
						
							|  |  |  |         msg = r"^'object' object is not callable$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, object()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_module_not_callable_no_suggestion_0(self): | 
					
						
							|  |  |  |         msg = r"^'module' object is not callable$" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, types.ModuleType("mod")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_module_not_callable_no_suggestion_1(self): | 
					
						
							|  |  |  |         msg = r"^'module' object is not callable$" | 
					
						
							|  |  |  |         mod = types.ModuleType("mod") | 
					
						
							|  |  |  |         mod.mod = 42 | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, mod) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_module_not_callable_no_suggestion_2(self): | 
					
						
							|  |  |  |         msg = r"^'module' object is not callable$" | 
					
						
							|  |  |  |         mod = types.ModuleType("mod") | 
					
						
							|  |  |  |         del mod.__name__ | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, mod) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_module_not_callable_no_suggestion_3(self): | 
					
						
							|  |  |  |         msg = r"^'module' object is not callable$" | 
					
						
							|  |  |  |         mod = types.ModuleType("mod") | 
					
						
							|  |  |  |         mod.__name__ = 42 | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, mod) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_module_not_callable_suggestion(self): | 
					
						
							|  |  |  |         msg = r"^'module' object is not callable\. Did you mean: 'mod\.mod\(\.\.\.\)'\?$" | 
					
						
							|  |  |  |         mod = types.ModuleType("mod") | 
					
						
							|  |  |  |         mod.mod = lambda: ... | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, mod) | 
					
						
							| 
									
										
										
										
											2017-06-06 18:45:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  | @unittest.skipIf(_testcapi is None, "requires _testcapi") | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  | class TestCallingConventions(unittest.TestCase): | 
					
						
							|  |  |  |     """Test calling using various C calling conventions (METH_*) from Python
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Subclasses test several kinds of functions (module-level, methods, | 
					
						
							|  |  |  |     class methods static methods) using these attributes: | 
					
						
							|  |  |  |       obj: the object that contains tested functions (as attributes) | 
					
						
							|  |  |  |       expected_self: expected "self" argument to the C function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The base class tests module-level functions. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         self.obj = self.expected_self = _testcapi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_varargs(1, 2, 3), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2, 3)), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs_ext(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_varargs(*(1, 2, 3)), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2, 3)), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs_error_kw(self): | 
					
						
							|  |  |  |         msg = r"meth_varargs\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_varargs(k=1), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs_keywords(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_varargs_keywords(1, 2, a=3, b=4), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2), {'a': 3, 'b': 4}) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_varargs_keywords_ext(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_varargs_keywords(*[1, 2], **{'a': 3, 'b': 4}), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2), {'a': 3, 'b': 4}) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_o(self): | 
					
						
							|  |  |  |         self.assertEqual(self.obj.meth_o(1), (self.expected_self, 1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_o_ext(self): | 
					
						
							|  |  |  |         self.assertEqual(self.obj.meth_o(*[1]), (self.expected_self, 1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_o_error_no_arg(self): | 
					
						
							|  |  |  |         msg = r"meth_o\(\) takes exactly one argument \(0 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex(TypeError, msg, self.obj.meth_o) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_o_error_two_args(self): | 
					
						
							|  |  |  |         msg = r"meth_o\(\) takes exactly one argument \(2 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_o(1, 2), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_o_error_ext(self): | 
					
						
							|  |  |  |         msg = r"meth_o\(\) takes exactly one argument \(3 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_o(*(1, 2, 3)), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_o_error_kw(self): | 
					
						
							|  |  |  |         msg = r"meth_o\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_o(k=1), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_o_error_arg_kw(self): | 
					
						
							|  |  |  |         msg = r"meth_o\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_o(k=1), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_noargs(self): | 
					
						
							|  |  |  |         self.assertEqual(self.obj.meth_noargs(), self.expected_self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_noargs_ext(self): | 
					
						
							|  |  |  |         self.assertEqual(self.obj.meth_noargs(*[]), self.expected_self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_noargs_error_arg(self): | 
					
						
							|  |  |  |         msg = r"meth_noargs\(\) takes no arguments \(1 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_noargs(1), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_noargs_error_arg2(self): | 
					
						
							|  |  |  |         msg = r"meth_noargs\(\) takes no arguments \(2 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_noargs(1, 2), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_noargs_error_ext(self): | 
					
						
							|  |  |  |         msg = r"meth_noargs\(\) takes no arguments \(3 given\)" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_noargs(*(1, 2, 3)), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_noargs_error_kw(self): | 
					
						
							|  |  |  |         msg = r"meth_noargs\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_noargs(k=1), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_fastcall(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_fastcall(1, 2, 3), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2, 3)), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_fastcall_ext(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_fastcall(*(1, 2, 3)), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2, 3)), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_fastcall_error_kw(self): | 
					
						
							|  |  |  |         msg = r"meth_fastcall\(\) takes no keyword arguments" | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, msg, lambda: self.obj.meth_fastcall(k=1), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_fastcall_keywords(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_fastcall_keywords(1, 2, a=3, b=4), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2), {'a': 3, 'b': 4}) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_fastcall_keywords_ext(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             self.obj.meth_fastcall_keywords(*(1, 2), **{'a': 3, 'b': 4}), | 
					
						
							|  |  |  |             (self.expected_self, (1, 2), {'a': 3, 'b': 4}) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestCallingConventionsInstance(TestCallingConventions): | 
					
						
							|  |  |  |     """Test calling instance methods using various calling conventions""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         self.obj = self.expected_self = _testcapi.MethInstance() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestCallingConventionsClass(TestCallingConventions): | 
					
						
							|  |  |  |     """Test calling class methods using various calling conventions""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         self.obj = self.expected_self = _testcapi.MethClass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestCallingConventionsClassInstance(TestCallingConventions): | 
					
						
							|  |  |  |     """Test calling class methods on instance""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         self.obj = _testcapi.MethClass() | 
					
						
							|  |  |  |         self.expected_self = _testcapi.MethClass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestCallingConventionsStatic(TestCallingConventions): | 
					
						
							|  |  |  |     """Test calling static methods using various calling conventions""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         self.obj = _testcapi.MethStatic() | 
					
						
							|  |  |  |         self.expected_self = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | def pyfunc(arg1, arg2): | 
					
						
							|  |  |  |     return [arg1, arg2] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def pyfunc_noarg(): | 
					
						
							|  |  |  |     return "noarg" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PythonClass: | 
					
						
							|  |  |  |     def method(self, arg1, arg2): | 
					
						
							|  |  |  |         return [arg1, arg2] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def method_noarg(self): | 
					
						
							|  |  |  |         return "noarg" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def class_method(cls): | 
					
						
							|  |  |  |         return "classmethod" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def static_method(): | 
					
						
							|  |  |  |         return "staticmethod" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PYTHON_INSTANCE = PythonClass() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  | NULL_OR_EMPTY = object() | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | class FastCallTests(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  |     """Test calling using various callables from C
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |     # Test calls with positional arguments | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  |     CALLS_POSARGS = [ | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |         # (func, args: tuple, result) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Python function with 2 arguments | 
					
						
							|  |  |  |         (pyfunc, (1, 2), [1, 2]), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Python function without argument | 
					
						
							|  |  |  |         (pyfunc_noarg, (), "noarg"), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Python class methods | 
					
						
							|  |  |  |         (PythonClass.class_method, (), "classmethod"), | 
					
						
							|  |  |  |         (PythonClass.static_method, (), "staticmethod"), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Python instance methods | 
					
						
							|  |  |  |         (PYTHON_INSTANCE.method, (1, 2), [1, 2]), | 
					
						
							|  |  |  |         (PYTHON_INSTANCE.method_noarg, (), "noarg"), | 
					
						
							|  |  |  |         (PYTHON_INSTANCE.class_method, (), "classmethod"), | 
					
						
							|  |  |  |         (PYTHON_INSTANCE.static_method, (), "staticmethod"), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  |         # C callables are added later | 
					
						
							|  |  |  |     ] | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Test calls with positional and keyword arguments | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  |     CALLS_KWARGS = [ | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |         # (func, args: tuple, kwargs: dict, result) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Python function with 2 arguments | 
					
						
							|  |  |  |         (pyfunc, (1,), {'arg2': 2}, [1, 2]), | 
					
						
							|  |  |  |         (pyfunc, (), {'arg1': 1, 'arg2': 2}, [1, 2]), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Python instance methods | 
					
						
							|  |  |  |         (PYTHON_INSTANCE.method, (1,), {'arg2': 2}, [1, 2]), | 
					
						
							|  |  |  |         (PYTHON_INSTANCE.method, (), {'arg1': 1, 'arg2': 2}, [1, 2]), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  |         # C callables are added later | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Add all the calling conventions and variants of C callables | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  |     if _testcapi: | 
					
						
							|  |  |  |         _instance = _testcapi.MethInstance() | 
					
						
							|  |  |  |         for obj, expected_self in ( | 
					
						
							|  |  |  |             (_testcapi, _testcapi),  # module-level function | 
					
						
							|  |  |  |             (_instance, _instance),  # bound method | 
					
						
							|  |  |  |             (_testcapi.MethClass, _testcapi.MethClass),  # class method on class | 
					
						
							|  |  |  |             (_testcapi.MethClass(), _testcapi.MethClass),  # class method on inst. | 
					
						
							|  |  |  |             (_testcapi.MethStatic, None),  # static method | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             CALLS_POSARGS.extend([ | 
					
						
							|  |  |  |                 (obj.meth_varargs, (1, 2), (expected_self, (1, 2))), | 
					
						
							|  |  |  |                 (obj.meth_varargs_keywords, | 
					
						
							|  |  |  |                     (1, 2), (expected_self, (1, 2), NULL_OR_EMPTY)), | 
					
						
							|  |  |  |                 (obj.meth_fastcall, (1, 2), (expected_self, (1, 2))), | 
					
						
							|  |  |  |                 (obj.meth_fastcall, (), (expected_self, ())), | 
					
						
							|  |  |  |                 (obj.meth_fastcall_keywords, | 
					
						
							|  |  |  |                     (1, 2), (expected_self, (1, 2), NULL_OR_EMPTY)), | 
					
						
							|  |  |  |                 (obj.meth_fastcall_keywords, | 
					
						
							|  |  |  |                     (), (expected_self, (), NULL_OR_EMPTY)), | 
					
						
							|  |  |  |                 (obj.meth_noargs, (), expected_self), | 
					
						
							|  |  |  |                 (obj.meth_o, (123, ), (expected_self, 123)), | 
					
						
							|  |  |  |             ]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             CALLS_KWARGS.extend([ | 
					
						
							|  |  |  |                 (obj.meth_varargs_keywords, | 
					
						
							|  |  |  |                     (1, 2), {'x': 'y'}, (expected_self, (1, 2), {'x': 'y'})), | 
					
						
							|  |  |  |                 (obj.meth_varargs_keywords, | 
					
						
							|  |  |  |                     (), {'x': 'y'}, (expected_self, (), {'x': 'y'})), | 
					
						
							|  |  |  |                 (obj.meth_varargs_keywords, | 
					
						
							|  |  |  |                     (1, 2), {}, (expected_self, (1, 2), NULL_OR_EMPTY)), | 
					
						
							|  |  |  |                 (obj.meth_fastcall_keywords, | 
					
						
							|  |  |  |                     (1, 2), {'x': 'y'}, (expected_self, (1, 2), {'x': 'y'})), | 
					
						
							|  |  |  |                 (obj.meth_fastcall_keywords, | 
					
						
							|  |  |  |                     (), {'x': 'y'}, (expected_self, (), {'x': 'y'})), | 
					
						
							|  |  |  |                 (obj.meth_fastcall_keywords, | 
					
						
							|  |  |  |                     (1, 2), {}, (expected_self, (1, 2), NULL_OR_EMPTY)), | 
					
						
							|  |  |  |             ]) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def check_result(self, result, expected): | 
					
						
							| 
									
										
										
										
											2019-09-10 12:21:09 +01:00
										 |  |  |         if isinstance(expected, tuple) and expected[-1] is NULL_OR_EMPTY: | 
					
						
							|  |  |  |             if result[-1] in ({}, None): | 
					
						
							|  |  |  |                 expected = (*expected[:-1], result[-1]) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |         self.assertEqual(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  |     @unittest.skipIf(_testcapi is None, "requires _testcapi") | 
					
						
							| 
									
										
										
										
											2019-05-29 20:31:52 +02:00
										 |  |  |     def test_vectorcall_dict(self): | 
					
						
							| 
									
										
										
										
											2020-02-11 17:46:57 +01:00
										 |  |  |         # Test PyObject_VectorcallDict() | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for func, args, expected in self.CALLS_POSARGS: | 
					
						
							|  |  |  |             with self.subTest(func=func, args=args): | 
					
						
							|  |  |  |                 # kwargs=NULL | 
					
						
							|  |  |  |                 result = _testcapi.pyobject_fastcalldict(func, args, None) | 
					
						
							|  |  |  |                 self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if not args: | 
					
						
							|  |  |  |                     # args=NULL, nargs=0, kwargs=NULL | 
					
						
							|  |  |  |                     result = _testcapi.pyobject_fastcalldict(func, None, None) | 
					
						
							|  |  |  |                     self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for func, args, kwargs, expected in self.CALLS_KWARGS: | 
					
						
							|  |  |  |             with self.subTest(func=func, args=args, kwargs=kwargs): | 
					
						
							|  |  |  |                 result = _testcapi.pyobject_fastcalldict(func, args, kwargs) | 
					
						
							|  |  |  |                 self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  |     @unittest.skipIf(_testcapi is None, "requires _testcapi") | 
					
						
							| 
									
										
										
										
											2019-05-29 20:31:52 +02:00
										 |  |  |     def test_vectorcall(self): | 
					
						
							| 
									
										
										
										
											2020-02-11 17:46:57 +01:00
										 |  |  |         # Test PyObject_Vectorcall() | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for func, args, expected in self.CALLS_POSARGS: | 
					
						
							|  |  |  |             with self.subTest(func=func, args=args): | 
					
						
							|  |  |  |                 # kwnames=NULL | 
					
						
							| 
									
										
										
										
											2019-05-29 20:31:52 +02:00
										 |  |  |                 result = _testcapi.pyobject_vectorcall(func, args, None) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |                 self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # kwnames=() | 
					
						
							| 
									
										
										
										
											2019-05-29 20:31:52 +02:00
										 |  |  |                 result = _testcapi.pyobject_vectorcall(func, args, ()) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |                 self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if not args: | 
					
						
							|  |  |  |                     # kwnames=NULL | 
					
						
							| 
									
										
										
										
											2019-05-29 20:31:52 +02:00
										 |  |  |                     result = _testcapi.pyobject_vectorcall(func, None, None) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |                     self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     # kwnames=() | 
					
						
							| 
									
										
										
										
											2019-05-29 20:31:52 +02:00
										 |  |  |                     result = _testcapi.pyobject_vectorcall(func, None, ()) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |                     self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for func, args, kwargs, expected in self.CALLS_KWARGS: | 
					
						
							|  |  |  |             with self.subTest(func=func, args=args, kwargs=kwargs): | 
					
						
							|  |  |  |                 kwnames = tuple(kwargs.keys()) | 
					
						
							|  |  |  |                 args = args + tuple(kwargs.values()) | 
					
						
							| 
									
										
										
										
											2019-05-29 20:31:52 +02:00
										 |  |  |                 result = _testcapi.pyobject_vectorcall(func, args, kwnames) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  |                 self.check_result(result, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-22 13:09:35 +02:00
										 |  |  |     def test_fastcall_clearing_dict(self): | 
					
						
							|  |  |  |         # Test bpo-36907: the point of the test is just checking that this | 
					
						
							|  |  |  |         # does not crash. | 
					
						
							|  |  |  |         class IntWithDict: | 
					
						
							|  |  |  |             __slots__ = ["kwargs"] | 
					
						
							|  |  |  |             def __init__(self, **kwargs): | 
					
						
							|  |  |  |                 self.kwargs = kwargs | 
					
						
							|  |  |  |             def __index__(self): | 
					
						
							|  |  |  |                 self.kwargs.clear() | 
					
						
							|  |  |  |                 gc.collect() | 
					
						
							|  |  |  |                 return 0 | 
					
						
							| 
									
										
										
										
											2022-12-04 14:28:56 +02:00
										 |  |  |         x = IntWithDict(optimize=IntWithDict()) | 
					
						
							| 
									
										
										
										
											2019-05-22 13:09:35 +02:00
										 |  |  |         # We test the argument handling of "compile" here, the compilation | 
					
						
							|  |  |  |         # itself is not relevant. When we pass flags=x below, x.__index__() is | 
					
						
							|  |  |  |         # called, which changes the keywords dict. | 
					
						
							|  |  |  |         compile("pass", "", "exec", x, **x.kwargs) | 
					
						
							| 
									
										
										
										
											2017-06-09 16:48:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Py_TPFLAGS_HAVE_VECTORCALL = 1 << 11 | 
					
						
							|  |  |  | Py_TPFLAGS_METHOD_DESCRIPTOR = 1 << 17 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def testfunction(self): | 
					
						
							|  |  |  |     """some doc""" | 
					
						
							|  |  |  |     return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def testfunction_kw(self, *, kw): | 
					
						
							|  |  |  |     """some doc""" | 
					
						
							|  |  |  |     return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  | @unittest.skipIf(_testcapi is None, "requires _testcapi") | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  | class TestPEP590(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_method_descriptor_flag(self): | 
					
						
							|  |  |  |         import functools | 
					
						
							|  |  |  |         cached = functools.lru_cache(1)(testfunction) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertFalse(type(repr).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  |         self.assertTrue(type(list.append).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  |         self.assertTrue(type(list.__add__).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  |         self.assertTrue(type(testfunction).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  |         self.assertTrue(type(cached).__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  |         self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  |         self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-08 12:48:01 +02:00
										 |  |  |         # Mutable heap types should not inherit Py_TPFLAGS_METHOD_DESCRIPTOR | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |         class MethodDescriptorHeap(_testcapi.MethodDescriptorBase): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_vectorcall_flag(self): | 
					
						
							|  |  |  |         self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) | 
					
						
							|  |  |  |         self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) | 
					
						
							|  |  |  |         self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) | 
					
						
							|  |  |  |         self.assertTrue(_testcapi.MethodDescriptor2.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 17:19:29 +02:00
										 |  |  |         # Mutable heap types should inherit Py_TPFLAGS_HAVE_VECTORCALL, | 
					
						
							|  |  |  |         # but should lose it when __call__ is overridden | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |         class MethodDescriptorHeap(_testcapi.MethodDescriptorBase): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2022-08-04 17:19:29 +02:00
										 |  |  |         self.assertTrue(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) | 
					
						
							|  |  |  |         MethodDescriptorHeap.__call__ = print | 
					
						
							|  |  |  |         self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Mutable heap types should not inherit Py_TPFLAGS_HAVE_VECTORCALL if | 
					
						
							|  |  |  |         # they define __call__ directly | 
					
						
							|  |  |  |         class MethodDescriptorHeap(_testcapi.MethodDescriptorBase): | 
					
						
							|  |  |  |             def __call__(self): | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |         self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_vectorcall_override(self): | 
					
						
							|  |  |  |         # Check that tp_call can correctly override vectorcall. | 
					
						
							|  |  |  |         # MethodDescriptorNopGet implements tp_call but it inherits from | 
					
						
							|  |  |  |         # MethodDescriptorBase, which implements vectorcall. Since | 
					
						
							|  |  |  |         # MethodDescriptorNopGet returns the args tuple when called, we check | 
					
						
							|  |  |  |         # additionally that no new tuple is created for this call. | 
					
						
							|  |  |  |         args = tuple(range(5)) | 
					
						
							|  |  |  |         f = _testcapi.MethodDescriptorNopGet() | 
					
						
							|  |  |  |         self.assertIs(f(*args), args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 17:19:29 +02:00
										 |  |  |     def test_vectorcall_override_on_mutable_class(self): | 
					
						
							|  |  |  |         """Setting __call__ should disable vectorcall""" | 
					
						
							|  |  |  |         TestType = _testcapi.make_vectorcall_class() | 
					
						
							|  |  |  |         instance = TestType() | 
					
						
							|  |  |  |         self.assertEqual(instance(), "tp_call") | 
					
						
							|  |  |  |         instance.set_vectorcall(TestType) | 
					
						
							|  |  |  |         self.assertEqual(instance(), "vectorcall")  # assume vectorcall is used | 
					
						
							|  |  |  |         TestType.__call__ = lambda self: "custom" | 
					
						
							|  |  |  |         self.assertEqual(instance(), "custom") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_vectorcall_override_with_subclass(self): | 
					
						
							|  |  |  |         """Setting __call__ on a superclass should disable vectorcall""" | 
					
						
							|  |  |  |         SuperType = _testcapi.make_vectorcall_class() | 
					
						
							|  |  |  |         class DerivedType(SuperType): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         instance = DerivedType() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Derived types with its own vectorcall should be unaffected | 
					
						
							|  |  |  |         UnaffectedType1 = _testcapi.make_vectorcall_class(DerivedType) | 
					
						
							|  |  |  |         UnaffectedType2 = _testcapi.make_vectorcall_class(SuperType) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Aside: Quickly check that the C helper actually made derived types | 
					
						
							|  |  |  |         self.assertTrue(issubclass(UnaffectedType1, DerivedType)) | 
					
						
							|  |  |  |         self.assertTrue(issubclass(UnaffectedType2, SuperType)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Initial state: tp_call | 
					
						
							|  |  |  |         self.assertEqual(instance(), "tp_call") | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(SuperType), True) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(DerivedType), True) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(UnaffectedType1), True) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(UnaffectedType2), True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Setting the vectorcall function | 
					
						
							|  |  |  |         instance.set_vectorcall(SuperType) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(instance(), "vectorcall") | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(SuperType), True) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(DerivedType), True) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(UnaffectedType1), True) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(UnaffectedType2), True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Setting __call__ should remove vectorcall from all subclasses | 
					
						
							|  |  |  |         SuperType.__call__ = lambda self: "custom" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(instance(), "custom") | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(SuperType), False) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(DerivedType), False) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(UnaffectedType1), True) | 
					
						
							|  |  |  |         self.assertEqual(_testcapi.has_vectorcall_flag(UnaffectedType2), True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |     def test_vectorcall(self): | 
					
						
							|  |  |  |         # Test a bunch of different ways to call objects: | 
					
						
							|  |  |  |         # 1. vectorcall using PyVectorcall_Call() | 
					
						
							|  |  |  |         #   (only for objects that support vectorcall directly) | 
					
						
							|  |  |  |         # 2. normal call | 
					
						
							| 
									
										
										
										
											2020-02-11 17:46:57 +01:00
										 |  |  |         # 3. vectorcall using PyObject_Vectorcall() | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |         # 4. call as bound method | 
					
						
							|  |  |  |         # 5. call using functools.partial | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # A list of (function, args, kwargs, result) calls to test | 
					
						
							|  |  |  |         calls = [(len, (range(42),), {}, 42), | 
					
						
							|  |  |  |                  (list.append, ([], 0), {}, None), | 
					
						
							|  |  |  |                  ([].append, (0,), {}, None), | 
					
						
							|  |  |  |                  (sum, ([36],), {"start":6}, 42), | 
					
						
							|  |  |  |                  (testfunction, (42,), {}, 42), | 
					
						
							|  |  |  |                  (testfunction_kw, (42,), {"kw":None}, 42), | 
					
						
							|  |  |  |                  (_testcapi.MethodDescriptorBase(), (0,), {}, True), | 
					
						
							|  |  |  |                  (_testcapi.MethodDescriptorDerived(), (0,), {}, True), | 
					
						
							|  |  |  |                  (_testcapi.MethodDescriptor2(), (0,), {}, False)] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         from _testcapi import pyobject_vectorcall, pyvectorcall_call | 
					
						
							|  |  |  |         from types import MethodType | 
					
						
							|  |  |  |         from functools import partial | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def vectorcall(func, args, kwargs): | 
					
						
							|  |  |  |             args = *args, *kwargs.values() | 
					
						
							|  |  |  |             kwnames = tuple(kwargs) | 
					
						
							|  |  |  |             return pyobject_vectorcall(func, args, kwnames) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (func, args, kwargs, expected) in calls: | 
					
						
							|  |  |  |             with self.subTest(str(func)): | 
					
						
							|  |  |  |                 if not kwargs: | 
					
						
							|  |  |  |                     self.assertEqual(expected, pyvectorcall_call(func, args)) | 
					
						
							|  |  |  |                 self.assertEqual(expected, pyvectorcall_call(func, args, kwargs)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Add derived classes (which do not support vectorcall directly, | 
					
						
							|  |  |  |         # but do support all other ways of calling). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class MethodDescriptorHeap(_testcapi.MethodDescriptorBase): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class MethodDescriptorOverridden(_testcapi.MethodDescriptorBase): | 
					
						
							|  |  |  |             def __call__(self, n): | 
					
						
							|  |  |  |                 return 'new' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 12:41:05 +02:00
										 |  |  |         class SuperBase: | 
					
						
							|  |  |  |             def __call__(self, *args): | 
					
						
							|  |  |  |                 return super().__call__(*args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class MethodDescriptorSuper(SuperBase, _testcapi.MethodDescriptorBase): | 
					
						
							|  |  |  |             def __call__(self, *args): | 
					
						
							|  |  |  |                 return super().__call__(*args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |         calls += [ | 
					
						
							| 
									
										
										
										
											2019-07-05 14:48:24 +02:00
										 |  |  |             (dict.update, ({},), {"key":True}, None), | 
					
						
							|  |  |  |             ({}.update, ({},), {"key":True}, None), | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |             (MethodDescriptorHeap(), (0,), {}, True), | 
					
						
							|  |  |  |             (MethodDescriptorOverridden(), (0,), {}, 'new'), | 
					
						
							| 
									
										
										
										
											2019-06-24 12:41:05 +02:00
										 |  |  |             (MethodDescriptorSuper(), (0,), {}, True), | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (func, args, kwargs, expected) in calls: | 
					
						
							|  |  |  |             with self.subTest(str(func)): | 
					
						
							|  |  |  |                 args1 = args[1:] | 
					
						
							|  |  |  |                 meth = MethodType(func, args[0]) | 
					
						
							|  |  |  |                 wrapped = partial(func) | 
					
						
							|  |  |  |                 if not kwargs: | 
					
						
							|  |  |  |                     self.assertEqual(expected, func(*args)) | 
					
						
							|  |  |  |                     self.assertEqual(expected, pyobject_vectorcall(func, args, None)) | 
					
						
							|  |  |  |                     self.assertEqual(expected, meth(*args1)) | 
					
						
							|  |  |  |                     self.assertEqual(expected, wrapped(*args)) | 
					
						
							|  |  |  |                 self.assertEqual(expected, func(*args, **kwargs)) | 
					
						
							|  |  |  |                 self.assertEqual(expected, vectorcall(func, args, kwargs)) | 
					
						
							|  |  |  |                 self.assertEqual(expected, meth(*args1, **kwargs)) | 
					
						
							|  |  |  |                 self.assertEqual(expected, wrapped(*args, **kwargs)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  |     def test_setvectorcall(self): | 
					
						
							|  |  |  |         from _testcapi import function_setvectorcall | 
					
						
							| 
									
										
										
										
											2025-01-29 10:49:58 -08:00
										 |  |  |         _testinternalcapi = import_helper.import_module("_testinternalcapi") | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  |         def f(num): return num + 1 | 
					
						
							|  |  |  |         assert_equal = self.assertEqual | 
					
						
							|  |  |  |         num = 10 | 
					
						
							|  |  |  |         assert_equal(11, f(num)) | 
					
						
							|  |  |  |         function_setvectorcall(f) | 
					
						
							| 
									
										
										
										
											2025-01-29 10:49:58 -08:00
										 |  |  |         for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  |             assert_equal("overridden", f(num)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_setvectorcall_load_attr_specialization_skip(self): | 
					
						
							|  |  |  |         from _testcapi import function_setvectorcall | 
					
						
							| 
									
										
										
										
											2025-01-29 10:49:58 -08:00
										 |  |  |         _testinternalcapi = import_helper.import_module("_testinternalcapi") | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         class X: | 
					
						
							|  |  |  |             def __getattribute__(self, attr): | 
					
						
							|  |  |  |                 return attr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert_equal = self.assertEqual | 
					
						
							|  |  |  |         x = X() | 
					
						
							|  |  |  |         assert_equal("a", x.a) | 
					
						
							|  |  |  |         function_setvectorcall(X.__getattribute__) | 
					
						
							|  |  |  |         # make sure specialization doesn't trigger | 
					
						
							|  |  |  |         # when vectorcall is overridden | 
					
						
							| 
									
										
										
										
											2025-01-29 10:49:58 -08:00
										 |  |  |         for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  |             assert_equal("overridden", x.a) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_setvectorcall_load_attr_specialization_deopt(self): | 
					
						
							|  |  |  |         from _testcapi import function_setvectorcall | 
					
						
							| 
									
										
										
										
											2025-01-29 10:49:58 -08:00
										 |  |  |         _testinternalcapi = import_helper.import_module("_testinternalcapi") | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         class X: | 
					
						
							|  |  |  |             def __getattribute__(self, attr): | 
					
						
							|  |  |  |                 return attr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def get_a(x): | 
					
						
							|  |  |  |             return x.a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert_equal = self.assertEqual | 
					
						
							|  |  |  |         x = X() | 
					
						
							|  |  |  |         # trigger LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN specialization | 
					
						
							| 
									
										
										
										
											2025-01-29 10:49:58 -08:00
										 |  |  |         for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  |             assert_equal("a", get_a(x)) | 
					
						
							|  |  |  |         function_setvectorcall(X.__getattribute__) | 
					
						
							|  |  |  |         # make sure specialized LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN | 
					
						
							|  |  |  |         # gets deopted due to overridden vectorcall | 
					
						
							| 
									
										
										
										
											2025-01-29 10:49:58 -08:00
										 |  |  |         for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2022-09-15 08:42:37 -07:00
										 |  |  |             assert_equal("overridden", get_a(x)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 13:48:43 +02:00
										 |  |  |     @requires_limited_api | 
					
						
							| 
									
										
										
										
											2022-10-27 11:45:42 +02:00
										 |  |  |     def test_vectorcall_limited_incoming(self): | 
					
						
							| 
									
										
										
										
											2022-08-08 14:12:05 +02:00
										 |  |  |         from _testcapi import pyobject_vectorcall | 
					
						
							| 
									
										
										
										
											2024-09-05 14:14:05 +02:00
										 |  |  |         for cls in (_testlimitedcapi.LimitedVectorCallClass, | 
					
						
							|  |  |  |                     _testlimitedcapi.LimitedRelativeVectorCallClass): | 
					
						
							|  |  |  |             with self.subTest(cls=cls): | 
					
						
							|  |  |  |                 obj = cls() | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							|  |  |  |                     pyobject_vectorcall(obj, (), ()), | 
					
						
							|  |  |  |                     "vectorcall called") | 
					
						
							| 
									
										
										
										
											2022-08-08 14:12:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-27 11:45:42 +02:00
										 |  |  |     @requires_limited_api | 
					
						
							|  |  |  |     def test_vectorcall_limited_outgoing(self): | 
					
						
							| 
									
										
										
										
											2024-03-07 19:31:12 +01:00
										 |  |  |         from _testlimitedcapi import call_vectorcall | 
					
						
							| 
									
										
										
										
											2022-10-27 11:45:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         args_captured = [] | 
					
						
							|  |  |  |         kwargs_captured = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(*args, **kwargs): | 
					
						
							|  |  |  |             args_captured.append(args) | 
					
						
							|  |  |  |             kwargs_captured.append(kwargs) | 
					
						
							|  |  |  |             return "success" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(call_vectorcall(f), "success") | 
					
						
							|  |  |  |         self.assertEqual(args_captured, [("foo",)]) | 
					
						
							|  |  |  |         self.assertEqual(kwargs_captured, [{"baz": "bar"}]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @requires_limited_api | 
					
						
							|  |  |  |     def test_vectorcall_limited_outgoing_method(self): | 
					
						
							| 
									
										
										
										
											2024-03-07 19:31:12 +01:00
										 |  |  |         from _testlimitedcapi import call_vectorcall_method | 
					
						
							| 
									
										
										
										
											2022-10-27 11:45:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         args_captured = [] | 
					
						
							|  |  |  |         kwargs_captured = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class TestInstance: | 
					
						
							|  |  |  |             def f(self, *args, **kwargs): | 
					
						
							|  |  |  |                 args_captured.append(args) | 
					
						
							|  |  |  |                 kwargs_captured.append(kwargs) | 
					
						
							|  |  |  |                 return "success" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(call_vectorcall_method(TestInstance()), "success") | 
					
						
							|  |  |  |         self.assertEqual(args_captured, [("foo",)]) | 
					
						
							|  |  |  |         self.assertEqual(kwargs_captured, [{"baz": "bar"}]) | 
					
						
							| 
									
										
										
										
											2019-06-07 17:51:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-22 16:40:17 -04:00
										 |  |  | class A: | 
					
						
							|  |  |  |     def method_two_args(self, x, y): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def static_no_args(): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def positional_only(arg, /): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @cpython_only | 
					
						
							|  |  |  | class TestErrorMessagesUseQualifiedName(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextlib.contextmanager | 
					
						
							|  |  |  |     def check_raises_type_error(self, message): | 
					
						
							|  |  |  |         with self.assertRaises(TypeError) as cm: | 
					
						
							|  |  |  |             yield | 
					
						
							|  |  |  |         self.assertEqual(str(cm.exception), message) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_missing_arguments(self): | 
					
						
							|  |  |  |         msg = "A.method_two_args() missing 1 required positional argument: 'y'" | 
					
						
							|  |  |  |         with self.check_raises_type_error(msg): | 
					
						
							|  |  |  |             A().method_two_args("x") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_too_many_positional(self): | 
					
						
							|  |  |  |         msg = "A.static_no_args() takes 0 positional arguments but 1 was given" | 
					
						
							|  |  |  |         with self.check_raises_type_error(msg): | 
					
						
							|  |  |  |             A.static_no_args("oops it's an arg") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_positional_only_passed_as_keyword(self): | 
					
						
							|  |  |  |         msg = "A.positional_only() got some positional-only arguments passed as keyword arguments: 'arg'" | 
					
						
							|  |  |  |         with self.check_raises_type_error(msg): | 
					
						
							|  |  |  |             A.positional_only(arg="x") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_unexpected_keyword(self): | 
					
						
							|  |  |  |         msg = "A.method_two_args() got an unexpected keyword argument 'bad'" | 
					
						
							|  |  |  |         with self.check_raises_type_error(msg): | 
					
						
							|  |  |  |             A().method_two_args(bad="x") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_multiple_values(self): | 
					
						
							|  |  |  |         msg = "A.method_two_args() got multiple values for argument 'x'" | 
					
						
							|  |  |  |         with self.check_raises_type_error(msg): | 
					
						
							|  |  |  |             A().method_two_args("x", "y", x="oops") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-17 19:39:42 +01:00
										 |  |  | @cpython_only | 
					
						
							|  |  |  | class TestErrorMessagesSuggestions(unittest.TestCase): | 
					
						
							|  |  |  |     @contextlib.contextmanager | 
					
						
							|  |  |  |     def check_suggestion_includes(self, message): | 
					
						
							|  |  |  |         with self.assertRaises(TypeError) as cm: | 
					
						
							|  |  |  |             yield | 
					
						
							|  |  |  |         self.assertIn(f"Did you mean '{message}'?", str(cm.exception)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextlib.contextmanager | 
					
						
							| 
									
										
										
										
											2024-02-08 01:04:41 -08:00
										 |  |  |     def check_suggestion_not_present(self): | 
					
						
							| 
									
										
										
										
											2023-08-17 19:39:42 +01:00
										 |  |  |         with self.assertRaises(TypeError) as cm: | 
					
						
							|  |  |  |             yield | 
					
						
							|  |  |  |         self.assertNotIn("Did you mean", str(cm.exception)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_unexpected_keyword_suggestion_valid_positions(self): | 
					
						
							|  |  |  |         def foo(blech=None, /, aaa=None, *args, late1=None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         cases = [ | 
					
						
							|  |  |  |             ("blach", None), | 
					
						
							|  |  |  |             ("aa", "aaa"), | 
					
						
							|  |  |  |             ("orgs", None), | 
					
						
							|  |  |  |             ("late11", "late1"), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for keyword, suggestion in cases: | 
					
						
							|  |  |  |             with self.subTest(keyword): | 
					
						
							| 
									
										
										
										
											2024-02-08 01:04:41 -08:00
										 |  |  |                 ctx = self.check_suggestion_includes(suggestion) if suggestion else self.check_suggestion_not_present() | 
					
						
							| 
									
										
										
										
											2023-08-17 19:39:42 +01:00
										 |  |  |                 with ctx: | 
					
						
							|  |  |  |                     foo(**{keyword:None}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_unexpected_keyword_suggestion_kinds(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def substitution(noise=None, more_noise=None, a = None, blech = None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def elimination(noise = None, more_noise = None, a = None, blch = None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def addition(noise = None, more_noise = None, a = None, bluchin = None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def substitution_over_elimination(blach = None, bluc = None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def substitution_over_addition(blach = None, bluchi = None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def elimination_over_addition(bluc = None, blucha = None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def case_change_over_substitution(BLuch=None, Luch = None, fluch = None): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for func, suggestion in [ | 
					
						
							|  |  |  |             (addition, "bluchin"), | 
					
						
							|  |  |  |             (substitution, "blech"), | 
					
						
							|  |  |  |             (elimination, "blch"), | 
					
						
							|  |  |  |             (addition, "bluchin"), | 
					
						
							|  |  |  |             (substitution_over_elimination, "blach"), | 
					
						
							|  |  |  |             (substitution_over_addition, "blach"), | 
					
						
							|  |  |  |             (elimination_over_addition, "bluc"), | 
					
						
							|  |  |  |             (case_change_over_substitution, "BLuch"), | 
					
						
							|  |  |  |         ]: | 
					
						
							|  |  |  |             with self.subTest(suggestion): | 
					
						
							|  |  |  |                 with self.check_suggestion_includes(suggestion): | 
					
						
							|  |  |  |                     func(bluch=None) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-08 01:04:41 -08:00
										 |  |  |     def test_unexpected_keyword_suggestion_via_getargs(self): | 
					
						
							|  |  |  |         with self.check_suggestion_includes("maxsplit"): | 
					
						
							|  |  |  |             "foo".split(maxsplt=1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, r"split\(\) got an unexpected keyword argument 'blech'$", | 
					
						
							|  |  |  |             "foo".split, blech=1 | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         with self.check_suggestion_not_present(): | 
					
						
							|  |  |  |             "foo".split(blech=1) | 
					
						
							|  |  |  |         with self.check_suggestion_not_present(): | 
					
						
							|  |  |  |             "foo".split(more_noise=1, maxsplt=1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Also test the vgetargskeywords path | 
					
						
							|  |  |  |         with self.check_suggestion_includes("name"): | 
					
						
							|  |  |  |             ImportError(namez="oops") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, r"ImportError\(\) got an unexpected keyword argument 'blech'$", | 
					
						
							|  |  |  |             ImportError, blech=1 | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         with self.check_suggestion_not_present(): | 
					
						
							|  |  |  |             ImportError(blech=1) | 
					
						
							|  |  |  |         with self.check_suggestion_not_present(): | 
					
						
							|  |  |  |             ImportError(blech=1, namez="oops") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 01:34:03 +01:00
										 |  |  | @cpython_only | 
					
						
							|  |  |  | class TestRecursion(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 10:10:29 +01:00
										 |  |  |     @skip_on_s390x | 
					
						
							| 
									
										
										
										
											2024-01-12 16:29:16 -08:00
										 |  |  |     @unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack") | 
					
						
							| 
									
										
										
										
											2025-02-06 17:03:01 -05:00
										 |  |  |     @skip_if_sanitizer("requires deep stack", thread=True) | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  |     @unittest.skipIf(_testcapi is None, "requires _testcapi") | 
					
						
							| 
									
										
										
										
											2024-12-05 01:26:25 +01:00
										 |  |  |     @skip_emscripten_stack_overflow() | 
					
						
							| 
									
										
										
										
											2025-02-25 09:24:48 +00:00
										 |  |  |     @skip_wasi_stack_overflow() | 
					
						
							| 
									
										
										
										
											2022-10-05 01:34:03 +01:00
										 |  |  |     def test_super_deep(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def recurse(n): | 
					
						
							|  |  |  |             if n: | 
					
						
							|  |  |  |                 recurse(n-1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def py_recurse(n, m): | 
					
						
							|  |  |  |             if n: | 
					
						
							|  |  |  |                 py_recurse(n-1, m) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 c_py_recurse(m-1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def c_recurse(n): | 
					
						
							|  |  |  |             if n: | 
					
						
							| 
									
										
										
										
											2023-06-30 11:46:43 +02:00
										 |  |  |                 _testcapi.pyobject_vectorcall(c_recurse, (n-1,), ()) | 
					
						
							| 
									
										
										
										
											2022-10-05 01:34:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def c_py_recurse(m): | 
					
						
							|  |  |  |             if m: | 
					
						
							| 
									
										
										
										
											2023-06-30 11:46:43 +02:00
										 |  |  |                 _testcapi.pyobject_vectorcall(py_recurse, (1000, m), ()) | 
					
						
							| 
									
										
										
										
											2022-10-05 01:34:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-12 16:29:16 -08:00
										 |  |  |         with set_recursion_limit(100_000): | 
					
						
							| 
									
										
										
										
											2022-10-05 01:34:03 +01:00
										 |  |  |             recurse(90_000) | 
					
						
							|  |  |  |             with self.assertRaises(RecursionError): | 
					
						
							|  |  |  |                 recurse(101_000) | 
					
						
							| 
									
										
										
										
											2025-02-25 09:24:48 +00:00
										 |  |  |             c_recurse(50) | 
					
						
							| 
									
										
										
										
											2022-10-05 01:34:03 +01:00
										 |  |  |             with self.assertRaises(RecursionError): | 
					
						
							|  |  |  |                 c_recurse(90_000) | 
					
						
							| 
									
										
										
										
											2025-02-25 09:24:48 +00:00
										 |  |  |             c_py_recurse(50) | 
					
						
							| 
									
										
										
										
											2022-10-05 01:34:03 +01:00
										 |  |  |             with self.assertRaises(RecursionError): | 
					
						
							|  |  |  |                 c_py_recurse(100_000) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 11:25:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-23 20:10:10 +00:00
										 |  |  | class TestFunctionWithManyArgs(unittest.TestCase): | 
					
						
							|  |  |  |     def test_function_with_many_args(self): | 
					
						
							|  |  |  |         for N in (10, 500, 1000): | 
					
						
							|  |  |  |             with self.subTest(N=N): | 
					
						
							|  |  |  |                 args = ",".join([f"a{i}" for i in range(N)]) | 
					
						
							|  |  |  |                 src = f"def f({args}) : return a{N//2}" | 
					
						
							|  |  |  |                 l = {} | 
					
						
							|  |  |  |                 exec(src, {}, l) | 
					
						
							|  |  |  |                 self.assertEqual(l['f'](*range(N)), N//2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-22 16:40:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 11:25:55 +02:00
										 |  |  | @unittest.skipIf(_testcapi is None, 'need _testcapi') | 
					
						
							|  |  |  | class TestCAPI(unittest.TestCase): | 
					
						
							|  |  |  |     def test_cfunction_call(self): | 
					
						
							|  |  |  |         def func(*args, **kwargs): | 
					
						
							|  |  |  |             return (args, kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # PyCFunction_Call() was removed in Python 3.13 API, but was kept in | 
					
						
							|  |  |  |         # the stable ABI. | 
					
						
							|  |  |  |         def PyCFunction_Call(func, *args, **kwargs): | 
					
						
							|  |  |  |             if kwargs: | 
					
						
							|  |  |  |                 return _testcapi.pycfunction_call(func, args, kwargs) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return _testcapi.pycfunction_call(func, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(PyCFunction_Call(func), ((), {})) | 
					
						
							|  |  |  |         self.assertEqual(PyCFunction_Call(func, 1, 2, 3), ((1, 2, 3), {})) | 
					
						
							|  |  |  |         self.assertEqual(PyCFunction_Call(func, "arg", num=5), (("arg",), {'num': 5})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-20 21:33:42 +00:00
										 |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2015-04-13 15:00:43 -05:00
										 |  |  |     unittest.main() |