| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- # Tests for extended unpacking, starred expressions.
- import doctest
- import unittest
- doctests = """
- Unpack tuple
- >>> t = (1, 2, 3)
- >>> a, *b, c = t
- >>> a == 1 and b == [2] and c == 3
- True
- Unpack list
- >>> l = [4, 5, 6]
- >>> a, *b = l
- >>> a == 4 and b == [5, 6]
- True
- Unpack implied tuple
- >>> *a, = 7, 8, 9
- >>> a == [7, 8, 9]
- True
- Unpack string... fun!
- >>> a, *b = 'one'
- >>> a == 'o' and b == ['n', 'e']
- True
- Unpack long sequence
- >>> a, b, c, *d, e, f, g = range(10)
- >>> (a, b, c, d, e, f, g) == (0, 1, 2, [3, 4, 5, 6], 7, 8, 9)
- True
- Unpack short sequence
- >>> a, *b, c = (1, 2)
- >>> a == 1 and c == 2 and b == []
- True
- Unpack generic sequence
- >>> class Seq:
- ... def __getitem__(self, i):
- ... if i >= 0 and i < 3: return i
- ... raise IndexError
- ...
- >>> a, *b = Seq()
- >>> a == 0 and b == [1, 2]
- True
- Unpack in for statement
- >>> for a, *b, c in [(1,2,3), (4,5,6,7)]:
- ... print(a, b, c)
- ...
- 1 [2] 3
- 4 [5, 6] 7
- Unpack in list
- >>> [a, *b, c] = range(5)
- >>> a == 0 and b == [1, 2, 3] and c == 4
- True
- Multiple targets
- >>> a, *b, c = *d, e = range(5)
- >>> a == 0 and b == [1, 2, 3] and c == 4 and d == [0, 1, 2, 3] and e == 4
- True
- Assignment unpacking
- >>> a, b, *c = range(5)
- >>> a, b, c
- (0, 1, [2, 3, 4])
- >>> *a, b, c = a, b, *c
- >>> a, b, c
- ([0, 1, 2], 3, 4)
- Set display element unpacking
- >>> a = [1, 2, 3]
- >>> sorted({1, *a, 0, 4})
- [0, 1, 2, 3, 4]
- >>> {1, *1, 0, 4}
- Traceback (most recent call last):
- ...
- TypeError: 'int' object is not iterable
- Dict display element unpacking
- >>> kwds = {'z': 0, 'w': 12}
- >>> sorted({'x': 1, 'y': 2, **kwds}.items())
- [('w', 12), ('x', 1), ('y', 2), ('z', 0)]
- >>> sorted({**{'x': 1}, 'y': 2, **{'z': 3}}.items())
- [('x', 1), ('y', 2), ('z', 3)]
- >>> sorted({**{'x': 1}, 'y': 2, **{'x': 3}}.items())
- [('x', 3), ('y', 2)]
- >>> sorted({**{'x': 1}, **{'x': 3}, 'x': 4}.items())
- [('x', 4)]
- >>> {**{}}
- {}
- >>> a = {}
- >>> {**a}[0] = 1
- >>> a
- {}
- >>> {**1}
- Traceback (most recent call last):
- ...
- TypeError: 'int' object is not a mapping
- >>> {**[]}
- Traceback (most recent call last):
- ...
- TypeError: 'list' object is not a mapping
- >>> len(eval("{" + ", ".join("**{{{}: {}}}".format(i, i)
- ... for i in range(1000)) + "}"))
- 1000
- >>> {0:1, **{0:2}, 0:3, 0:4}
- {0: 4}
- List comprehension element unpacking
- >>> a, b, c = [0, 1, 2], 3, 4
- >>> [*a, b, c]
- [0, 1, 2, 3, 4]
- >>> l = [a, (3, 4), {5}, {6: None}, (i for i in range(7, 10))]
- >>> [*item for item in l]
- Traceback (most recent call last):
- ...
- SyntaxError: iterable unpacking cannot be used in comprehension
- >>> [*[0, 1] for i in range(10)]
- Traceback (most recent call last):
- ...
- SyntaxError: iterable unpacking cannot be used in comprehension
- >>> [*'a' for i in range(10)]
- Traceback (most recent call last):
- ...
- SyntaxError: iterable unpacking cannot be used in comprehension
- >>> [*[] for i in range(10)]
- Traceback (most recent call last):
- ...
- SyntaxError: iterable unpacking cannot be used in comprehension
- >>> {**{} for a in [1]}
- Traceback (most recent call last):
- ...
- SyntaxError: dict unpacking cannot be used in dict comprehension
- # Pegen is better here.
- # Generator expression in function arguments
- # >>> list(*x for x in (range(5) for i in range(3)))
- # Traceback (most recent call last):
- # ...
- # list(*x for x in (range(5) for i in range(3)))
- # ^
- # SyntaxError: invalid syntax
- >>> dict(**x for x in [{1:2}])
- Traceback (most recent call last):
- ...
- dict(**x for x in [{1:2}])
- ^
- SyntaxError: invalid syntax
- Iterable argument unpacking
- >>> print(*[1], *[2], 3)
- 1 2 3
- Make sure that they don't corrupt the passed-in dicts.
- >>> def f(x, y):
- ... print(x, y)
- ...
- >>> original_dict = {'x': 1}
- >>> f(**original_dict, y=2)
- 1 2
- >>> original_dict
- {'x': 1}
- Now for some failures
- Make sure the raised errors are right for keyword argument unpackings
- >>> from collections.abc import MutableMapping
- >>> class CrazyDict(MutableMapping):
- ... def __init__(self):
- ... self.d = {}
- ...
- ... def __iter__(self):
- ... for x in self.d.__iter__():
- ... if x == 'c':
- ... self.d['z'] = 10
- ... yield x
- ...
- ... def __getitem__(self, k):
- ... return self.d[k]
- ...
- ... def __len__(self):
- ... return len(self.d)
- ...
- ... def __setitem__(self, k, v):
- ... self.d[k] = v
- ...
- ... def __delitem__(self, k):
- ... del self.d[k]
- ...
- >>> d = CrazyDict()
- >>> d.d = {chr(ord('a') + x): x for x in range(5)}
- >>> e = {**d}
- Traceback (most recent call last):
- ...
- RuntimeError: dictionary changed size during iteration
- >>> d.d = {chr(ord('a') + x): x for x in range(5)}
- >>> def f(**kwargs): print(kwargs)
- >>> f(**d)
- Traceback (most recent call last):
- ...
- RuntimeError: dictionary changed size during iteration
- Overridden parameters
- >>> f(x=5, **{'x': 3}, y=2)
- Traceback (most recent call last):
- ...
- TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
- >>> f(**{'x': 3}, x=5, y=2)
- Traceback (most recent call last):
- ...
- TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
- >>> f(**{'x': 3}, **{'x': 5}, y=2)
- Traceback (most recent call last):
- ...
- TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
- >>> f(x=5, **{'x': 3}, **{'x': 2})
- Traceback (most recent call last):
- ...
- TypeError: test.test_unpack_ex.f() got multiple values for keyword argument 'x'
- >>> f(**{1: 3}, **{1: 5})
- Traceback (most recent call last):
- ...
- TypeError: test.test_unpack_ex.f() got multiple values for keyword argument '1'
- Unpacking non-sequence
- >>> a, *b = 7
- Traceback (most recent call last):
- ...
- TypeError: cannot unpack non-iterable int object
- Unpacking sequence too short
- >>> a, *b, c, d, e = Seq()
- Traceback (most recent call last):
- ...
- ValueError: not enough values to unpack (expected at least 4, got 3)
- Unpacking sequence too short and target appears last
- >>> a, b, c, d, *e = Seq()
- Traceback (most recent call last):
- ...
- ValueError: not enough values to unpack (expected at least 4, got 3)
- Unpacking a sequence where the test for too long raises a different kind of
- error
- >>> class BozoError(Exception):
- ... pass
- ...
- >>> class BadSeq:
- ... def __getitem__(self, i):
- ... if i >= 0 and i < 3:
- ... return i
- ... elif i == 3:
- ... raise BozoError
- ... else:
- ... raise IndexError
- ...
- Trigger code while not expecting an IndexError (unpack sequence too long, wrong
- error)
- >>> a, *b, c, d, e = BadSeq()
- Traceback (most recent call last):
- ...
- test.test_unpack_ex.BozoError
- Now some general starred expressions (all fail).
- >>> a, *b, c, *d, e = range(10) # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: multiple starred expressions in assignment
- >>> [*b, *c] = range(10) # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: multiple starred expressions in assignment
- >>> a,*b,*c,*d = range(4) # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: multiple starred expressions in assignment
- >>> *a = range(10) # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: starred assignment target must be in a list or tuple
- >>> *a # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: can't use starred expression here
- >>> *1 # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: can't use starred expression here
- >>> x = *a # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: can't use starred expression here
- >>> (*x),y = 1, 2 # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: cannot use starred expression here
- >>> (((*x))),y = 1, 2 # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: cannot use starred expression here
- >>> z,(*x),y = 1, 2, 4 # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: cannot use starred expression here
- >>> z,(*x) = 1, 2 # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: cannot use starred expression here
- >>> ((*x),y) = 1, 2 # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: cannot use starred expression here
- Some size constraints (all fail.)
- >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)"
- >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: too many expressions in star-unpacking assignment
- >>> s = ", ".join("a%d" % i for i in range(1<<8 + 1)) + ", *rest = range(1<<8 + 2)"
- >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- SyntaxError: too many expressions in star-unpacking assignment
- (there is an additional limit, on the number of expressions after the
- '*rest', but it's 1<<24 and testing it takes too much memory.)
- """
- __test__ = {'doctests' : doctests}
- def load_tests(loader, tests, pattern):
- tests.addTest(doctest.DocTestSuite())
- return tests
- if __name__ == "__main__":
- unittest.main()
|