test_unpack_ex.py 9.9 KB

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