• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    >>> g(*range(1), *(broken() for i in range(1)))
167    Traceback (most recent call last):
168      ...
169    TypeError: myerror
170
171    >>> class BrokenIterable1:
172    ...     def __iter__(self):
173    ...         raise TypeError('myerror')
174    ...
175    >>> g(*BrokenIterable1())
176    Traceback (most recent call last):
177      ...
178    TypeError: myerror
179    >>> g(*range(1), *BrokenIterable1())
180    Traceback (most recent call last):
181      ...
182    TypeError: myerror
183
184    >>> class BrokenIterable2:
185    ...     def __iter__(self):
186    ...         yield 0
187    ...         raise TypeError('myerror')
188    ...
189    >>> g(*BrokenIterable2())
190    Traceback (most recent call last):
191      ...
192    TypeError: myerror
193    >>> g(*range(1), *BrokenIterable2())
194    Traceback (most recent call last):
195      ...
196    TypeError: myerror
197
198    >>> class BrokenSequence:
199    ...     def __getitem__(self, idx):
200    ...         raise TypeError('myerror')
201    ...
202    >>> g(*BrokenSequence())
203    Traceback (most recent call last):
204      ...
205    TypeError: myerror
206    >>> g(*range(1), *BrokenSequence())
207    Traceback (most recent call last):
208      ...
209    TypeError: myerror
210
211Make sure that the function doesn't stomp the dictionary
212
213    >>> d = {'a': 1, 'b': 2, 'c': 3}
214    >>> d2 = d.copy()
215    >>> g(1, d=4, **d)
216    1 () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
217    >>> d == d2
218    True
219
220What about willful misconduct?
221
222    >>> def saboteur(**kw):
223    ...     kw['x'] = 'm'
224    ...     return kw
225
226    >>> d = {}
227    >>> kw = saboteur(a=1, **d)
228    >>> d
229    {}
230
231
232    >>> g(1, 2, 3, **{'x': 4, 'y': 5})
233    Traceback (most recent call last):
234      ...
235    TypeError: g() got multiple values for argument 'x'
236
237    >>> f(**{1:2})
238    Traceback (most recent call last):
239      ...
240    TypeError: f() keywords must be strings
241
242    >>> h(**{'e': 2})
243    Traceback (most recent call last):
244      ...
245    TypeError: h() got an unexpected keyword argument 'e'
246
247    >>> h(*h)
248    Traceback (most recent call last):
249      ...
250    TypeError: h() argument after * must be an iterable, not function
251
252    >>> h(1, *h)
253    Traceback (most recent call last):
254      ...
255    TypeError: h() argument after * must be an iterable, not function
256
257    >>> h(*[1], *h)
258    Traceback (most recent call last):
259      ...
260    TypeError: h() argument after * must be an iterable, not function
261
262    >>> dir(*h)
263    Traceback (most recent call last):
264      ...
265    TypeError: dir() argument after * must be an iterable, not function
266
267    >>> nothing = None
268    >>> nothing(*h)
269    Traceback (most recent call last):
270      ...
271    TypeError: NoneType object argument after * must be an iterable, \
272not function
273
274    >>> h(**h)
275    Traceback (most recent call last):
276      ...
277    TypeError: h() argument after ** must be a mapping, not function
278
279    >>> h(**[])
280    Traceback (most recent call last):
281      ...
282    TypeError: h() argument after ** must be a mapping, not list
283
284    >>> h(a=1, **h)
285    Traceback (most recent call last):
286      ...
287    TypeError: h() argument after ** must be a mapping, not function
288
289    >>> h(a=1, **[])
290    Traceback (most recent call last):
291      ...
292    TypeError: h() argument after ** must be a mapping, not list
293
294    >>> h(**{'a': 1}, **h)
295    Traceback (most recent call last):
296      ...
297    TypeError: h() argument after ** must be a mapping, not function
298
299    >>> h(**{'a': 1}, **[])
300    Traceback (most recent call last):
301      ...
302    TypeError: h() argument after ** must be a mapping, not list
303
304    >>> dir(**h)
305    Traceback (most recent call last):
306      ...
307    TypeError: dir() argument after ** must be a mapping, not function
308
309    >>> nothing(**h)
310    Traceback (most recent call last):
311      ...
312    TypeError: NoneType object argument after ** must be a mapping, \
313not function
314
315    >>> dir(b=1, **{'b': 1})
316    Traceback (most recent call last):
317      ...
318    TypeError: dir() got multiple values for keyword argument 'b'
319
320Test a kwargs mapping with duplicated keys.
321
322    >>> from collections.abc import Mapping
323    >>> class MultiDict(Mapping):
324    ...     def __init__(self, items):
325    ...         self._items = items
326    ...
327    ...     def __iter__(self):
328    ...         return (k for k, v in self._items)
329    ...
330    ...     def __getitem__(self, key):
331    ...         for k, v in self._items:
332    ...             if k == key:
333    ...                 return v
334    ...         raise KeyError(key)
335    ...
336    ...     def __len__(self):
337    ...         return len(self._items)
338    ...
339    ...     def keys(self):
340    ...         return [k for k, v in self._items]
341    ...
342    ...     def values(self):
343    ...         return [v for k, v in self._items]
344    ...
345    ...     def items(self):
346    ...         return [(k, v) for k, v in self._items]
347    ...
348    >>> g(**MultiDict([('x', 1), ('y', 2)]))
349    1 () {'y': 2}
350
351    >>> g(**MultiDict([('x', 1), ('x', 2)]))
352    Traceback (most recent call last):
353      ...
354    TypeError: g() got multiple values for keyword argument 'x'
355
356    >>> g(a=3, **MultiDict([('x', 1), ('x', 2)]))
357    Traceback (most recent call last):
358      ...
359    TypeError: g() got multiple values for keyword argument 'x'
360
361    >>> g(**MultiDict([('a', 3)]), **MultiDict([('x', 1), ('x', 2)]))
362    Traceback (most recent call last):
363      ...
364    TypeError: g() got multiple values for keyword argument 'x'
365
366Another helper function
367
368    >>> def f2(*a, **b):
369    ...     return a, b
370
371
372    >>> d = {}
373    >>> for i in range(512):
374    ...     key = 'k%d' % i
375    ...     d[key] = i
376    >>> a, b = f2(1, *(2,3), **d)
377    >>> len(a), len(b), b == d
378    (3, 512, True)
379
380    >>> class Foo:
381    ...     def method(self, arg1, arg2):
382    ...         return arg1+arg2
383
384    >>> x = Foo()
385    >>> Foo.method(*(x, 1, 2))
386    3
387    >>> Foo.method(x, *(1, 2))
388    3
389    >>> Foo.method(*(1, 2, 3))
390    5
391    >>> Foo.method(1, *[2, 3])
392    5
393
394A PyCFunction that takes only positional parameters should allow an
395empty keyword dictionary to pass without a complaint, but raise a
396TypeError if te dictionary is not empty
397
398    >>> try:
399    ...     silence = id(1, *{})
400    ...     True
401    ... except:
402    ...     False
403    True
404
405    >>> id(1, **{'foo': 1})
406    Traceback (most recent call last):
407      ...
408    TypeError: id() takes no keyword arguments
409
410A corner case of keyword dictionary items being deleted during
411the function call setup. See <http://bugs.python.org/issue2016>.
412
413    >>> class Name(str):
414    ...     def __eq__(self, other):
415    ...         try:
416    ...              del x[self]
417    ...         except KeyError:
418    ...              pass
419    ...         return str.__eq__(self, other)
420    ...     def __hash__(self):
421    ...         return str.__hash__(self)
422
423    >>> x = {Name("a"):1, Name("b"):2}
424    >>> def f(a, b):
425    ...     print(a,b)
426    >>> f(**x)
427    1 2
428
429Too many arguments:
430
431    >>> def f(): pass
432    >>> f(1)
433    Traceback (most recent call last):
434      ...
435    TypeError: f() takes 0 positional arguments but 1 was given
436    >>> def f(a): pass
437    >>> f(1, 2)
438    Traceback (most recent call last):
439      ...
440    TypeError: f() takes 1 positional argument but 2 were given
441    >>> def f(a, b=1): pass
442    >>> f(1, 2, 3)
443    Traceback (most recent call last):
444      ...
445    TypeError: f() takes from 1 to 2 positional arguments but 3 were given
446    >>> def f(*, kw): pass
447    >>> f(1, kw=3)
448    Traceback (most recent call last):
449      ...
450    TypeError: f() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
451    >>> def f(*, kw, b): pass
452    >>> f(1, 2, 3, b=3, kw=3)
453    Traceback (most recent call last):
454      ...
455    TypeError: f() takes 0 positional arguments but 3 positional arguments (and 2 keyword-only arguments) were given
456    >>> def f(a, b=2, *, kw): pass
457    >>> f(2, 3, 4, kw=4)
458    Traceback (most recent call last):
459      ...
460    TypeError: f() takes from 1 to 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given
461
462Too few and missing arguments:
463
464    >>> def f(a): pass
465    >>> f()
466    Traceback (most recent call last):
467      ...
468    TypeError: f() missing 1 required positional argument: 'a'
469    >>> def f(a, b): pass
470    >>> f()
471    Traceback (most recent call last):
472      ...
473    TypeError: f() missing 2 required positional arguments: 'a' and 'b'
474    >>> def f(a, b, c): pass
475    >>> f()
476    Traceback (most recent call last):
477      ...
478    TypeError: f() missing 3 required positional arguments: 'a', 'b', and 'c'
479    >>> def f(a, b, c, d, e): pass
480    >>> f()
481    Traceback (most recent call last):
482      ...
483    TypeError: f() missing 5 required positional arguments: 'a', 'b', 'c', 'd', and 'e'
484    >>> def f(a, b=4, c=5, d=5): pass
485    >>> f(c=12, b=9)
486    Traceback (most recent call last):
487      ...
488    TypeError: f() missing 1 required positional argument: 'a'
489
490Same with keyword only args:
491
492    >>> def f(*, w): pass
493    >>> f()
494    Traceback (most recent call last):
495      ...
496    TypeError: f() missing 1 required keyword-only argument: 'w'
497    >>> def f(*, a, b, c, d, e): pass
498    >>> f()
499    Traceback (most recent call last):
500      ...
501    TypeError: f() missing 5 required keyword-only arguments: 'a', 'b', 'c', 'd', and 'e'
502
503"""
504
505import sys
506from test import support
507
508def test_main():
509    support.run_doctest(sys.modules[__name__], True)
510
511if __name__ == '__main__':
512    test_main()
513