1 # -*- coding: utf-8 -*- 2 3 """Doctest for method/function calls. 4 5 We're going the use these types for extra testing 6 7 >>> from UserList import UserList 8 >>> from UserDict import UserDict 9 10 We'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 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, *UserList([4, 5])) 39 (1, 2, 3, 4, 5) {} 40 41 Here 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 57 Examples with invalid arguments (TypeErrors). We're also testing the function 58 names in the exception messages. 59 60 Verify 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 131 Make 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 140 What 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, \ 181 not 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, \ 197 not 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 204 Another 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 \ 231 first 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 \ 237 first argument (got int instance instead) 238 239 A PyCFunction that takes only positional parameters should allow an 240 empty keyword dictionary to pass without a complaint, but raise a 241 TypeError 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 255 A corner case of keyword dictionary items being deleted during 256 the 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 274 A 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 283 The 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 293 import unittest 294 import sys 295 from test import test_support 296 297 298 class 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'stren': 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 314 def test_main(): 315 test_support.run_doctest(sys.modules[__name__], True) 316 test_support.run_unittest(ExtCallTest) 317 318 if __name__ == '__main__': 319 test_main() 320