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