diff options
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_compiler.py | 32 | ||||
-rw-r--r-- | Lib/test/test_dictcomps.py | 54 | ||||
-rw-r--r-- | Lib/test/test_grammar.py | 7 | ||||
-rw-r--r-- | Lib/test/test_parser.py | 12 | ||||
-rw-r--r-- | Lib/test/test_setcomps.py | 151 |
5 files changed, 256 insertions, 0 deletions
diff --git a/Lib/test/test_compiler.py b/Lib/test/test_compiler.py index 8d4a3a995e..b54894da70 100644 --- a/Lib/test/test_compiler.py +++ b/Lib/test/test_compiler.py @@ -140,6 +140,36 @@ class CompilerTest(unittest.TestCase): 'eval') self.assertEquals(eval(c), [(0, 3), (1, 3), (2, 3)]) + def testSetLiteral(self): + c = compiler.compile('{1, 2, 3}', '<string>', 'eval') + self.assertEquals(eval(c), {1,2,3}) + c = compiler.compile('{1, 2, 3,}', '<string>', 'eval') + self.assertEquals(eval(c), {1,2,3}) + + def testDictLiteral(self): + c = compiler.compile('{1:2, 2:3, 3:4}', '<string>', 'eval') + self.assertEquals(eval(c), {1:2, 2:3, 3:4}) + c = compiler.compile('{1:2, 2:3, 3:4,}', '<string>', 'eval') + self.assertEquals(eval(c), {1:2, 2:3, 3:4}) + + def testSetComp(self): + c = compiler.compile('{x for x in range(1, 4)}', '<string>', 'eval') + self.assertEquals(eval(c), {1, 2, 3}) + c = compiler.compile('{x * y for x in range(3) if x != 0' + ' for y in range(4) if y != 0}', + '<string>', + 'eval') + self.assertEquals(eval(c), {1, 2, 3, 4, 6}) + + def testDictComp(self): + c = compiler.compile('{x:x+1 for x in range(1, 4)}', '<string>', 'eval') + self.assertEquals(eval(c), {1:2, 2:3, 3:4}) + c = compiler.compile('{(x, y) : y for x in range(2) if x != 0' + ' for y in range(3) if y != 0}', + '<string>', + 'eval') + self.assertEquals(eval(c), {(1, 2): 2, (1, 1): 1}) + def testWith(self): # SF bug 1638243 c = compiler.compile('from __future__ import with_statement\n' @@ -248,6 +278,8 @@ l[0] l[3:4] d = {'a': 2} d = {} +d = {x: y for x, y in zip(range(5), range(5,10))} +s = {x for x in range(10)} s = {1} t = () t = (1, 2) diff --git a/Lib/test/test_dictcomps.py b/Lib/test/test_dictcomps.py new file mode 100644 index 0000000000..9af9e48b2c --- /dev/null +++ b/Lib/test/test_dictcomps.py @@ -0,0 +1,54 @@ + +doctests = """ + + >>> k = "old value" + >>> { k: None for k in range(10) } + {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None} + >>> k + 'old value' + + >>> { k: k+10 for k in range(10) } + {0: 10, 1: 11, 2: 12, 3: 13, 4: 14, 5: 15, 6: 16, 7: 17, 8: 18, 9: 19} + + >>> g = "Global variable" + >>> { k: g for k in range(10) } + {0: 'Global variable', 1: 'Global variable', 2: 'Global variable', 3: 'Global variable', 4: 'Global variable', 5: 'Global variable', 6: 'Global variable', 7: 'Global variable', 8: 'Global variable', 9: 'Global variable'} + + >>> { k: v for k in range(10) for v in range(10) if k == v } + {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} + + >>> { k: v for v in range(10) for k in range(v*9, v*10) } + {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4, 38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6, 55: 6, 56: 6, 57: 6, 58: 6, 59: 6, 63: 7, 64: 7, 65: 7, 66: 7, 67: 7, 68: 7, 69: 7, 72: 8, 73: 8, 74: 8, 75: 8, 76: 8, 77: 8, 78: 8, 79: 8, 81: 9, 82: 9, 83: 9, 84: 9, 85: 9, 86: 9, 87: 9, 88: 9, 89: 9} + + >>> { x: y for y, x in ((1, 2), (3, 4)) } = 5 # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + SyntaxError: ... + + >>> { x: y for y, x in ((1, 2), (3, 4)) } += 5 # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + SyntaxError: ... + +""" + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_dictcomps + test_support.run_doctest(test_dictcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in range(len(counts)): + test_support.run_doctest(test_dictcomps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 4713d1ab78..12039e7c92 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -808,6 +808,13 @@ hello world pass self.assertEqual(G.decorated, True) + def testDictcomps(self): + # dictorsetmaker: ( (test ':' test (comp_for | + # (',' test ':' test)* [','])) | + # (test (comp_for | (',' test)* [','])) ) + nums = [1, 2, 3] + self.assertEqual({i:i+1 for i in nums}, {1: 2, 2: 3, 3: 4}) + def testListcomps(self): # list comprehension tests nums = [1, 2, 3, 4, 5] diff --git a/Lib/test/test_parser.py b/Lib/test/test_parser.py index 03803d9aaf..6ae99758d3 100644 --- a/Lib/test/test_parser.py +++ b/Lib/test/test_parser.py @@ -76,9 +76,20 @@ class RoundtripLegalSyntaxTestCase(unittest.TestCase): self.check_expr("[x**3 for x in range(20)]") self.check_expr("[x**3 for x in range(20) if x % 3]") self.check_expr("[x**3 for x in range(20) if x % 2 if x % 3]") + self.check_expr("[x+y for x in range(30) for y in range(20) if x % 2 if y % 3]") + #self.check_expr("[x for x in lambda: True, lambda: False if x()]") self.check_expr("list(x**3 for x in range(20))") self.check_expr("list(x**3 for x in range(20) if x % 3)") self.check_expr("list(x**3 for x in range(20) if x % 2 if x % 3)") + self.check_expr("list(x+y for x in range(30) for y in range(20) if x % 2 if y % 3)") + self.check_expr("{x**3 for x in range(30)}") + self.check_expr("{x**3 for x in range(30) if x % 3}") + self.check_expr("{x**3 for x in range(30) if x % 2 if x % 3}") + self.check_expr("{x+y for x in range(30) for y in range(20) if x % 2 if y % 3}") + self.check_expr("{x**3: y**2 for x, y in zip(range(30), range(30))}") + self.check_expr("{x**3: y**2 for x, y in zip(range(30), range(30)) if x % 3}") + self.check_expr("{x**3: y**2 for x, y in zip(range(30), range(30)) if x % 3 if y % 3}") + self.check_expr("{x:y for x in range(30) for y in range(20) if x % 2 if y % 3}") self.check_expr("foo(*args)") self.check_expr("foo(*args, **kw)") self.check_expr("foo(**kw)") @@ -107,6 +118,7 @@ class RoundtripLegalSyntaxTestCase(unittest.TestCase): self.check_expr("lambda foo=bar, blaz=blat+2, **z: 0") self.check_expr("lambda foo=bar, blaz=blat+2, *y, **z: 0") self.check_expr("lambda x, *y, **z: 0") + self.check_expr("lambda x: 5 if x else 2") self.check_expr("(x for x in range(10))") self.check_expr("foo(x for x in range(10))") diff --git a/Lib/test/test_setcomps.py b/Lib/test/test_setcomps.py new file mode 100644 index 0000000000..db5e6f7c97 --- /dev/null +++ b/Lib/test/test_setcomps.py @@ -0,0 +1,151 @@ +doctests = """ +########### Tests mostly copied from test_listcomps.py ############ + +Test simple loop with conditional + + >>> sum({i*i for i in range(100) if i&1 == 1}) + 166650 + +Test simple case + + >>> {2*y + x + 1 for x in (0,) for y in (1,)} + set([3]) + +Test simple nesting + + >>> list(sorted({(i,j) for i in range(3) for j in range(4)})) + [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] + +Test nesting with the inner expression dependent on the outer + + >>> list(sorted({(i,j) for i in range(4) for j in range(i)})) + [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] + +Make sure the induction variable is not exposed + + >>> i = 20 + >>> sum({i*i for i in range(100)}) + 328350 + + >>> i + 20 + +Verify that syntax error's are raised for setcomps used as lvalues + + >>> {y for y in (1,2)} = 10 # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + SyntaxError: ... + + >>> {y for y in (1,2)} += 10 # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + SyntaxError: ... + + +Make a nested set comprehension that acts like set(range()) + + >>> def srange(n): + ... return {i for i in range(n)} + >>> list(sorted(srange(10))) + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + +Same again, only as a lambda expression instead of a function definition + + >>> lrange = lambda n: {i for i in range(n)} + >>> list(sorted(lrange(10))) + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + +Generators can call other generators: + + >>> def grange(n): + ... for x in {i for i in range(n)}: + ... yield x + >>> list(sorted(grange(5))) + [0, 1, 2, 3, 4] + + +Make sure that None is a valid return value + + >>> {None for i in range(10)} + set([None]) + +########### Tests for various scoping corner cases ############ + +Return lambdas that use the iteration variable as a default argument + + >>> items = {(lambda i=i: i) for i in range(5)} + >>> {x() for x in items} == set(range(5)) + True + +Same again, only this time as a closure variable + + >>> items = {(lambda: i) for i in range(5)} + >>> {x() for x in items} + set([4]) + +Another way to test that the iteration variable is local to the list comp + + >>> items = {(lambda: i) for i in range(5)} + >>> i = 20 + >>> {x() for x in items} + set([4]) + +And confirm that a closure can jump over the list comp scope + + >>> items = {(lambda: y) for i in range(5)} + >>> y = 2 + >>> {x() for x in items} + set([2]) + +We also repeat each of the above scoping tests inside a function + + >>> def test_func(): + ... items = {(lambda i=i: i) for i in range(5)} + ... return {x() for x in items} + >>> test_func() == set(range(5)) + True + + >>> def test_func(): + ... items = {(lambda: i) for i in range(5)} + ... return {x() for x in items} + >>> test_func() + set([4]) + + >>> def test_func(): + ... items = {(lambda: i) for i in range(5)} + ... i = 20 + ... return {x() for x in items} + >>> test_func() + set([4]) + + >>> def test_func(): + ... items = {(lambda: y) for i in range(5)} + ... y = 2 + ... return {x() for x in items} + >>> test_func() + set([2]) + +""" + + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_setcomps + test_support.run_doctest(test_setcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in range(len(counts)): + test_support.run_doctest(test_setcomps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) |