1# Tests for extended unpacking, starred expressions. 2 3doctests = """ 4 5Unpack tuple 6 7 >>> t = (1, 2, 3) 8 >>> a, *b, c = t 9 >>> a == 1 and b == [2] and c == 3 10 True 11 12Unpack list 13 14 >>> l = [4, 5, 6] 15 >>> a, *b = l 16 >>> a == 4 and b == [5, 6] 17 True 18 19Unpack implied tuple 20 21 >>> *a, = 7, 8, 9 22 >>> a == [7, 8, 9] 23 True 24 25Unpack string... fun! 26 27 >>> a, *b = 'one' 28 >>> a == 'o' and b == ['n', 'e'] 29 True 30 31Unpack long sequence 32 33 >>> a, b, c, *d, e, f, g = range(10) 34 >>> (a, b, c, d, e, f, g) == (0, 1, 2, [3, 4, 5, 6], 7, 8, 9) 35 True 36 37Unpack short sequence 38 39 >>> a, *b, c = (1, 2) 40 >>> a == 1 and c == 2 and b == [] 41 True 42 43Unpack generic sequence 44 45 >>> class Seq: 46 ... def __getitem__(self, i): 47 ... if i >= 0 and i < 3: return i 48 ... raise IndexError 49 ... 50 >>> a, *b = Seq() 51 >>> a == 0 and b == [1, 2] 52 True 53 54Unpack in for statement 55 56 >>> for a, *b, c in [(1,2,3), (4,5,6,7)]: 57 ... print(a, b, c) 58 ... 59 1 [2] 3 60 4 [5, 6] 7 61 62Unpack in list 63 64 >>> [a, *b, c] = range(5) 65 >>> a == 0 and b == [1, 2, 3] and c == 4 66 True 67 68Multiple targets 69 70 >>> a, *b, c = *d, e = range(5) 71 >>> a == 0 and b == [1, 2, 3] and c == 4 and d == [0, 1, 2, 3] and e == 4 72 True 73 74Assignment unpacking 75 76 >>> a, b, *c = range(5) 77 >>> a, b, c 78 (0, 1, [2, 3, 4]) 79 >>> *a, b, c = a, b, *c 80 >>> a, b, c 81 ([0, 1, 2], 3, 4) 82 83Set display element unpacking 84 85 >>> a = [1, 2, 3] 86 >>> sorted({1, *a, 0, 4}) 87 [0, 1, 2, 3, 4] 88 89 >>> {1, *1, 0, 4} 90 Traceback (most recent call last): 91 ... 92 TypeError: 'int' object is not iterable 93 94Dict display element unpacking 95 96 >>> kwds = {'z': 0, 'w': 12} 97 >>> sorted({'x': 1, 'y': 2, **kwds}.items()) 98 [('w', 12), ('x', 1), ('y', 2), ('z', 0)] 99 100 >>> sorted({**{'x': 1}, 'y': 2, **{'z': 3}}.items()) 101 [('x', 1), ('y', 2), ('z', 3)] 102 103 >>> sorted({**{'x': 1}, 'y': 2, **{'x': 3}}.items()) 104 [('x', 3), ('y', 2)] 105 106 >>> sorted({**{'x': 1}, **{'x': 3}, 'x': 4}.items()) 107 [('x', 4)] 108 109 >>> {**{}} 110 {} 111 112 >>> a = {} 113 >>> {**a}[0] = 1 114 >>> a 115 {} 116 117 >>> {**1} 118 Traceback (most recent call last): 119 ... 120 TypeError: 'int' object is not a mapping 121 122 >>> {**[]} 123 Traceback (most recent call last): 124 ... 125 TypeError: 'list' object is not a mapping 126 127 >>> len(eval("{" + ", ".join("**{{{}: {}}}".format(i, i) 128 ... for i in range(1000)) + "}")) 129 1000 130 131 >>> {0:1, **{0:2}, 0:3, 0:4} 132 {0: 4} 133 134List comprehension element unpacking 135 136 >>> a, b, c = [0, 1, 2], 3, 4 137 >>> [*a, b, c] 138 [0, 1, 2, 3, 4] 139 140 >>> l = [a, (3, 4), {5}, {6: None}, (i for i in range(7, 10))] 141 >>> [*item for item in l] 142 Traceback (most recent call last): 143 ... 144 SyntaxError: iterable unpacking cannot be used in comprehension 145 146 >>> [*[0, 1] for i in range(10)] 147 Traceback (most recent call last): 148 ... 149 SyntaxError: iterable unpacking cannot be used in comprehension 150 151 >>> [*'a' for i in range(10)] 152 Traceback (most recent call last): 153 ... 154 SyntaxError: iterable unpacking cannot be used in comprehension 155 156 >>> [*[] for i in range(10)] 157 Traceback (most recent call last): 158 ... 159 SyntaxError: iterable unpacking cannot be used in comprehension 160 161 >>> {**{} for a in [1]} 162 Traceback (most recent call last): 163 ... 164 SyntaxError: dict unpacking cannot be used in dict comprehension 165 166# Pegen is better here. 167# Generator expression in function arguments 168 169# >>> list(*x for x in (range(5) for i in range(3))) 170# Traceback (most recent call last): 171# ... 172# list(*x for x in (range(5) for i in range(3))) 173# ^ 174# SyntaxError: invalid syntax 175 176 >>> dict(**x for x in [{1:2}]) 177 Traceback (most recent call last): 178 ... 179 dict(**x for x in [{1:2}]) 180 ^ 181 SyntaxError: invalid syntax 182 183Iterable argument unpacking 184 185 >>> print(*[1], *[2], 3) 186 1 2 3 187 188Make sure that they don't corrupt the passed-in dicts. 189 190 >>> def f(x, y): 191 ... print(x, y) 192 ... 193 >>> original_dict = {'x': 1} 194 >>> f(**original_dict, y=2) 195 1 2 196 >>> original_dict 197 {'x': 1} 198 199Now for some failures 200 201Make sure the raised errors are right for keyword argument unpackings 202 203 >>> from collections.abc import MutableMapping 204 >>> class CrazyDict(MutableMapping): 205 ... def __init__(self): 206 ... self.d = {} 207 ... 208 ... def __iter__(self): 209 ... for x in self.d.__iter__(): 210 ... if x == 'c': 211 ... self.d['z'] = 10 212 ... yield x 213 ... 214 ... def __getitem__(self, k): 215 ... return self.d[k] 216 ... 217 ... def __len__(self): 218 ... return len(self.d) 219 ... 220 ... def __setitem__(self, k, v): 221 ... self.d[k] = v 222 ... 223 ... def __delitem__(self, k): 224 ... del self.d[k] 225 ... 226 >>> d = CrazyDict() 227 >>> d.d = {chr(ord('a') + x): x for x in range(5)} 228 >>> e = {**d} 229 Traceback (most recent call last): 230 ... 231 RuntimeError: dictionary changed size during iteration 232 233 >>> d.d = {chr(ord('a') + x): x for x in range(5)} 234 >>> def f(**kwargs): print(kwargs) 235 >>> f(**d) 236 Traceback (most recent call last): 237 ... 238 RuntimeError: dictionary changed size during iteration 239 240Overridden parameters 241 242 >>> f(x=5, **{'x': 3}, y=2) 243 Traceback (most recent call last): 244 ... 245 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x' 246 247 >>> f(**{'x': 3}, x=5, y=2) 248 Traceback (most recent call last): 249 ... 250 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x' 251 252 >>> f(**{'x': 3}, **{'x': 5}, y=2) 253 Traceback (most recent call last): 254 ... 255 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x' 256 257 >>> f(x=5, **{'x': 3}, **{'x': 2}) 258 Traceback (most recent call last): 259 ... 260 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x' 261 262 >>> f(**{1: 3}, **{1: 5}) 263 Traceback (most recent call last): 264 ... 265 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument '1' 266 267Unpacking non-sequence 268 269 >>> a, *b = 7 270 Traceback (most recent call last): 271 ... 272 TypeError: cannot unpack non-iterable int object 273 274Unpacking sequence too short 275 276 >>> a, *b, c, d, e = Seq() 277 Traceback (most recent call last): 278 ... 279 ValueError: not enough values to unpack (expected at least 4, got 3) 280 281Unpacking sequence too short and target appears last 282 283 >>> a, b, c, d, *e = Seq() 284 Traceback (most recent call last): 285 ... 286 ValueError: not enough values to unpack (expected at least 4, got 3) 287 288Unpacking a sequence where the test for too long raises a different kind of 289error 290 291 >>> class BozoError(Exception): 292 ... pass 293 ... 294 >>> class BadSeq: 295 ... def __getitem__(self, i): 296 ... if i >= 0 and i < 3: 297 ... return i 298 ... elif i == 3: 299 ... raise BozoError 300 ... else: 301 ... raise IndexError 302 ... 303 304Trigger code while not expecting an IndexError (unpack sequence too long, wrong 305error) 306 307 >>> a, *b, c, d, e = BadSeq() 308 Traceback (most recent call last): 309 ... 310 test.test_unpack_ex.BozoError 311 312Now some general starred expressions (all fail). 313 314 >>> a, *b, c, *d, e = range(10) # doctest:+ELLIPSIS 315 Traceback (most recent call last): 316 ... 317 SyntaxError: multiple starred expressions in assignment 318 319 >>> [*b, *c] = range(10) # doctest:+ELLIPSIS 320 Traceback (most recent call last): 321 ... 322 SyntaxError: multiple starred expressions in assignment 323 324 >>> a,*b,*c,*d = range(4) # doctest:+ELLIPSIS 325 Traceback (most recent call last): 326 ... 327 SyntaxError: multiple starred expressions in assignment 328 329 >>> *a = range(10) # doctest:+ELLIPSIS 330 Traceback (most recent call last): 331 ... 332 SyntaxError: starred assignment target must be in a list or tuple 333 334 >>> *a # doctest:+ELLIPSIS 335 Traceback (most recent call last): 336 ... 337 SyntaxError: can't use starred expression here 338 339 >>> *1 # doctest:+ELLIPSIS 340 Traceback (most recent call last): 341 ... 342 SyntaxError: can't use starred expression here 343 344 >>> x = *a # doctest:+ELLIPSIS 345 Traceback (most recent call last): 346 ... 347 SyntaxError: can't use starred expression here 348 349Some size constraints (all fail.) 350 351 >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)" 352 >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS 353 Traceback (most recent call last): 354 ... 355 SyntaxError: too many expressions in star-unpacking assignment 356 357 >>> s = ", ".join("a%d" % i for i in range(1<<8 + 1)) + ", *rest = range(1<<8 + 2)" 358 >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS 359 Traceback (most recent call last): 360 ... 361 SyntaxError: too many expressions in star-unpacking assignment 362 363(there is an additional limit, on the number of expressions after the 364'*rest', but it's 1<<24 and testing it takes too much memory.) 365 366""" 367 368__test__ = {'doctests' : doctests} 369 370def test_main(verbose=False): 371 from test import support 372 from test import test_unpack_ex 373 support.run_doctest(test_unpack_ex, verbose) 374 375if __name__ == "__main__": 376 test_main(verbose=True) 377