# Python code coverage for Lib/test/test_unpack_ex.py

# | count | content |
---|---|---|

1 | n/a | # Tests for extended unpacking, starred expressions. |

2 | n/a | |

3 | n/a | doctests = """ |

4 | n/a | |

5 | n/a | Unpack tuple |

6 | n/a | |

7 | n/a | >>> t = (1, 2, 3) |

8 | n/a | >>> a, *b, c = t |

9 | n/a | >>> a == 1 and b == [2] and c == 3 |

10 | n/a | True |

11 | n/a | |

12 | n/a | Unpack list |

13 | n/a | |

14 | n/a | >>> l = [4, 5, 6] |

15 | n/a | >>> a, *b = l |

16 | n/a | >>> a == 4 and b == [5, 6] |

17 | n/a | True |

18 | n/a | |

19 | n/a | Unpack implied tuple |

20 | n/a | |

21 | n/a | >>> *a, = 7, 8, 9 |

22 | n/a | >>> a == [7, 8, 9] |

23 | n/a | True |

24 | n/a | |

25 | n/a | Unpack string... fun! |

26 | n/a | |

27 | n/a | >>> a, *b = 'one' |

28 | n/a | >>> a == 'o' and b == ['n', 'e'] |

29 | n/a | True |

30 | n/a | |

31 | n/a | Unpack long sequence |

32 | n/a | |

33 | n/a | >>> a, b, c, *d, e, f, g = range(10) |

34 | n/a | >>> (a, b, c, d, e, f, g) == (0, 1, 2, [3, 4, 5, 6], 7, 8, 9) |

35 | n/a | True |

36 | n/a | |

37 | n/a | Unpack short sequence |

38 | n/a | |

39 | n/a | >>> a, *b, c = (1, 2) |

40 | n/a | >>> a == 1 and c == 2 and b == [] |

41 | n/a | True |

42 | n/a | |

43 | n/a | Unpack generic sequence |

44 | n/a | |

45 | n/a | >>> class Seq: |

46 | n/a | ... def __getitem__(self, i): |

47 | n/a | ... if i >= 0 and i < 3: return i |

48 | n/a | ... raise IndexError |

49 | n/a | ... |

50 | n/a | >>> a, *b = Seq() |

51 | n/a | >>> a == 0 and b == [1, 2] |

52 | n/a | True |

53 | n/a | |

54 | n/a | Unpack in for statement |

55 | n/a | |

56 | n/a | >>> for a, *b, c in [(1,2,3), (4,5,6,7)]: |

57 | n/a | ... print(a, b, c) |

58 | n/a | ... |

59 | n/a | 1 [2] 3 |

60 | n/a | 4 [5, 6] 7 |

61 | n/a | |

62 | n/a | Unpack in list |

63 | n/a | |

64 | n/a | >>> [a, *b, c] = range(5) |

65 | n/a | >>> a == 0 and b == [1, 2, 3] and c == 4 |

66 | n/a | True |

67 | n/a | |

68 | n/a | Multiple targets |

69 | n/a | |

70 | n/a | >>> a, *b, c = *d, e = range(5) |

71 | n/a | >>> a == 0 and b == [1, 2, 3] and c == 4 and d == [0, 1, 2, 3] and e == 4 |

72 | n/a | True |

73 | n/a | |

74 | n/a | Assignment unpacking |

75 | n/a | |

76 | n/a | >>> a, b, *c = range(5) |

77 | n/a | >>> a, b, c |

78 | n/a | (0, 1, [2, 3, 4]) |

79 | n/a | >>> *a, b, c = a, b, *c |

80 | n/a | >>> a, b, c |

81 | n/a | ([0, 1, 2], 3, 4) |

82 | n/a | |

83 | n/a | Set display element unpacking |

84 | n/a | |

85 | n/a | >>> a = [1, 2, 3] |

86 | n/a | >>> sorted({1, *a, 0, 4}) |

87 | n/a | [0, 1, 2, 3, 4] |

88 | n/a | |

89 | n/a | >>> {1, *1, 0, 4} |

90 | n/a | Traceback (most recent call last): |

91 | n/a | ... |

92 | n/a | TypeError: 'int' object is not iterable |

93 | n/a | |

94 | n/a | Dict display element unpacking |

95 | n/a | |

96 | n/a | >>> kwds = {'z': 0, 'w': 12} |

97 | n/a | >>> sorted({'x': 1, 'y': 2, **kwds}.items()) |

98 | n/a | [('w', 12), ('x', 1), ('y', 2), ('z', 0)] |

99 | n/a | |

100 | n/a | >>> sorted({**{'x': 1}, 'y': 2, **{'z': 3}}.items()) |

101 | n/a | [('x', 1), ('y', 2), ('z', 3)] |

102 | n/a | |

103 | n/a | >>> sorted({**{'x': 1}, 'y': 2, **{'x': 3}}.items()) |

104 | n/a | [('x', 3), ('y', 2)] |

105 | n/a | |

106 | n/a | >>> sorted({**{'x': 1}, **{'x': 3}, 'x': 4}.items()) |

107 | n/a | [('x', 4)] |

108 | n/a | |

109 | n/a | >>> {**{}} |

110 | n/a | {} |

111 | n/a | |

112 | n/a | >>> a = {} |

113 | n/a | >>> {**a}[0] = 1 |

114 | n/a | >>> a |

115 | n/a | {} |

116 | n/a | |

117 | n/a | >>> {**1} |

118 | n/a | Traceback (most recent call last): |

119 | n/a | ... |

120 | n/a | TypeError: 'int' object is not a mapping |

121 | n/a | |

122 | n/a | >>> {**[]} |

123 | n/a | Traceback (most recent call last): |

124 | n/a | ... |

125 | n/a | TypeError: 'list' object is not a mapping |

126 | n/a | |

127 | n/a | >>> len(eval("{" + ", ".join("**{{{}: {}}}".format(i, i) |

128 | n/a | ... for i in range(1000)) + "}")) |

129 | n/a | 1000 |

130 | n/a | |

131 | n/a | >>> {0:1, **{0:2}, 0:3, 0:4} |

132 | n/a | {0: 4} |

133 | n/a | |

134 | n/a | List comprehension element unpacking |

135 | n/a | |

136 | n/a | >>> a, b, c = [0, 1, 2], 3, 4 |

137 | n/a | >>> [*a, b, c] |

138 | n/a | [0, 1, 2, 3, 4] |

139 | n/a | |

140 | n/a | >>> l = [a, (3, 4), {5}, {6: None}, (i for i in range(7, 10))] |

141 | n/a | >>> [*item for item in l] |

142 | n/a | Traceback (most recent call last): |

143 | n/a | ... |

144 | n/a | SyntaxError: iterable unpacking cannot be used in comprehension |

145 | n/a | |

146 | n/a | >>> [*[0, 1] for i in range(10)] |

147 | n/a | Traceback (most recent call last): |

148 | n/a | ... |

149 | n/a | SyntaxError: iterable unpacking cannot be used in comprehension |

150 | n/a | |

151 | n/a | >>> [*'a' for i in range(10)] |

152 | n/a | Traceback (most recent call last): |

153 | n/a | ... |

154 | n/a | SyntaxError: iterable unpacking cannot be used in comprehension |

155 | n/a | |

156 | n/a | >>> [*[] for i in range(10)] |

157 | n/a | Traceback (most recent call last): |

158 | n/a | ... |

159 | n/a | SyntaxError: iterable unpacking cannot be used in comprehension |

160 | n/a | |

161 | n/a | Generator expression in function arguments |

162 | n/a | |

163 | n/a | >>> list(*x for x in (range(5) for i in range(3))) |

164 | n/a | Traceback (most recent call last): |

165 | n/a | ... |

166 | n/a | list(*x for x in (range(5) for i in range(3))) |

167 | n/a | ^ |

168 | n/a | SyntaxError: invalid syntax |

169 | n/a | |

170 | n/a | >>> dict(**x for x in [{1:2}]) |

171 | n/a | Traceback (most recent call last): |

172 | n/a | ... |

173 | n/a | dict(**x for x in [{1:2}]) |

174 | n/a | ^ |

175 | n/a | SyntaxError: invalid syntax |

176 | n/a | |

177 | n/a | Iterable argument unpacking |

178 | n/a | |

179 | n/a | >>> print(*[1], *[2], 3) |

180 | n/a | 1 2 3 |

181 | n/a | |

182 | n/a | Make sure that they don't corrupt the passed-in dicts. |

183 | n/a | |

184 | n/a | >>> def f(x, y): |

185 | n/a | ... print(x, y) |

186 | n/a | ... |

187 | n/a | >>> original_dict = {'x': 1} |

188 | n/a | >>> f(**original_dict, y=2) |

189 | n/a | 1 2 |

190 | n/a | >>> original_dict |

191 | n/a | {'x': 1} |

192 | n/a | |

193 | n/a | Now for some failures |

194 | n/a | |

195 | n/a | Make sure the raised errors are right for keyword argument unpackings |

196 | n/a | |

197 | n/a | >>> from collections.abc import MutableMapping |

198 | n/a | >>> class CrazyDict(MutableMapping): |

199 | n/a | ... def __init__(self): |

200 | n/a | ... self.d = {} |

201 | n/a | ... |

202 | n/a | ... def __iter__(self): |

203 | n/a | ... for x in self.d.__iter__(): |

204 | n/a | ... if x == 'c': |

205 | n/a | ... self.d['z'] = 10 |

206 | n/a | ... yield x |

207 | n/a | ... |

208 | n/a | ... def __getitem__(self, k): |

209 | n/a | ... return self.d[k] |

210 | n/a | ... |

211 | n/a | ... def __len__(self): |

212 | n/a | ... return len(self.d) |

213 | n/a | ... |

214 | n/a | ... def __setitem__(self, k, v): |

215 | n/a | ... self.d[k] = v |

216 | n/a | ... |

217 | n/a | ... def __delitem__(self, k): |

218 | n/a | ... del self.d[k] |

219 | n/a | ... |

220 | n/a | >>> d = CrazyDict() |

221 | n/a | >>> d.d = {chr(ord('a') + x): x for x in range(5)} |

222 | n/a | >>> e = {**d} |

223 | n/a | Traceback (most recent call last): |

224 | n/a | ... |

225 | n/a | RuntimeError: dictionary changed size during iteration |

226 | n/a | |

227 | n/a | >>> d.d = {chr(ord('a') + x): x for x in range(5)} |

228 | n/a | >>> def f(**kwargs): print(kwargs) |

229 | n/a | >>> f(**d) |

230 | n/a | Traceback (most recent call last): |

231 | n/a | ... |

232 | n/a | RuntimeError: dictionary changed size during iteration |

233 | n/a | |

234 | n/a | Overridden parameters |

235 | n/a | |

236 | n/a | >>> f(x=5, **{'x': 3}, y=2) |

237 | n/a | Traceback (most recent call last): |

238 | n/a | ... |

239 | n/a | TypeError: f() got multiple values for keyword argument 'x' |

240 | n/a | |

241 | n/a | >>> f(**{'x': 3}, x=5, y=2) |

242 | n/a | Traceback (most recent call last): |

243 | n/a | ... |

244 | n/a | TypeError: f() got multiple values for keyword argument 'x' |

245 | n/a | |

246 | n/a | >>> f(**{'x': 3}, **{'x': 5}, y=2) |

247 | n/a | Traceback (most recent call last): |

248 | n/a | ... |

249 | n/a | TypeError: f() got multiple values for keyword argument 'x' |

250 | n/a | |

251 | n/a | >>> f(x=5, **{'x': 3}, **{'x': 2}) |

252 | n/a | Traceback (most recent call last): |

253 | n/a | ... |

254 | n/a | TypeError: f() got multiple values for keyword argument 'x' |

255 | n/a | |

256 | n/a | >>> f(**{1: 3}, **{1: 5}) |

257 | n/a | Traceback (most recent call last): |

258 | n/a | ... |

259 | n/a | TypeError: f() keywords must be strings |

260 | n/a | |

261 | n/a | Unpacking non-sequence |

262 | n/a | |

263 | n/a | >>> a, *b = 7 |

264 | n/a | Traceback (most recent call last): |

265 | n/a | ... |

266 | n/a | TypeError: 'int' object is not iterable |

267 | n/a | |

268 | n/a | Unpacking sequence too short |

269 | n/a | |

270 | n/a | >>> a, *b, c, d, e = Seq() |

271 | n/a | Traceback (most recent call last): |

272 | n/a | ... |

273 | n/a | ValueError: not enough values to unpack (expected at least 4, got 3) |

274 | n/a | |

275 | n/a | Unpacking sequence too short and target appears last |

276 | n/a | |

277 | n/a | >>> a, b, c, d, *e = Seq() |

278 | n/a | Traceback (most recent call last): |

279 | n/a | ... |

280 | n/a | ValueError: not enough values to unpack (expected at least 4, got 3) |

281 | n/a | |

282 | n/a | Unpacking a sequence where the test for too long raises a different kind of |

283 | n/a | error |

284 | n/a | |

285 | n/a | >>> class BozoError(Exception): |

286 | n/a | ... pass |

287 | n/a | ... |

288 | n/a | >>> class BadSeq: |

289 | n/a | ... def __getitem__(self, i): |

290 | n/a | ... if i >= 0 and i < 3: |

291 | n/a | ... return i |

292 | n/a | ... elif i == 3: |

293 | n/a | ... raise BozoError |

294 | n/a | ... else: |

295 | n/a | ... raise IndexError |

296 | n/a | ... |

297 | n/a | |

298 | n/a | Trigger code while not expecting an IndexError (unpack sequence too long, wrong |

299 | n/a | error) |

300 | n/a | |

301 | n/a | >>> a, *b, c, d, e = BadSeq() |

302 | n/a | Traceback (most recent call last): |

303 | n/a | ... |

304 | n/a | test.test_unpack_ex.BozoError |

305 | n/a | |

306 | n/a | Now some general starred expressions (all fail). |

307 | n/a | |

308 | n/a | >>> a, *b, c, *d, e = range(10) # doctest:+ELLIPSIS |

309 | n/a | Traceback (most recent call last): |

310 | n/a | ... |

311 | n/a | SyntaxError: two starred expressions in assignment |

312 | n/a | |

313 | n/a | >>> [*b, *c] = range(10) # doctest:+ELLIPSIS |

314 | n/a | Traceback (most recent call last): |

315 | n/a | ... |

316 | n/a | SyntaxError: two starred expressions in assignment |

317 | n/a | |

318 | n/a | >>> *a = range(10) # doctest:+ELLIPSIS |

319 | n/a | Traceback (most recent call last): |

320 | n/a | ... |

321 | n/a | SyntaxError: starred assignment target must be in a list or tuple |

322 | n/a | |

323 | n/a | >>> *a # doctest:+ELLIPSIS |

324 | n/a | Traceback (most recent call last): |

325 | n/a | ... |

326 | n/a | SyntaxError: can't use starred expression here |

327 | n/a | |

328 | n/a | >>> *1 # doctest:+ELLIPSIS |

329 | n/a | Traceback (most recent call last): |

330 | n/a | ... |

331 | n/a | SyntaxError: can't use starred expression here |

332 | n/a | |

333 | n/a | >>> x = *a # doctest:+ELLIPSIS |

334 | n/a | Traceback (most recent call last): |

335 | n/a | ... |

336 | n/a | SyntaxError: can't use starred expression here |

337 | n/a | |

338 | n/a | Some size constraints (all fail.) |

339 | n/a | |

340 | n/a | >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)" |

341 | n/a | >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS |

342 | n/a | Traceback (most recent call last): |

343 | n/a | ... |

344 | n/a | SyntaxError: too many expressions in star-unpacking assignment |

345 | n/a | |

346 | n/a | >>> s = ", ".join("a%d" % i for i in range(1<<8 + 1)) + ", *rest = range(1<<8 + 2)" |

347 | n/a | >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS |

348 | n/a | Traceback (most recent call last): |

349 | n/a | ... |

350 | n/a | SyntaxError: too many expressions in star-unpacking assignment |

351 | n/a | |

352 | n/a | (there is an additional limit, on the number of expressions after the |

353 | n/a | '*rest', but it's 1<<24 and testing it takes too much memory.) |

354 | n/a | |

355 | n/a | """ |

356 | n/a | |

357 | n/a | __test__ = {'doctests' : doctests} |

358 | n/a | |

359 | n/a | def test_main(verbose=False): |

360 | n/a | from test import support |

361 | n/a | from test import test_unpack_ex |

362 | n/a | support.run_doctest(test_unpack_ex, verbose) |

363 | n/a | |

364 | n/a | if __name__ == "__main__": |

365 | n/a | test_main(verbose=True) |