diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2007-04-15 12:05:43 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2007-04-15 12:05:43 (GMT) |
commit | 650f0d06d3574f843f52edd1126ddd9ebd6fac7d (patch) | |
tree | 9116cebfb4031d0ac3b2db7dc0e8c85d82751e59 /Lib | |
parent | 6ef6306dd62aa092539298ed69c7c6ffff568e2d (diff) | |
download | cpython-650f0d06d3574f843f52edd1126ddd9ebd6fac7d.zip cpython-650f0d06d3574f843f52edd1126ddd9ebd6fac7d.tar.gz cpython-650f0d06d3574f843f52edd1126ddd9ebd6fac7d.tar.bz2 |
Hide list comp variables and support set comprehensions
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/compiler/transformer.py | 4 | ||||
-rw-r--r-- | Lib/decimal.py | 2 | ||||
-rw-r--r-- | Lib/opcode.py | 1 | ||||
-rw-r--r-- | Lib/pickle.py | 1 | ||||
-rw-r--r-- | Lib/test/test_datetime.py | 4 | ||||
-rw-r--r-- | Lib/test/test_dis.py | 8 | ||||
-rw-r--r-- | Lib/test/test_grammar.py | 3 | ||||
-rw-r--r-- | Lib/test/test_listcomps.py | 444 | ||||
-rw-r--r-- | Lib/test/test_setcomps.py | 453 | ||||
-rw-r--r-- | Lib/test/test_syntax.py | 4 | ||||
-rw-r--r-- | Lib/test/test_univnewlines.py | 1 | ||||
-rw-r--r-- | Lib/tokenize.py | 1 |
12 files changed, 912 insertions, 14 deletions
diff --git a/Lib/compiler/transformer.py b/Lib/compiler/transformer.py index 3d4bb4f..48de750 100644 --- a/Lib/compiler/transformer.py +++ b/Lib/compiler/transformer.py @@ -559,7 +559,7 @@ class Transformer: testlist1 = testlist exprlist = testlist - def testlist_gexp(self, nodelist): + def testlist_comp(self, nodelist): if len(nodelist) == 2 and nodelist[1][0] == symbol.gen_for: test = self.com_node(nodelist[0]) return self.com_generator_expression(test, nodelist[1]) @@ -1027,7 +1027,7 @@ class Transformer: # loop to avoid trivial recursion while 1: t = node[0] - if t in (symbol.exprlist, symbol.testlist, symbol.testlist_safe, symbol.testlist_gexp): + if t in (symbol.exprlist, symbol.testlist, symbol.testlist_comp): if len(node) > 2: return self.com_assign_tuple(node, assigning) node = node[1] diff --git a/Lib/decimal.py b/Lib/decimal.py index 74b23b6..148b626 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -2282,10 +2282,8 @@ class Context(object): _ignored_flags = [] if not isinstance(flags, dict): flags = dict([(s,s in flags) for s in _signals]) - del s if traps is not None and not isinstance(traps, dict): traps = dict([(s,s in traps) for s in _signals]) - del s for name, val in locals().items(): if val is None: setattr(self, name, _copy.copy(getattr(DefaultContext, name))) diff --git a/Lib/opcode.py b/Lib/opcode.py index 61b288a..4125a79 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -57,6 +57,7 @@ def_op('UNARY_NOT', 12) def_op('UNARY_INVERT', 15) +def_op('SET_ADD', 17) def_op('LIST_APPEND', 18) def_op('BINARY_POWER', 19) def_op('BINARY_MULTIPLY', 20) diff --git a/Lib/pickle.py b/Lib/pickle.py index 3d2ebd2..8e772e7 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -163,7 +163,6 @@ _tuplesize2code = [EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3] __all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$",x)]) -del x # Pickling machinery diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py index 6b4c667..8a7c1b6 100644 --- a/Lib/test/test_datetime.py +++ b/Lib/test/test_datetime.py @@ -20,9 +20,9 @@ from datetime import time from datetime import date, datetime pickle_choices = [(pickler, unpickler, proto) - for pickler in pickle, cPickle + for pickler in (pickle, cPickle) if pickler is not None - for unpickler in pickle, cPickle + for unpickler in (pickle, cPickle) if unpickler is not None for proto in range(3)] if cPickle is None: diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index bb8638b..8e97a6a 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -129,8 +129,12 @@ class DisTests(unittest.TestCase): def test_bug_1333982(self): # This one is checking bytecodes generated for an `assert` statement, # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) + pass # Test has been disabled due to change in the way + # list comps are handled. The byte code now includes + # a memory address and a file location, so they change from + # run to run. + # if __debug__: + # self.do_disassembly_test(bug1333982, dis_bug1333982) def test_big_linenos(self): def func(count): diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index bd80db6..2c1b6ca 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -843,7 +843,8 @@ class GrammarTests(unittest.TestCase): print(x) return ret - self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True]) + # the next line is not allowed anymore + #self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True]) self.assertEqual([ x() for x in (lambda: True, lambda: False) if x() ], [True]) self.assertEqual([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ], [True]) self.assertEqual((5 if 1 else _checkeval("check 1", 0)), 5) diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py new file mode 100644 index 0000000..bef4fff --- /dev/null +++ b/Lib/test/test_listcomps.py @@ -0,0 +1,444 @@ +doctests = """ +########### Tests borrowed from or inspired by test_genexps.py ############ + +Test simple loop with conditional + + >>> sum([i*i for i in range(100) if i&1 == 1]) + 166650 + +Test simple nesting + + >>> [(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 + + >>> [(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 listcomps 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: ... + + +########### Tests borrowed from or inspired by test_generators.py ############ + +Make a nested list comprehension that acts like range() + + >>> def frange(n): + ... return [i for i in xrange(n)] + >>> frange(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 xrange(n)] + >>> 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 xrange(n)]: + ... yield x + >>> list(grange(5)) + [0, 1, 2, 3, 4] + + +Make sure that None is a valid return value + + >>> [None for i in xrange(10)] + [None, None, None, None, None, None, None, None, None, 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] + [0, 1, 2, 3, 4] + +Same again, only this time as a closure variable + + >>> items = [(lambda: i) for i in range(5)] + >>> [x() for x in items] + [4, 4, 4, 4, 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] + [4, 4, 4, 4, 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] + [2, 2, 2, 2, 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() + [0, 1, 2, 3, 4] + + >>> def test_func(): + ... items = [(lambda: i) for i in range(5)] + ... return [x() for x in items] + >>> test_func() + [4, 4, 4, 4, 4] + + >>> def test_func(): + ... items = [(lambda: i) for i in range(5)] + ... i = 20 + ... return [x() for x in items] + >>> test_func() + [4, 4, 4, 4, 4] + + >>> def test_func(): + ... items = [(lambda: y) for i in range(5)] + ... y = 2 + ... return [x() for x in items] + >>> test_func() + [2, 2, 2, 2, 2] + +""" + + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_listcomps + test_support.run_doctest(test_listcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in xrange(len(counts)): + test_support.run_doctest(test_genexps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) +doctests = """ +########### Tests borrowed from or inspired by test_genexps.py ############ + +Test simple loop with conditional + + >>> sum([i*i for i in range(100) if i&1 == 1]) + 166650 + +Test simple nesting + + >>> [(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 + + >>> [(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 listcomps 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: ... + + +########### Tests borrowed from or inspired by test_generators.py ############ + +Make a nested list comprehension that acts like range() + + >>> def frange(n): + ... return [i for i in xrange(n)] + >>> frange(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 xrange(n)] + >>> 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 xrange(n)]: + ... yield x + >>> list(grange(5)) + [0, 1, 2, 3, 4] + + +Make sure that None is a valid return value + + >>> [None for i in xrange(10)] + [None, None, None, None, None, None, None, None, None, 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] + [0, 1, 2, 3, 4] + +Same again, only this time as a closure variable + + >>> items = [(lambda: i) for i in range(5)] + >>> [x() for x in items] + [4, 4, 4, 4, 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] + [4, 4, 4, 4, 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] + [2, 2, 2, 2, 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() + [0, 1, 2, 3, 4] + + >>> def test_func(): + ... items = [(lambda: i) for i in range(5)] + ... return [x() for x in items] + >>> test_func() + [4, 4, 4, 4, 4] + + >>> def test_func(): + ... items = [(lambda: i) for i in range(5)] + ... i = 20 + ... return [x() for x in items] + >>> test_func() + [4, 4, 4, 4, 4] + + >>> def test_func(): + ... items = [(lambda: y) for i in range(5)] + ... y = 2 + ... return [x() for x in items] + >>> test_func() + [2, 2, 2, 2, 2] + +""" + + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_listcomps + test_support.run_doctest(test_listcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in xrange(len(counts)): + test_support.run_doctest(test_genexps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) +doctests = """ +########### Tests borrowed from or inspired by test_genexps.py ############ + +Test simple loop with conditional + + >>> sum([i*i for i in range(100) if i&1 == 1]) + 166650 + +Test simple nesting + + >>> [(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 + + >>> [(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 listcomps 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: ... + + +########### Tests borrowed from or inspired by test_generators.py ############ + +Make a nested list comprehension that acts like range() + + >>> def frange(n): + ... return [i for i in xrange(n)] + >>> frange(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 xrange(n)] + >>> 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 xrange(n)]: + ... yield x + >>> list(grange(5)) + [0, 1, 2, 3, 4] + + +Make sure that None is a valid return value + + >>> [None for i in xrange(10)] + [None, None, None, None, None, None, None, None, None, 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] + [0, 1, 2, 3, 4] + +Same again, only this time as a closure variable + + >>> items = [(lambda: i) for i in range(5)] + >>> [x() for x in items] + [4, 4, 4, 4, 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] + [4, 4, 4, 4, 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] + [2, 2, 2, 2, 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() + [0, 1, 2, 3, 4] + + >>> def test_func(): + ... items = [(lambda: i) for i in range(5)] + ... return [x() for x in items] + >>> test_func() + [4, 4, 4, 4, 4] + + >>> def test_func(): + ... items = [(lambda: i) for i in range(5)] + ... i = 20 + ... return [x() for x in items] + >>> test_func() + [4, 4, 4, 4, 4] + + >>> def test_func(): + ... items = [(lambda: y) for i in range(5)] + ... y = 2 + ... return [x() for x in items] + >>> test_func() + [2, 2, 2, 2, 2] + +""" + + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_listcomps + test_support.run_doctest(test_listcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in xrange(len(counts)): + test_support.run_doctest(test_genexps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) diff --git a/Lib/test/test_setcomps.py b/Lib/test/test_setcomps.py new file mode 100644 index 0000000..c64e53e --- /dev/null +++ b/Lib/test/test_setcomps.py @@ -0,0 +1,453 @@ +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,)} + {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(xrange()) + + >>> def srange(n): + ... return {i for i in xrange(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 xrange(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 xrange(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 xrange(10)} + {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} + {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} + {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} + {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() + {4} + + >>> def test_func(): + ... items = {(lambda: i) for i in range(5)} + ... i = 20 + ... return {x() for x in items} + >>> test_func() + {4} + + >>> def test_func(): + ... items = {(lambda: y) for i in range(5)} + ... y = 2 + ... return {x() for x in items} + >>> test_func() + {2} + +""" + + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_listcomps + test_support.run_doctest(test_listcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in xrange(len(counts)): + test_support.run_doctest(test_genexps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) +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,)} + {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(xrange()) + + >>> def srange(n): + ... return {i for i in xrange(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 xrange(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 xrange(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 xrange(10)} + {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} + {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} + {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} + {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() + {4} + + >>> def test_func(): + ... items = {(lambda: i) for i in range(5)} + ... i = 20 + ... return {x() for x in items} + >>> test_func() + {4} + + >>> def test_func(): + ... items = {(lambda: y) for i in range(5)} + ... y = 2 + ... return {x() for x in items} + >>> test_func() + {2} + +""" + + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_listcomps + test_support.run_doctest(test_listcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in xrange(len(counts)): + test_support.run_doctest(test_genexps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) +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,)} + {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(xrange()) + + >>> def srange(n): + ... return {i for i in xrange(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 xrange(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 xrange(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 xrange(10)} + {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} + {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} + {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} + {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() + {4} + + >>> def test_func(): + ... items = {(lambda: i) for i in range(5)} + ... i = 20 + ... return {x() for x in items} + >>> test_func() + {4} + + >>> def test_func(): + ... items = {(lambda: y) for i in range(5)} + ... y = 2 + ... return {x() for x in items} + >>> test_func() + {2} + +""" + + +__test__ = {'doctests' : doctests} + +def test_main(verbose=None): + import sys + from test import test_support + from test import test_listcomps + test_support.run_doctest(test_listcomps, verbose) + + # verify reference counting + if verbose and hasattr(sys, "gettotalrefcount"): + import gc + counts = [None] * 5 + for i in xrange(len(counts)): + test_support.run_doctest(test_genexps, verbose) + gc.collect() + counts[i] = sys.gettotalrefcount() + print(counts) + +if __name__ == "__main__": + test_main(verbose=True) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index f37b666..b21f6cf 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -5,7 +5,7 @@ Here's an example of the sort of thing that is tested. >>> def f(x): ... global x Traceback (most recent call last): -SyntaxError: name 'x' is local and global +SyntaxError: name 'x' is parameter and global The tests are all raise SyntaxErrors. They were created by checking each C call that raises SyntaxError. There are several modules that @@ -373,7 +373,7 @@ Misuse of the nonlocal statement can lead to a few unique syntax errors. ... nonlocal x Traceback (most recent call last): ... - SyntaxError: name 'x' is local and nonlocal + SyntaxError: name 'x' is parameter and nonlocal >>> def f(): ... global x diff --git a/Lib/test/test_univnewlines.py b/Lib/test/test_univnewlines.py index 922c184..ae4c442 100644 --- a/Lib/test/test_univnewlines.py +++ b/Lib/test/test_univnewlines.py @@ -28,7 +28,6 @@ DATA_CRLF = "\r\n".join(DATA_TEMPLATE) + "\r\n" # before end-of-file. DATA_MIXED = "\n".join(DATA_TEMPLATE) + "\r" DATA_SPLIT = [x + "\n" for x in DATA_TEMPLATE] -del x class TestGenericUnivNewlines(unittest.TestCase): # use a class variable DATA to define the data to write to the file diff --git a/Lib/tokenize.py b/Lib/tokenize.py index cda82ca..8dc4c53 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -32,7 +32,6 @@ from token import * import token __all__ = [x for x in dir(token) if x[0] != '_'] + ["COMMENT", "tokenize", "generate_tokens", "NL", "untokenize"] -del x del token COMMENT = N_TOKENS |