1
2 """Doctest for method/function calls.
3
4 We're going the use these types for extra testing
5
6 >>> from collections import UserList
7 >>> from collections import UserDict
8
9 We're defining four helper functions
10
11 >>> from test import support
12 >>> def e(a,b):
13 ... print(a, b)
14
15 >>> def f(*a, **k):
16 ... print(a, support.sortdict(k))
17
18 >>> def g(x, *y, **z):
19 ... print(x, y, support.sortdict(z))
20
21 >>> def h(j=1, a=2, h=3):
22 ... print(j, a, h)
23
24 Argument list examples
25
26 >>> f()
27 () {}
28 >>> f(1)
29 (1,) {}
30 >>> f(1, 2)
31 (1, 2) {}
32 >>> f(1, 2, 3)
33 (1, 2, 3) {}
34 >>> f(1, 2, 3, *(4, 5))
35 (1, 2, 3, 4, 5) {}
36 >>> f(1, 2, 3, *[4, 5])
37 (1, 2, 3, 4, 5) {}
38 >>> f(*[1, 2, 3], 4, 5)
39 (1, 2, 3, 4, 5) {}
40 >>> f(1, 2, 3, *UserList([4, 5]))
41 (1, 2, 3, 4, 5) {}
42 >>> f(1, 2, 3, *[4, 5], *[6, 7])
43 (1, 2, 3, 4, 5, 6, 7) {}
44 >>> f(1, *[2, 3], 4, *[5, 6], 7)
45 (1, 2, 3, 4, 5, 6, 7) {}
46 >>> f(*UserList([1, 2]), *UserList([3, 4]), 5, *UserList([6, 7]))
47 (1, 2, 3, 4, 5, 6, 7) {}
48
49 Here we add keyword arguments
50
51 >>> f(1, 2, 3, **{'a':4, 'b':5})
52 (1, 2, 3) {'a': 4, 'b': 5}
53 >>> f(1, 2, **{'a': -1, 'b': 5}, **{'a': 4, 'c': 6})
54 Traceback (most recent call last):
55 ...
56 TypeError: test.test_extcall.f() got multiple values for keyword argument 'a'
57 >>> f(1, 2, **{'a': -1, 'b': 5}, a=4, c=6)
58 Traceback (most recent call last):
59 ...
60 TypeError: test.test_extcall.f() got multiple values for keyword argument 'a'
61 >>> f(1, 2, a=3, **{'a': 4}, **{'a': 5})
62 Traceback (most recent call last):
63 ...
64 TypeError: test.test_extcall.f() got multiple values for keyword argument 'a'
65 >>> f(1, 2, 3, *[4, 5], **{'a':6, 'b':7})
66 (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
67 >>> f(1, 2, 3, x=4, y=5, *(6, 7), **{'a':8, 'b': 9})
68 (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
69 >>> f(1, 2, 3, *[4, 5], **{'c': 8}, **{'a':6, 'b':7})
70 (1, 2, 3, 4, 5) {'a': 6, 'b': 7, 'c': 8}
71 >>> f(1, 2, 3, *(4, 5), x=6, y=7, **{'a':8, 'b': 9})
72 (1, 2, 3, 4, 5) {'a': 8, 'b': 9, 'x': 6, 'y': 7}
73
74 >>> f(1, 2, 3, **UserDict(a=4, b=5))
75 (1, 2, 3) {'a': 4, 'b': 5}
76 >>> f(1, 2, 3, *(4, 5), **UserDict(a=6, b=7))
77 (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
78 >>> f(1, 2, 3, x=4, y=5, *(6, 7), **UserDict(a=8, b=9))
79 (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
80 >>> f(1, 2, 3, *(4, 5), x=6, y=7, **UserDict(a=8, b=9))
81 (1, 2, 3, 4, 5) {'a': 8, 'b': 9, 'x': 6, 'y': 7}
82
83 Mix keyword arguments and dict unpacking
84
85 >>> d1 = {'a':1}
86
87 >>> d2 = {'c':3}
88
89 >>> f(b=2, **d1, **d2)
90 () {'a': 1, 'b': 2, 'c': 3}
91
92 >>> f(**d1, b=2, **d2)
93 () {'a': 1, 'b': 2, 'c': 3}
94
95 >>> f(**d1, **d2, b=2)
96 () {'a': 1, 'b': 2, 'c': 3}
97
98 >>> f(**d1, b=2, **d2, d=4)
99 () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
100
101 Examples with invalid arguments (TypeErrors). We're also testing the function
102 names in the exception messages.
103
104 Verify clearing of SF bug #733667
105
106 >>> e(c=4)
107 Traceback (most recent call last):
108 ...
109 TypeError: e() got an unexpected keyword argument 'c'
110
111 >>> g()
112 Traceback (most recent call last):
113 ...
114 TypeError: g() missing 1 required positional argument: 'x'
115
116 >>> g(*())
117 Traceback (most recent call last):
118 ...
119 TypeError: g() missing 1 required positional argument: 'x'
120
121 >>> g(*(), **{})
122 Traceback (most recent call last):
123 ...
124 TypeError: g() missing 1 required positional argument: 'x'
125
126 >>> g(1)
127 1 () {}
128 >>> g(1, 2)
129 1 (2,) {}
130 >>> g(1, 2, 3)
131 1 (2, 3) {}
132 >>> g(1, 2, 3, *(4, 5))
133 1 (2, 3, 4, 5) {}
134
135 >>> class Nothing: pass
136 ...
137 >>> g(*Nothing())
138 Traceback (most recent call last):
139 ...
140 TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing
141
142 >>> class Nothing:
143 ... def __len__(self): return 5
144 ...
145
146 >>> g(*Nothing())
147 Traceback (most recent call last):
148 ...
149 TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing
150
151 >>> class Nothing():
152 ... def __len__(self): return 5
153 ... def __getitem__(self, i):
154 ... if i<3: return i
155 ... else: raise IndexError(i)
156 ...
157
158 >>> g(*Nothing())
159 0 (1, 2) {}
160
161 >>> class Nothing:
162 ... def __init__(self): self.c = 0
163 ... def __iter__(self): return self
164 ... def __next__(self):
165 ... if self.c == 4:
166 ... raise StopIteration
167 ... c = self.c
168 ... self.c += 1
169 ... return c
170 ...
171
172 >>> g(*Nothing())
173 0 (1, 2, 3) {}
174
175 Check for issue #4806: Does a TypeError in a generator get propagated with the
176 right error message? (Also check with other iterables.)
177
178 >>> def broken(): raise TypeError("myerror")
179 ...
180
181 >>> g(*(broken() for i in range(1)))
182 Traceback (most recent call last):
183 ...
184 TypeError: myerror
185 >>> g(*range(1), *(broken() for i in range(1)))
186 Traceback (most recent call last):
187 ...
188 TypeError: myerror
189
190 >>> class BrokenIterable1:
191 ... def __iter__(self):
192 ... raise TypeError('myerror')
193 ...
194 >>> g(*BrokenIterable1())
195 Traceback (most recent call last):
196 ...
197 TypeError: myerror
198 >>> g(*range(1), *BrokenIterable1())
199 Traceback (most recent call last):
200 ...
201 TypeError: myerror
202
203 >>> class BrokenIterable2:
204 ... def __iter__(self):
205 ... yield 0
206 ... raise TypeError('myerror')
207 ...
208 >>> g(*BrokenIterable2())
209 Traceback (most recent call last):
210 ...
211 TypeError: myerror
212 >>> g(*range(1), *BrokenIterable2())
213 Traceback (most recent call last):
214 ...
215 TypeError: myerror
216
217 >>> class BrokenSequence:
218 ... def __getitem__(self, idx):
219 ... raise TypeError('myerror')
220 ...
221 >>> g(*BrokenSequence())
222 Traceback (most recent call last):
223 ...
224 TypeError: myerror
225 >>> g(*range(1), *BrokenSequence())
226 Traceback (most recent call last):
227 ...
228 TypeError: myerror
229
230 Make sure that the function doesn't stomp the dictionary
231
232 >>> d = {'a': 1, 'b': 2, 'c': 3}
233 >>> d2 = d.copy()
234 >>> g(1, d=4, **d)
235 1 () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
236 >>> d == d2
237 True
238
239 What about willful misconduct?
240
241 >>> def saboteur(**kw):
242 ... kw['x'] = 'm'
243 ... return kw
244
245 >>> d = {}
246 >>> kw = saboteur(a=1, **d)
247 >>> d
248 {}
249
250
251 >>> g(1, 2, 3, **{'x': 4, 'y': 5})
252 Traceback (most recent call last):
253 ...
254 TypeError: g() got multiple values for argument 'x'
255
256 >>> f(**{1:2})
257 Traceback (most recent call last):
258 ...
259 TypeError: keywords must be strings
260
261 >>> h(**{'e': 2})
262 Traceback (most recent call last):
263 ...
264 TypeError: h() got an unexpected keyword argument 'e'
265
266 >>> h(*h)
267 Traceback (most recent call last):
268 ...
269 TypeError: test.test_extcall.h() argument after * must be an iterable, not function
270
271 >>> h(1, *h)
272 Traceback (most recent call last):
273 ...
274 TypeError: Value after * must be an iterable, not function
275
276 >>> h(*[1], *h)
277 Traceback (most recent call last):
278 ...
279 TypeError: Value after * must be an iterable, not function
280
281 >>> dir(*h)
282 Traceback (most recent call last):
283 ...
284 TypeError: dir() argument after * must be an iterable, not function
285
286 >>> nothing = None
287 >>> nothing(*h)
288 Traceback (most recent call last):
289 ...
290 TypeError: None argument after * must be an iterable, \
291 not function
292
293 >>> h(**h)
294 Traceback (most recent call last):
295 ...
296 TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
297
298 >>> h(**[])
299 Traceback (most recent call last):
300 ...
301 TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
302
303 >>> h(a=1, **h)
304 Traceback (most recent call last):
305 ...
306 TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
307
308 >>> h(a=1, **[])
309 Traceback (most recent call last):
310 ...
311 TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
312
313 >>> h(**{'a': 1}, **h)
314 Traceback (most recent call last):
315 ...
316 TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
317
318 >>> h(**{'a': 1}, **[])
319 Traceback (most recent call last):
320 ...
321 TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
322
323 >>> dir(**h)
324 Traceback (most recent call last):
325 ...
326 TypeError: dir() argument after ** must be a mapping, not function
327
328 >>> nothing(**h)
329 Traceback (most recent call last):
330 ...
331 TypeError: None argument after ** must be a mapping, \
332 not function
333
334 >>> dir(b=1, **{'b': 1})
335 Traceback (most recent call last):
336 ...
337 TypeError: dir() got multiple values for keyword argument 'b'
338
339 Test a kwargs mapping with duplicated keys.
340
341 >>> from collections.abc import Mapping
342 >>> class MultiDict(Mapping):
343 ... def __init__(self, items):
344 ... self._items = items
345 ...
346 ... def __iter__(self):
347 ... return (k for k, v in self._items)
348 ...
349 ... def __getitem__(self, key):
350 ... for k, v in self._items:
351 ... if k == key:
352 ... return v
353 ... raise KeyError(key)
354 ...
355 ... def __len__(self):
356 ... return len(self._items)
357 ...
358 ... def keys(self):
359 ... return [k for k, v in self._items]
360 ...
361 ... def values(self):
362 ... return [v for k, v in self._items]
363 ...
364 ... def items(self):
365 ... return [(k, v) for k, v in self._items]
366 ...
367 >>> g(**MultiDict([('x', 1), ('y', 2)]))
368 1 () {'y': 2}
369
370 >>> g(**MultiDict([('x', 1), ('x', 2)]))
371 Traceback (most recent call last):
372 ...
373 TypeError: test.test_extcall.g() got multiple values for keyword argument 'x'
374
375 >>> g(a=3, **MultiDict([('x', 1), ('x', 2)]))
376 Traceback (most recent call last):
377 ...
378 TypeError: test.test_extcall.g() got multiple values for keyword argument 'x'
379
380 >>> g(**MultiDict([('a', 3)]), **MultiDict([('x', 1), ('x', 2)]))
381 Traceback (most recent call last):
382 ...
383 TypeError: test.test_extcall.g() got multiple values for keyword argument 'x'
384
385 Call with dict subtype:
386
387 >>> class MyDict(dict):
388 ... pass
389
390 >>> def s1(**kwargs):
391 ... return kwargs
392 >>> def s2(*args, **kwargs):
393 ... return (args, kwargs)
394 >>> def s3(*, n, **kwargs):
395 ... return (n, kwargs)
396
397 >>> md = MyDict({'a': 1, 'b': 2})
398 >>> assert s1(**md) == {'a': 1, 'b': 2}
399 >>> assert s2(*(1, 2), **md) == ((1, 2), {'a': 1, 'b': 2})
400 >>> assert s3(**MyDict({'n': 1, 'b': 2})) == (1, {'b': 2})
401 >>> s3(**md)
402 Traceback (most recent call last):
403 ...
404 TypeError: s3() missing 1 required keyword-only argument: 'n'
405
406 Another helper function
407
408 >>> def f2(*a, **b):
409 ... return a, b
410
411
412 >>> d = {}
413 >>> for i in range(512):
414 ... key = 'k%d' % i
415 ... d[key] = i
416 >>> a, b = f2(1, *(2,3), **d)
417 >>> len(a), len(b), b == d
418 (3, 512, True)
419
420 >>> class Foo:
421 ... def method(self, arg1, arg2):
422 ... return arg1+arg2
423
424 >>> x = Foo()
425 >>> Foo.method(*(x, 1, 2))
426 3
427 >>> Foo.method(x, *(1, 2))
428 3
429 >>> Foo.method(*(1, 2, 3))
430 5
431 >>> Foo.method(1, *[2, 3])
432 5
433
434 A PyCFunction that takes only positional parameters should allow an
435 empty keyword dictionary to pass without a complaint, but raise a
436 TypeError if te dictionary is not empty
437
438 >>> try:
439 ... silence = id(1, *{})
440 ... True
441 ... except:
442 ... False
443 True
444
445 >>> id(1, **{'foo': 1})
446 Traceback (most recent call last):
447 ...
448 TypeError: id() takes no keyword arguments
449
450 A corner case of keyword dictionary items being deleted during
451 the function call setup. See <http://bugs.python.org/issue2016>.
452
453 >>> class Name(str):
454 ... def __eq__(self, other):
455 ... try:
456 ... del x[self]
457 ... except KeyError:
458 ... pass
459 ... return str.__eq__(self, other)
460 ... def __hash__(self):
461 ... return str.__hash__(self)
462
463 >>> x = {Name("a"):1, Name("b"):2}
464 >>> def f(a, b):
465 ... print(a,b)
466 >>> f(**x)
467 1 2
468
469 Too many arguments:
470
471 >>> def f(): pass
472 >>> f(1)
473 Traceback (most recent call last):
474 ...
475 TypeError: f() takes 0 positional arguments but 1 was given
476 >>> def f(a): pass
477 >>> f(1, 2)
478 Traceback (most recent call last):
479 ...
480 TypeError: f() takes 1 positional argument but 2 were given
481 >>> def f(a, b=1): pass
482 >>> f(1, 2, 3)
483 Traceback (most recent call last):
484 ...
485 TypeError: f() takes from 1 to 2 positional arguments but 3 were given
486 >>> def f(*, kw): pass
487 >>> f(1, kw=3)
488 Traceback (most recent call last):
489 ...
490 TypeError: f() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
491 >>> def f(*, kw, b): pass
492 >>> f(1, 2, 3, b=3, kw=3)
493 Traceback (most recent call last):
494 ...
495 TypeError: f() takes 0 positional arguments but 3 positional arguments (and 2 keyword-only arguments) were given
496 >>> def f(a, b=2, *, kw): pass
497 >>> f(2, 3, 4, kw=4)
498 Traceback (most recent call last):
499 ...
500 TypeError: f() takes from 1 to 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given
501
502 Too few and missing arguments:
503
504 >>> def f(a): pass
505 >>> f()
506 Traceback (most recent call last):
507 ...
508 TypeError: f() missing 1 required positional argument: 'a'
509 >>> def f(a, b): pass
510 >>> f()
511 Traceback (most recent call last):
512 ...
513 TypeError: f() missing 2 required positional arguments: 'a' and 'b'
514 >>> def f(a, b, c): pass
515 >>> f()
516 Traceback (most recent call last):
517 ...
518 TypeError: f() missing 3 required positional arguments: 'a', 'b', and 'c'
519 >>> def f(a, b, c, d, e): pass
520 >>> f()
521 Traceback (most recent call last):
522 ...
523 TypeError: f() missing 5 required positional arguments: 'a', 'b', 'c', 'd', and 'e'
524 >>> def f(a, b=4, c=5, d=5): pass
525 >>> f(c=12, b=9)
526 Traceback (most recent call last):
527 ...
528 TypeError: f() missing 1 required positional argument: 'a'
529
530 Same with keyword only args:
531
532 >>> def f(*, w): pass
533 >>> f()
534 Traceback (most recent call last):
535 ...
536 TypeError: f() missing 1 required keyword-only argument: 'w'
537 >>> def f(*, a, b, c, d, e): pass
538 >>> f()
539 Traceback (most recent call last):
540 ...
541 TypeError: f() missing 5 required keyword-only arguments: 'a', 'b', 'c', 'd', and 'e'
542
543 """
544
545 import doctest
546 import unittest
547
548 def load_tests(loader, tests, pattern):
549 tests.addTest(doctest.DocTestSuite())
550 return tests
551
552
553 if __name__ == '__main__':
554 unittest.main()