1# -*- coding: utf-8 -*-
2
3"""Doctest for method/function calls.
4
5We're going the use these types for extra testing
6
7    >>> from UserList import UserList
8    >>> from UserDict import UserDict
9
10We're defining four helper functions
11
12    >>> def e(a,b):
13    ...     print a, b
14
15    >>> def f(*a, **k):
16    ...     print a, test_support.sortdict(k)
17
18    >>> def g(x, *y, **z):
19    ...     print x, y, test_support.sortdict(z)
20
21    >>> def h(j=1, a=2, h=3):
22    ...     print j, a, h
23
24Argument 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, *UserList([4, 5]))
39    (1, 2, 3, 4, 5) {}
40
41Here we add keyword arguments
42
43    >>> f(1, 2, 3, **{'a':4, 'b':5})
44    (1, 2, 3) {'a': 4, 'b': 5}
45    >>> f(1, 2, 3, *[4, 5], **{'a':6, 'b':7})
46    (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
47    >>> f(1, 2, 3, x=4, y=5, *(6, 7), **{'a':8, 'b': 9})
48    (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
49
50    >>> f(1, 2, 3, **UserDict(a=4, b=5))
51    (1, 2, 3) {'a': 4, 'b': 5}
52    >>> f(1, 2, 3, *(4, 5), **UserDict(a=6, b=7))
53    (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
54    >>> f(1, 2, 3, x=4, y=5, *(6, 7), **UserDict(a=8, b=9))
55    (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
56
57Examples with invalid arguments (TypeErrors). We're also testing the function
58names in the exception messages.
59
60Verify clearing of SF bug #733667
61
62    >>> e(c=4)
63    Traceback (most recent call last):
64      ...
65    TypeError: e() got an unexpected keyword argument 'c'
66
67    >>> g()
68    Traceback (most recent call last):
69      ...
70    TypeError: g() takes at least 1 argument (0 given)
71
72    >>> g(*())
73    Traceback (most recent call last):
74      ...
75    TypeError: g() takes at least 1 argument (0 given)
76
77    >>> g(*(), **{})
78    Traceback (most recent call last):
79      ...
80    TypeError: g() takes at least 1 argument (0 given)
81
82    >>> g(1)
83    1 () {}
84    >>> g(1, 2)
85    1 (2,) {}
86    >>> g(1, 2, 3)
87    1 (2, 3) {}
88    >>> g(1, 2, 3, *(4, 5))
89    1 (2, 3, 4, 5) {}
90
91    >>> class Nothing: pass
92    ...
93    >>> g(*Nothing())
94    Traceback (most recent call last):
95      ...
96    TypeError: g() argument after * must be a sequence, not instance
97
98    >>> class Nothing:
99    ...     def __len__(self): return 5
100    ...
101
102    >>> g(*Nothing())
103    Traceback (most recent call last):
104      ...
105    TypeError: g() argument after * must be a sequence, not instance
106
107    >>> class Nothing():
108    ...     def __len__(self): return 5
109    ...     def __getitem__(self, i):
110    ...         if i<3: return i
111    ...         else: raise IndexError(i)
112    ...
113
114    >>> g(*Nothing())
115    0 (1, 2) {}
116
117    >>> class Nothing:
118    ...     def __init__(self): self.c = 0
119    ...     def __iter__(self): return self
120    ...     def next(self):
121    ...         if self.c == 4:
122    ...             raise StopIteration
123    ...         c = self.c
124    ...         self.c += 1
125    ...         return c
126    ...
127
128    >>> g(*Nothing())
129    0 (1, 2, 3) {}
130
131Make sure that the function doesn't stomp the dictionary
132
133    >>> d = {'a': 1, 'b': 2, 'c': 3}
134    >>> d2 = d.copy()
135    >>> g(1, d=4, **d)
136    1 () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
137    >>> d == d2
138    True
139
140What about willful misconduct?
141
142    >>> def saboteur(**kw):
143    ...     kw['x'] = 'm'
144    ...     return kw
145
146    >>> d = {}
147    >>> kw = saboteur(a=1, **d)
148    >>> d
149    {}
150
151
152    >>> g(1, 2, 3, **{'x': 4, 'y': 5})
153    Traceback (most recent call last):
154      ...
155    TypeError: g() got multiple values for keyword argument 'x'
156
157    >>> f(**{1:2})
158    Traceback (most recent call last):
159      ...
160    TypeError: f() keywords must be strings
161
162    >>> h(**{'e': 2})
163    Traceback (most recent call last):
164      ...
165    TypeError: h() got an unexpected keyword argument 'e'
166
167    >>> h(*h)
168    Traceback (most recent call last):
169      ...
170    TypeError: h() argument after * must be a sequence, not function
171
172    >>> dir(*h)
173    Traceback (most recent call last):
174      ...
175    TypeError: dir() argument after * must be a sequence, not function
176
177    >>> None(*h)
178    Traceback (most recent call last):
179      ...
180    TypeError: NoneType object argument after * must be a sequence, \
181not function
182
183    >>> h(**h)
184    Traceback (most recent call last):
185      ...
186    TypeError: h() argument after ** must be a mapping, not function
187
188    >>> dir(**h)
189    Traceback (most recent call last):
190      ...
191    TypeError: dir() argument after ** must be a mapping, not function
192
193    >>> None(**h)
194    Traceback (most recent call last):
195      ...
196    TypeError: NoneType object argument after ** must be a mapping, \
197not function
198
199    >>> dir(b=1, **{'b': 1})
200    Traceback (most recent call last):
201      ...
202    TypeError: dir() got multiple values for keyword argument 'b'
203
204Another helper function
205
206    >>> def f2(*a, **b):
207    ...     return a, b
208
209
210    >>> d = {}
211    >>> for i in xrange(512):
212    ...     key = 'k%d' % i
213    ...     d[key] = i
214    >>> a, b = f2(1, *(2,3), **d)
215    >>> len(a), len(b), b == d
216    (3, 512, True)
217
218    >>> class Foo:
219    ...     def method(self, arg1, arg2):
220    ...         return arg1+arg2
221
222    >>> x = Foo()
223    >>> Foo.method(*(x, 1, 2))
224    3
225    >>> Foo.method(x, *(1, 2))
226    3
227    >>> Foo.method(*(1, 2, 3))
228    Traceback (most recent call last):
229      ...
230    TypeError: unbound method method() must be called with Foo instance as \
231first argument (got int instance instead)
232
233    >>> Foo.method(1, *[2, 3])
234    Traceback (most recent call last):
235      ...
236    TypeError: unbound method method() must be called with Foo instance as \
237first argument (got int instance instead)
238
239A PyCFunction that takes only positional parameters should allow an
240empty keyword dictionary to pass without a complaint, but raise a
241TypeError if te dictionary is not empty
242
243    >>> try:
244    ...     silence = id(1, *{})
245    ...     True
246    ... except:
247    ...     False
248    True
249
250    >>> id(1, **{'foo': 1})
251    Traceback (most recent call last):
252      ...
253    TypeError: id() takes no keyword arguments
254
255A corner case of keyword dictionary items being deleted during
256the function call setup. See <http://bugs.python.org/issue2016>.
257
258    >>> class Name(str):
259    ...     def __eq__(self, other):
260    ...         try:
261    ...              del x[self]
262    ...         except KeyError:
263    ...              pass
264    ...         return str.__eq__(self, other)
265    ...     def __hash__(self):
266    ...         return str.__hash__(self)
267
268    >>> x = {Name("a"):1, Name("b"):2}
269    >>> def f(a, b):
270    ...     print a,b
271    >>> f(**x)
272    1 2
273
274A obscure message:
275
276    >>> def f(a, b):
277    ...    pass
278    >>> f(b=1)
279    Traceback (most recent call last):
280      ...
281    TypeError: f() takes exactly 2 arguments (1 given)
282
283The number of arguments passed in includes keywords:
284
285    >>> def f(a):
286    ...    pass
287    >>> f(6, a=4, *(1, 2, 3))
288    Traceback (most recent call last):
289      ...
290    TypeError: f() takes exactly 1 argument (5 given)
291"""
292
293import unittest
294import sys
295from test import test_support
296
297
298class ExtCallTest(unittest.TestCase):
299
300    def test_unicode_keywords(self):
301        def f(a):
302            return a
303        self.assertEqual(f(**{u'a': 4}), 4)
304        self.assertRaises(TypeError, f, **{u'stören': 4})
305        self.assertRaises(TypeError, f, **{u'someLongString':2})
306        try:
307            f(a=4, **{u'a': 4})
308        except TypeError:
309            pass
310        else:
311            self.fail("duplicate arguments didn't raise")
312
313
314def test_main():
315    test_support.run_doctest(sys.modules[__name__], True)
316    test_support.run_unittest(ExtCallTest)
317
318if __name__ == '__main__':
319    test_main()
320