blob: 049e48b13fa1f90d9d14ec2439c272f0eea801b5 [file] [log] [blame]
Guido van Rossum0368b722007-05-11 16:50:42 +00001# 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
Benjamin Peterson025e9eb2015-05-05 20:16:41 -040074Assignment 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
Benjamin Petersond5d77aa2015-07-05 10:37:25 -0500131 >>> {0:1, **{0:2}, 0:3, 0:4}
132 {0: 4}
133
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400134List 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
Batuhan Taskayab8a65ec2020-05-22 01:39:56 +0300161 >>> {**{} for a in [1]}
162 Traceback (most recent call last):
163 ...
164 SyntaxError: dict unpacking cannot be used in dict comprehension
165
Pablo Galindoc5fc1562020-04-22 23:29:27 +0100166# Pegen is better here.
167# Generator expression in function arguments
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400168
Pablo Galindoc5fc1562020-04-22 23:29:27 +0100169# >>> 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
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400175
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
Guido van Rossum0368b722007-05-11 16:50:42 +0000199Now for some failures
200
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400201Make 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 ...
Jeroen Demeyerbf17d412019-11-05 16:48:04 +0100245 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400246
247 >>> f(**{'x': 3}, x=5, y=2)
248 Traceback (most recent call last):
249 ...
Jeroen Demeyerbf17d412019-11-05 16:48:04 +0100250 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400251
252 >>> f(**{'x': 3}, **{'x': 5}, y=2)
253 Traceback (most recent call last):
254 ...
Jeroen Demeyerbf17d412019-11-05 16:48:04 +0100255 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400256
Serhiy Storchaka3c317e72016-06-12 09:22:01 +0300257 >>> f(x=5, **{'x': 3}, **{'x': 2})
258 Traceback (most recent call last):
259 ...
Jeroen Demeyerbf17d412019-11-05 16:48:04 +0100260 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
Serhiy Storchaka3c317e72016-06-12 09:22:01 +0300261
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400262 >>> f(**{1: 3}, **{1: 5})
263 Traceback (most recent call last):
264 ...
Jeroen Demeyerbf17d412019-11-05 16:48:04 +0100265 TypeError: test.test_unpack_ex.f() got multiple values for keyword argument '1'
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400266
Guido van Rossum0368b722007-05-11 16:50:42 +0000267Unpacking non-sequence
268
269 >>> a, *b = 7
270 Traceback (most recent call last):
271 ...
Serhiy Storchaka13a6c092017-12-26 12:30:41 +0200272 TypeError: cannot unpack non-iterable int object
Guido van Rossum0368b722007-05-11 16:50:42 +0000273
274Unpacking sequence too short
275
276 >>> a, *b, c, d, e = Seq()
277 Traceback (most recent call last):
278 ...
R David Murray4171bbe2015-04-15 17:08:45 -0400279 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)
Guido van Rossum0368b722007-05-11 16:50:42 +0000287
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 ...
Furkan Öndercb6534e2020-03-26 04:54:31 +0300317 SyntaxError: multiple starred expressions in assignment
Guido van Rossum0368b722007-05-11 16:50:42 +0000318
319 >>> [*b, *c] = range(10) # doctest:+ELLIPSIS
320 Traceback (most recent call last):
321 ...
Furkan Öndercb6534e2020-03-26 04:54:31 +0300322 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
Guido van Rossum0368b722007-05-11 16:50:42 +0000328
329 >>> *a = range(10) # doctest:+ELLIPSIS
330 Traceback (most recent call last):
331 ...
Guido van Rossum33d26892007-08-05 15:29:28 +0000332 SyntaxError: starred assignment target must be in a list or tuple
Guido van Rossum0368b722007-05-11 16:50:42 +0000333
334 >>> *a # doctest:+ELLIPSIS
335 Traceback (most recent call last):
336 ...
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400337 SyntaxError: can't use starred expression here
Guido van Rossum0368b722007-05-11 16:50:42 +0000338
339 >>> *1 # doctest:+ELLIPSIS
340 Traceback (most recent call last):
341 ...
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400342 SyntaxError: can't use starred expression here
Guido van Rossum0368b722007-05-11 16:50:42 +0000343
344 >>> x = *a # doctest:+ELLIPSIS
345 Traceback (most recent call last):
346 ...
Benjamin Peterson025e9eb2015-05-05 20:16:41 -0400347 SyntaxError: can't use starred expression here
Guido van Rossum0368b722007-05-11 16:50:42 +0000348
Lysandros Nikolaou2ea320d2021-01-03 01:14:21 +0200349 >>> (*x),y = 1, 2 # doctest:+ELLIPSIS
350 Traceback (most recent call last):
351 ...
352 SyntaxError: can't use starred expression here
353
354 >>> (((*x))),y = 1, 2 # doctest:+ELLIPSIS
355 Traceback (most recent call last):
356 ...
357 SyntaxError: can't use starred expression here
358
359 >>> z,(*x),y = 1, 2, 4 # doctest:+ELLIPSIS
360 Traceback (most recent call last):
361 ...
362 SyntaxError: can't use starred expression here
363
364 >>> z,(*x) = 1, 2 # doctest:+ELLIPSIS
365 Traceback (most recent call last):
366 ...
367 SyntaxError: can't use starred expression here
368
369 >>> ((*x),y) = 1, 2 # doctest:+ELLIPSIS
370 Traceback (most recent call last):
371 ...
372 SyntaxError: can't use starred expression here
373
Thomas Woutersdeef6742008-03-14 17:16:59 +0000374Some size constraints (all fail.)
375
376 >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)"
377 >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS
378 Traceback (most recent call last):
379 ...
380 SyntaxError: too many expressions in star-unpacking assignment
381
382 >>> s = ", ".join("a%d" % i for i in range(1<<8 + 1)) + ", *rest = range(1<<8 + 2)"
383 >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS
384 Traceback (most recent call last):
385 ...
386 SyntaxError: too many expressions in star-unpacking assignment
387
388(there is an additional limit, on the number of expressions after the
389'*rest', but it's 1<<24 and testing it takes too much memory.)
390
Guido van Rossum0368b722007-05-11 16:50:42 +0000391"""
392
393__test__ = {'doctests' : doctests}
394
395def test_main(verbose=False):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000396 from test import support
Guido van Rossum0368b722007-05-11 16:50:42 +0000397 from test import test_unpack_ex
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000398 support.run_doctest(test_unpack_ex, verbose)
Guido van Rossum0368b722007-05-11 16:50:42 +0000399
400if __name__ == "__main__":
401 test_main(verbose=True)