• 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    >>> None(*h)
268    Traceback (most recent call last):
269      ...
270    TypeError: NoneType object argument after * must be an iterable, \
271not function
272
273    >>> h(**h)
274    Traceback (most recent call last):
275      ...
276    TypeError: h() argument after ** must be a mapping, not function
277
278    >>> h(**[])
279    Traceback (most recent call last):
280      ...
281    TypeError: h() argument after ** must be a mapping, not list
282
283    >>> h(a=1, **h)
284    Traceback (most recent call last):
285      ...
286    TypeError: h() argument after ** must be a mapping, not function
287
288    >>> h(a=1, **[])
289    Traceback (most recent call last):
290      ...
291    TypeError: h() argument after ** must be a mapping, not list
292
293    >>> h(**{'a': 1}, **h)
294    Traceback (most recent call last):
295      ...
296    TypeError: h() argument after ** must be a mapping, not function
297
298    >>> h(**{'a': 1}, **[])
299    Traceback (most recent call last):
300      ...
301    TypeError: h() argument after ** must be a mapping, not list
302
303    >>> dir(**h)
304    Traceback (most recent call last):
305      ...
306    TypeError: dir() argument after ** must be a mapping, not function
307
308    >>> None(**h)
309    Traceback (most recent call last):
310      ...
311    TypeError: NoneType object argument after ** must be a mapping, \
312not function
313
314    >>> dir(b=1, **{'b': 1})
315    Traceback (most recent call last):
316      ...
317    TypeError: dir() got multiple values for keyword argument 'b'
318
319Another helper function
320
321    >>> def f2(*a, **b):
322    ...     return a, b
323
324
325    >>> d = {}
326    >>> for i in range(512):
327    ...     key = 'k%d' % i
328    ...     d[key] = i
329    >>> a, b = f2(1, *(2,3), **d)
330    >>> len(a), len(b), b == d
331    (3, 512, True)
332
333    >>> class Foo:
334    ...     def method(self, arg1, arg2):
335    ...         return arg1+arg2
336
337    >>> x = Foo()
338    >>> Foo.method(*(x, 1, 2))
339    3
340    >>> Foo.method(x, *(1, 2))
341    3
342    >>> Foo.method(*(1, 2, 3))
343    5
344    >>> Foo.method(1, *[2, 3])
345    5
346
347A PyCFunction that takes only positional parameters should allow an
348empty keyword dictionary to pass without a complaint, but raise a
349TypeError if te dictionary is not empty
350
351    >>> try:
352    ...     silence = id(1, *{})
353    ...     True
354    ... except:
355    ...     False
356    True
357
358    >>> id(1, **{'foo': 1})
359    Traceback (most recent call last):
360      ...
361    TypeError: id() takes no keyword arguments
362
363A corner case of keyword dictionary items being deleted during
364the function call setup. See <http://bugs.python.org/issue2016>.
365
366    >>> class Name(str):
367    ...     def __eq__(self, other):
368    ...         try:
369    ...              del x[self]
370    ...         except KeyError:
371    ...              pass
372    ...         return str.__eq__(self, other)
373    ...     def __hash__(self):
374    ...         return str.__hash__(self)
375
376    >>> x = {Name("a"):1, Name("b"):2}
377    >>> def f(a, b):
378    ...     print(a,b)
379    >>> f(**x)
380    1 2
381
382Too many arguments:
383
384    >>> def f(): pass
385    >>> f(1)
386    Traceback (most recent call last):
387      ...
388    TypeError: f() takes 0 positional arguments but 1 was given
389    >>> def f(a): pass
390    >>> f(1, 2)
391    Traceback (most recent call last):
392      ...
393    TypeError: f() takes 1 positional argument but 2 were given
394    >>> def f(a, b=1): pass
395    >>> f(1, 2, 3)
396    Traceback (most recent call last):
397      ...
398    TypeError: f() takes from 1 to 2 positional arguments but 3 were given
399    >>> def f(*, kw): pass
400    >>> f(1, kw=3)
401    Traceback (most recent call last):
402      ...
403    TypeError: f() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
404    >>> def f(*, kw, b): pass
405    >>> f(1, 2, 3, b=3, kw=3)
406    Traceback (most recent call last):
407      ...
408    TypeError: f() takes 0 positional arguments but 3 positional arguments (and 2 keyword-only arguments) were given
409    >>> def f(a, b=2, *, kw): pass
410    >>> f(2, 3, 4, kw=4)
411    Traceback (most recent call last):
412      ...
413    TypeError: f() takes from 1 to 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given
414
415Too few and missing arguments:
416
417    >>> def f(a): pass
418    >>> f()
419    Traceback (most recent call last):
420      ...
421    TypeError: f() missing 1 required positional argument: 'a'
422    >>> def f(a, b): pass
423    >>> f()
424    Traceback (most recent call last):
425      ...
426    TypeError: f() missing 2 required positional arguments: 'a' and 'b'
427    >>> def f(a, b, c): pass
428    >>> f()
429    Traceback (most recent call last):
430      ...
431    TypeError: f() missing 3 required positional arguments: 'a', 'b', and 'c'
432    >>> def f(a, b, c, d, e): pass
433    >>> f()
434    Traceback (most recent call last):
435      ...
436    TypeError: f() missing 5 required positional arguments: 'a', 'b', 'c', 'd', and 'e'
437    >>> def f(a, b=4, c=5, d=5): pass
438    >>> f(c=12, b=9)
439    Traceback (most recent call last):
440      ...
441    TypeError: f() missing 1 required positional argument: 'a'
442
443Same with keyword only args:
444
445    >>> def f(*, w): pass
446    >>> f()
447    Traceback (most recent call last):
448      ...
449    TypeError: f() missing 1 required keyword-only argument: 'w'
450    >>> def f(*, a, b, c, d, e): pass
451    >>> f()
452    Traceback (most recent call last):
453      ...
454    TypeError: f() missing 5 required keyword-only arguments: 'a', 'b', 'c', 'd', and 'e'
455
456"""
457
458import sys
459from test import support
460
461def test_main():
462    support.run_doctest(sys.modules[__name__], True)
463
464if __name__ == '__main__':
465    test_main()
466