]> granicus.if.org Git - python/commitdiff
Merged revisions 66453 via svnmerge from
authorBenjamin Peterson <benjamin@python.org>
Sat, 13 Sep 2008 18:37:09 +0000 (18:37 +0000)
committerBenjamin Peterson <benjamin@python.org>
Sat, 13 Sep 2008 18:37:09 +0000 (18:37 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

................
  r66453 | benjamin.peterson | 2008-09-13 12:43:19 -0500 (Sat, 13 Sep 2008) | 24 lines

  Merged revisions 66191,66418,66438,66445 via svnmerge from
  svn+ssh://pythondev@svn.python.org/sandbox/trunk/2to3/lib2to3

  ........
    r66191 | benjamin.peterson | 2008-09-03 17:00:52 -0500 (Wed, 03 Sep 2008) | 1 line

    update the Grammar file after recent syntax changes
  ........
    r66418 | benjamin.peterson | 2008-09-12 18:49:48 -0500 (Fri, 12 Sep 2008) | 1 line

    a trival fix to get a few more print corner cases #2899
  ........
    r66438 | benjamin.peterson | 2008-09-12 21:32:30 -0500 (Fri, 12 Sep 2008) | 5 lines

    add Jack Diederich's fixer for metaclass syntax #2366

    my contribution to this was adding a few tests and fixing a few bugs
    I also reviewed it (Jack is a committer)
  ........
    r66445 | benjamin.peterson | 2008-09-13 10:50:00 -0500 (Sat, 13 Sep 2008) | 1 line

    add a few more tests concerning int literals and weird spacing
  ........
................

Lib/lib2to3/Grammar.txt
Lib/lib2to3/fixes/fix_metaclass.py [new file with mode: 0644]
Lib/lib2to3/fixes/fix_print.py
Lib/lib2to3/tests/data/py2_test_grammar.py
Lib/lib2to3/tests/data/py3_test_grammar.py
Lib/lib2to3/tests/test_fixers.py

index abf1e1582e1d07d2442d8811b6266e3e272d7370..1f4a50ffbe0774bc994e95d2c9309aa8b5cbc041 100644 (file)
@@ -138,7 +138,9 @@ dictsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
 
 classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
 
-arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
+arglist: (argument ',')* (argument [',']
+                         |'*' test (',' argument)* [',' '**' test] 
+                         |'**' test)
 argument: test [comp_for] | test '=' test  # Really [keyword '='] test
 
 comp_iter: comp_for | comp_if
diff --git a/Lib/lib2to3/fixes/fix_metaclass.py b/Lib/lib2to3/fixes/fix_metaclass.py
new file mode 100644 (file)
index 0000000..e291dd7
--- /dev/null
@@ -0,0 +1,227 @@
+"""Fixer for __metaclass__ = X -> (metaclass=X) methods.
+
+   The various forms of classef (inherits nothing, inherits once, inherints
+   many) don't parse the same in the CST so we look at ALL classes for
+   a __metaclass__ and if we find one normalize the inherits to all be
+   an arglist.
+
+   For one-liner classes ('class X: pass') there is no indent/dedent so
+   we normalize those into having a suite.
+
+   Moving the __metaclass__ into the classdef can also cause the class
+   body to be empty so there is some special casing for that as well.
+
+   This fixer also tries very hard to keep original indenting and spacing
+   in all those corner cases.
+
+"""
+# Author: Jack Diederich
+
+import os
+
+# Local imports
+from .. import fixer_base
+from ..pygram import token
+from ..fixer_util import Name, syms, Node, Leaf
+
+
+def has_metaclass(parent):
+    """ we have to check the cls_node without changing it.
+        There are two possiblities:
+          1)  clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta')
+          2)  clsdef => simple_stmt => expr_stmt => Leaf('__meta')
+    """
+    for node in parent.children:
+        if node.type == syms.suite:
+            return has_metaclass(node)
+        elif node.type == syms.simple_stmt and node.children:
+            expr_node = node.children[0]
+            if expr_node.type == syms.expr_stmt and expr_node.children:
+                leaf_node = expr_node.children[0]
+                if leaf_node.value == '__metaclass__':
+                    return True
+    return False
+
+
+def fixup_parse_tree(cls_node):
+    """ one-line classes don't get a suite in the parse tree so we add
+        one to normalize the tree
+    """
+    for node in cls_node.children:
+        if node.type == syms.suite:
+            # already in the prefered format, do nothing
+            return
+
+    # !%@#! oneliners have no suite node, we have to fake one up
+    for i, node in enumerate(cls_node.children):
+        if node.type == token.COLON:
+            break
+    else:
+        raise ValueError("No class suite and no ':'!")
+
+    # move everything into a suite node
+    suite = Node(syms.suite, [])
+    while cls_node.children[i+1:]:
+        move_node = cls_node.children[i+1]
+        suite.append_child(move_node.clone())
+        move_node.remove()
+    cls_node.append_child(suite)
+    node = suite
+
+
+def fixup_simple_stmt(parent, i, stmt_node):
+    """ if there is a semi-colon all the parts count as part of the same
+        simple_stmt.  We just want the __metaclass__ part so we move
+        everything efter the semi-colon into its own simple_stmt node
+    """
+    for semi_ind, node in enumerate(stmt_node.children):
+        if node.type == token.SEMI: # *sigh*
+            break
+    else:
+        return
+
+    node.remove() # kill the semicolon
+    new_expr = Node(syms.expr_stmt, [])
+    new_stmt = Node(syms.simple_stmt, [new_expr])
+    while stmt_node.children[semi_ind:]:
+        move_node = stmt_node.children[semi_ind]
+        new_expr.append_child(move_node.clone())
+        move_node.remove()
+    parent.insert_child(i, new_stmt)
+    new_leaf1 = new_stmt.children[0].children[0]
+    old_leaf1 = stmt_node.children[0].children[0]
+    new_leaf1.set_prefix(old_leaf1.get_prefix())
+
+
+def remove_trailing_newline(node):
+    if node.children and node.children[-1].type == token.NEWLINE:
+        node.children[-1].remove()
+
+
+def find_metas(cls_node):
+    # find the suite node (Mmm, sweet nodes)
+    for node in cls_node.children:
+        if node.type == syms.suite:
+            break
+    else:
+        raise ValueError("No class suite!")
+
+    # look for simple_stmt[ expr_stmt[ Leaf('__metaclass__') ] ]
+    for i, simple_node in list(enumerate(node.children)):
+        if simple_node.type == syms.simple_stmt and simple_node.children:
+            expr_node = simple_node.children[0]
+            if expr_node.type == syms.expr_stmt and expr_node.children:
+                leaf_node = expr_node.children[0]
+                if leaf_node.value == '__metaclass__':
+                    fixup_simple_stmt(node, i, simple_node)
+                    remove_trailing_newline(simple_node)
+                    yield (node, i, simple_node)
+
+
+def fixup_indent(suite):
+    """ If an INDENT is followed by a thing with a prefix then nuke the prefix
+        Otherwise we get in trouble when removing __metaclass__ at suite start
+    """
+    kids = suite.children[::-1]
+    # find the first indent
+    while kids:
+        node = kids.pop()
+        if node.type == token.INDENT:
+            break
+
+    # find the first Leaf
+    while kids:
+        node = kids.pop()
+        if isinstance(node, Leaf) and node.type != token.DEDENT:
+            if node.prefix:
+                node.set_prefix('')
+            return
+        else:
+            kids.extend(node.children[::-1])
+
+
+class FixMetaclass(fixer_base.BaseFix):
+
+    PATTERN = """
+    classdef<any*>
+    """
+
+    def transform(self, node, results):
+        if not has_metaclass(node):
+            return node
+
+        fixup_parse_tree(node)
+
+        # find metaclasses, keep the last one
+        last_metaclass = None
+        for suite, i, stmt in find_metas(node):
+            last_metaclass = stmt
+            stmt.remove()
+
+        text_type = node.children[0].type # always Leaf(nnn, 'class')
+
+        # figure out what kind of classdef we have
+        if len(node.children) == 7:
+            # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite])
+            #                 0        1       2    3        4    5    6
+            if node.children[3].type == syms.arglist:
+                arglist = node.children[3]
+            # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite])
+            elif isinstance(node.children[3], Leaf):
+                parent = node.children[3].clone()
+                arglist = Node(syms.arglist, [parent])
+                node.set_child(3, arglist)
+            else:
+                raise ValueError("Unexpected class inheritance arglist")
+        elif len(node.children) == 6:
+            # Node(classdef, ['class', 'name', '(',  ')', ':', suite])
+            #                 0        1       2     3    4    5
+            arglist = Node(syms.arglist, [])
+            node.insert_child(3, arglist)
+        elif len(node.children) == 4:
+            # Node(classdef, ['class', 'name', ':', suite])
+            #                 0        1       2    3
+            arglist = Node(syms.arglist, [])
+            node.insert_child(2, Leaf(token.RPAR, ')'))
+            node.insert_child(2, arglist)
+            node.insert_child(2, Leaf(token.LPAR, '('))
+        else:
+            raise ValueError("Unexpected class definition")
+
+        # now stick the metaclass in the arglist
+        meta_txt = last_metaclass.children[0].children[0]
+        meta_txt.value = 'metaclass'
+        orig_meta_prefix = meta_txt.get_prefix()
+
+        if arglist.children:
+            arglist.append_child(Leaf(token.COMMA, ','))
+            meta_txt.set_prefix(' ')
+        else:
+            meta_txt.set_prefix('')
+
+        # compact the expression "metaclass = Meta" -> "metaclass=Meta"
+        expr_stmt = last_metaclass.children[0]
+        assert expr_stmt.type == syms.expr_stmt
+        expr_stmt.children[1].set_prefix('')
+        expr_stmt.children[2].set_prefix('')
+
+        arglist.append_child(last_metaclass)
+
+        fixup_indent(suite)
+
+        # check for empty suite
+        if not suite.children:
+            # one-liner that was just __metaclass_
+            suite.remove()
+            pass_leaf = Leaf(text_type, 'pass')
+            pass_leaf.set_prefix(orig_meta_prefix)
+            node.append_child(pass_leaf)
+            node.append_child(Leaf(token.NEWLINE, os.linesep))
+
+        elif len(suite.children) > 1 and \
+                 (suite.children[-2].type == token.INDENT and
+                  suite.children[-1].type == token.DEDENT):
+            # there was only one line in the class body and it was __metaclass__
+            pass_leaf = Leaf(text_type, 'pass')
+            suite.insert_child(-1, pass_leaf)
+            suite.insert_child(-1, Leaf(token.NEWLINE, os.linesep))
index 6d01dfd931f5c8a78f216d39627352114e28e74a..134a972b07d252a1264c3969360c5f94905f1c21 100644 (file)
@@ -29,7 +29,7 @@ parend_expr = patcomp.compile_pattern(
 class FixPrint(fixer_base.ConditionalFix):
 
     PATTERN = """
-              simple_stmt< bare='print' any > | print_stmt
+              simple_stmt< any* bare='print' any* > | print_stmt
               """
 
     skip_on = '__future__.print_function'
index b2ff643ef9fc032a377fb19a2284a7562af655ca..dc794e2974c38d3a5ab048c92185465ee2a8f1af 100644 (file)
@@ -1,4 +1,4 @@
-# Python 2's Lib/test/test_grammar.py (r54061)
+# Python 2's Lib/test/test_grammar.py (r66189)
 
 # Python test set -- part 1, grammar.
 # This just tests whether the parser accepts them all.
@@ -30,13 +30,15 @@ class TokenTests(unittest.TestCase):
 
     def testPlainIntegers(self):
         self.assertEquals(0xff, 255)
-        self.assertEquals(0o377, 255)
-        self.assertEquals(2147483647, 0o17777777777)
-        from sys import maxsize
+        self.assertEquals(0377, 255)
+        self.assertEquals(2147483647, 017777777777)
+        # "0x" is not a valid literal
+        self.assertRaises(SyntaxError, eval, "0x")
+        from sys import maxint
         if maxint == 2147483647:
-            self.assertEquals(-2147483647-1, -0o20000000000)
+            self.assertEquals(-2147483647-1, -020000000000)
             # XXX -2147483648
-            self.assert_(0o37777777777 > 0)
+            self.assert_(037777777777 > 0)
             self.assert_(0xffffffff > 0)
             for s in '2147483648', '040000000000', '0x100000000':
                 try:
@@ -44,8 +46,8 @@ class TokenTests(unittest.TestCase):
                 except OverflowError:
                     self.fail("OverflowError on huge integer literal %r" % s)
         elif maxint == 9223372036854775807:
-            self.assertEquals(-9223372036854775807-1, -0o1000000000000000000000)
-            self.assert_(0o1777777777777777777777 > 0)
+            self.assertEquals(-9223372036854775807-1, -01000000000000000000000)
+            self.assert_(01777777777777777777777 > 0)
             self.assert_(0xffffffffffffffff > 0)
             for s in '9223372036854775808', '02000000000000000000000', \
                      '0x10000000000000000':
@@ -57,14 +59,14 @@ class TokenTests(unittest.TestCase):
             self.fail('Weird maxint value %r' % maxint)
 
     def testLongIntegers(self):
-        x = 0
-        x = 0
-        x = 0xffffffffffffffff
-        x = 0xffffffffffffffff
-        x = 0o77777777777777777
-        x = 0o77777777777777777
-        x = 123456789012345678901234567890
-        x = 123456789012345678901234567890
+        x = 0L
+        x = 0l
+        x = 0xffffffffffffffffL
+        x = 0xffffffffffffffffl
+        x = 077777777777777777L
+        x = 077777777777777777l
+        x = 123456789012345678901234567890L
+        x = 123456789012345678901234567890l
 
     def testFloats(self):
         x = 3.14
@@ -152,27 +154,27 @@ class GrammarTests(unittest.TestCase):
         f1(*(), **{})
         def f2(one_argument): pass
         def f3(two, arguments): pass
-        def f4(two, xxx_todo_changeme): (compound, (argument, list)) = xxx_todo_changeme; pass
-        def f5(xxx_todo_changeme1, two): (compound, first) = xxx_todo_changeme1; pass
-        self.assertEquals(f2.__code__.co_varnames, ('one_argument',))
-        self.assertEquals(f3.__code__.co_varnames, ('two', 'arguments'))
+        def f4(two, (compound, (argument, list))): pass
+        def f5((compound, first), two): pass
+        self.assertEquals(f2.func_code.co_varnames, ('one_argument',))
+        self.assertEquals(f3.func_code.co_varnames, ('two', 'arguments'))
         if sys.platform.startswith('java'):
-            self.assertEquals(f4.__code__.co_varnames,
+            self.assertEquals(f4.func_code.co_varnames,
                    ('two', '(compound, (argument, list))', 'compound', 'argument',
                                 'list',))
-            self.assertEquals(f5.__code__.co_varnames,
+            self.assertEquals(f5.func_code.co_varnames,
                    ('(compound, first)', 'two', 'compound', 'first'))
         else:
-            self.assertEquals(f4.__code__.co_varnames,
+            self.assertEquals(f4.func_code.co_varnames,
                   ('two', '.1', 'compound', 'argument',  'list'))
-            self.assertEquals(f5.__code__.co_varnames,
+            self.assertEquals(f5.func_code.co_varnames,
                   ('.0', 'two', 'compound', 'first'))
         def a1(one_arg,): pass
         def a2(two, args,): pass
         def v0(*rest): pass
         def v1(a, *rest): pass
         def v2(a, b, *rest): pass
-        def v3(a, xxx_todo_changeme2, *rest): (b, c) = xxx_todo_changeme2; return a, b, c, rest
+        def v3(a, (b, c), *rest): return a, b, c, rest
 
         f1()
         f2(1)
@@ -201,9 +203,9 @@ class GrammarTests(unittest.TestCase):
         # ceval unpacks the formal arguments into the first argcount names;
         # thus, the names nested inside tuples must appear after these names.
         if sys.platform.startswith('java'):
-            self.assertEquals(v3.__code__.co_varnames, ('a', '(b, c)', 'rest', 'b', 'c'))
+            self.assertEquals(v3.func_code.co_varnames, ('a', '(b, c)', 'rest', 'b', 'c'))
         else:
-            self.assertEquals(v3.__code__.co_varnames, ('a', '.1', 'rest', 'b', 'c'))
+            self.assertEquals(v3.func_code.co_varnames, ('a', '.1', 'rest', 'b', 'c'))
         self.assertEquals(v3(1, (2, 3), 4), (1, 2, 3, (4,)))
         def d01(a=1): pass
         d01()
@@ -277,17 +279,29 @@ class GrammarTests(unittest.TestCase):
         d22v(*(1, 2, 3, 4))
         d22v(1, 2, *(3, 4, 5))
         d22v(1, *(2, 3), **{'d': 4})
-        def d31v(xxx_todo_changeme3): (x) = xxx_todo_changeme3; pass
+        def d31v((x)): pass
         d31v(1)
-        def d32v(xxx_todo_changeme4): (x,) = xxx_todo_changeme4; pass
+        def d32v((x,)): pass
         d32v((1,))
 
+        # keyword arguments after *arglist
+        def f(*args, **kwargs):
+            return args, kwargs
+        self.assertEquals(f(1, x=2, *[3, 4], y=5), ((1, 3, 4),
+                                                    {'x':2, 'y':5}))
+        self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)")
+        self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)")
+
+        # Check ast errors in *args and *kwargs
+        check_syntax_error(self, "f(*g(1=2))")
+        check_syntax_error(self, "f(**g(1=2))")
+
     def testLambdef(self):
         ### lambdef: 'lambda' [varargslist] ':' test
         l1 = lambda : 0
         self.assertEquals(l1(), 0)
         l2 = lambda : a[d] # XXX just testing the expression
-        l3 = lambda : [2 < x for x in [-1, 3, 0]]
+        l3 = lambda : [2 < x for x in [-1, 3, 0L]]
         self.assertEquals(l3(), [0, 1, 0])
         l4 = lambda x = lambda y = lambda z=1 : z : y() : x()
         self.assertEquals(l4(), 1)
@@ -295,6 +309,7 @@ class GrammarTests(unittest.TestCase):
         self.assertEquals(l5(1, 2), 5)
         self.assertEquals(l5(1, 2, 3), 6)
         check_syntax_error(self, "lambda x: x = 2")
+        check_syntax_error(self, "lambda (None,): None")
 
     ### stmt: simple_stmt | compound_stmt
     # Tested below
@@ -325,36 +340,36 @@ class GrammarTests(unittest.TestCase):
 
     def testPrintStmt(self):
         # 'print' (test ',')* [test]
-        import io
+        import StringIO
 
         # Can't test printing to real stdout without comparing output
         # which is not available in unittest.
         save_stdout = sys.stdout
-        sys.stdout = io.StringIO()
+        sys.stdout = StringIO.StringIO()
 
-        print(1, 2, 3)
-        print(1, 2, 3, end=' ')
-        print()
-        print(0 or 1, 0 or 1, end=' ')
-        print(0 or 1)
+        print 1, 2, 3
+        print 1, 2, 3,
+        print
+        print 0 or 1, 0 or 1,
+        print 0 or 1
 
         # 'print' '>>' test ','
-        print(1, 2, 3, file=sys.stdout)
-        print(1, 2, 3, end=' ', file=sys.stdout)
-        print(file=sys.stdout)
-        print(0 or 1, 0 or 1, end=' ', file=sys.stdout)
-        print(0 or 1, file=sys.stdout)
+        print >> sys.stdout, 1, 2, 3
+        print >> sys.stdout, 1, 2, 3,
+        print >> sys.stdout
+        print >> sys.stdout, 0 or 1, 0 or 1,
+        print >> sys.stdout, 0 or 1
 
         # test printing to an instance
         class Gulp:
             def write(self, msg): pass
 
         gulp = Gulp()
-        print(1, 2, 3, file=gulp)
-        print(1, 2, 3, end=' ', file=gulp)
-        print(file=gulp)
-        print(0 or 1, 0 or 1, end=' ', file=gulp)
-        print(0 or 1, file=gulp)
+        print >> gulp, 1, 2, 3
+        print >> gulp, 1, 2, 3,
+        print >> gulp
+        print >> gulp, 0 or 1, 0 or 1,
+        print >> gulp, 0 or 1
 
         # test print >> None
         def driver():
@@ -368,13 +383,13 @@ class GrammarTests(unittest.TestCase):
 
         # we should see this once
         def tellme(file=sys.stdout):
-            print('hello world', file=file)
+            print >> file, 'hello world'
 
         driver()
 
         # we should not see this at all
         def tellme(file=None):
-            print('goodbye universe', file=file)
+            print >> file, 'goodbye universe'
 
         driver()
 
@@ -461,7 +476,7 @@ hello world
                     continue
                 except:
                     raise
-            if count > 2 or big_hippo != 1:
+            if count > 2 or big_hippo <> 1:
                 self.fail("continue then break in try/except in loop broken!")
         test_inner()
 
@@ -478,7 +493,7 @@ hello world
 
     def testRaise(self):
         # 'raise' test [',' test]
-        try: raise RuntimeError('just testing')
+        try: raise RuntimeError, 'just testing'
         except RuntimeError: pass
         try: raise KeyboardInterrupt
         except KeyboardInterrupt: pass
@@ -506,33 +521,33 @@ hello world
         # 'exec' expr ['in' expr [',' expr]]
         z = None
         del z
-        exec('z=1+1\n')
+        exec 'z=1+1\n'
         if z != 2: self.fail('exec \'z=1+1\'\\n')
         del z
-        exec('z=1+1')
+        exec 'z=1+1'
         if z != 2: self.fail('exec \'z=1+1\'')
         z = None
         del z
         import types
         if hasattr(types, "UnicodeType"):
-            exec(r"""if 1:
+            exec r"""if 1:
             exec u'z=1+1\n'
             if z != 2: self.fail('exec u\'z=1+1\'\\n')
             del z
             exec u'z=1+1'
-            if z != 2: self.fail('exec u\'z=1+1\'')""")
+            if z != 2: self.fail('exec u\'z=1+1\'')"""
         g = {}
-        exec('z = 1', g)
-        if '__builtins__' in g: del g['__builtins__']
+        exec 'z = 1' in g
+        if g.has_key('__builtins__'): del g['__builtins__']
         if g != {'z': 1}: self.fail('exec \'z = 1\' in g')
         g = {}
         l = {}
 
         import warnings
         warnings.filterwarnings("ignore", "global statement", module="<string>")
-        exec('global a; a = 1; b = 2', g, l)
-        if '__builtins__' in g: del g['__builtins__']
-        if '__builtins__' in l: del l['__builtins__']
+        exec 'global a; a = 1; b = 2' in g, l
+        if g.has_key('__builtins__'): del g['__builtins__']
+        if l.has_key('__builtins__'): del l['__builtins__']
         if (g, l) != ({'a':1}, {'b':2}):
             self.fail('exec ... in g (%s), l (%s)' %(g,l))
 
@@ -544,7 +559,7 @@ hello world
         assert 1, lambda x:x+1
         try:
             assert 0, "msg"
-        except AssertionError as e:
+        except AssertionError, e:
             self.assertEquals(e.args[0], "msg")
         else:
             if __debug__:
@@ -572,6 +587,15 @@ hello world
         while 0: pass
         else: pass
 
+        # Issue1920: "while 0" is optimized away,
+        # ensure that the "else" clause is still present.
+        x = 0
+        while 0:
+            x = 1
+        else:
+            x = 2
+        self.assertEquals(x, 2)
+
     def testFor(self):
         # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
         for i in 1, 2, 3: pass
@@ -602,7 +626,7 @@ hello world
     def testTry(self):
         ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
         ###         | 'try' ':' suite 'finally' ':' suite
-        ### except_clause: 'except' [expr [',' expr]]
+        ### except_clause: 'except' [expr [('as' | ',') expr]]
         try:
             1/0
         except ZeroDivisionError:
@@ -611,7 +635,7 @@ hello world
             pass
         try: 1/0
         except EOFError: pass
-        except TypeError, msg: pass
+        except TypeError as msg: pass
         except RuntimeError, msg: pass
         except: pass
         else: pass
@@ -655,7 +679,7 @@ hello world
         x = (1 == 1)
         if 1 == 1: pass
         if 1 != 1: pass
-        if 1 != 1: pass
+        if 1 <> 1: pass
         if 1 < 1: pass
         if 1 > 1: pass
         if 1 <= 1: pass
@@ -664,7 +688,7 @@ hello world
         if 1 is not 1: pass
         if 1 in (): pass
         if 1 not in (): pass
-        if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 != 1 in 1 not in 1 is 1 is not 1: pass
+        if 1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1: pass
 
     def testBinaryMaskOps(self):
         x = 1 & 1
@@ -747,9 +771,9 @@ hello world
         x = {'one': 1, 'two': 2,}
         x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6}
 
-        x = repr(x)
-        x = repr(1 or 2 or 3)
-        self.assertEqual(repr((1,2)), '(1, 2)')
+        x = `x`
+        x = `1 or 2 or 3`
+        self.assertEqual(`1,2`, '(1, 2)')
 
         x = x
         x = 'x'
@@ -770,6 +794,16 @@ hello world
             def meth1(self): pass
             def meth2(self, arg): pass
             def meth3(self, a1, a2): pass
+        # decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
+        # decorators: decorator+
+        # decorated: decorators (classdef | funcdef)
+        def class_decorator(x):
+            x.decorated = True
+            return x
+        @class_decorator
+        class G:
+            pass
+        self.assertEqual(G.decorated, True)
 
     def testListcomps(self):
         # list comprehension tests
@@ -837,9 +871,9 @@ hello world
     def testGenexps(self):
         # generator expression tests
         g = ([x for x in range(10)] for x in range(1))
-        self.assertEqual(next(g), [x for x in range(10)])
+        self.assertEqual(g.next(), [x for x in range(10)])
         try:
-            next(g)
+            g.next()
             self.fail('should produce StopIteration exception')
         except StopIteration:
             pass
@@ -847,7 +881,7 @@ hello world
         a = 1
         try:
             g = (a for d in a)
-            next(g)
+            g.next()
             self.fail('should produce TypeError')
         except TypeError:
             pass
@@ -892,7 +926,7 @@ hello world
         # Test ifelse expressions in various cases
         def _checkeval(msg, ret):
             "helper to check that evaluation of expressions is done correctly"
-            print(x)
+            print x
             return ret
 
         self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True])
index 2fb321717c5024f2409d531e1e059b99fbf72712..9a8846307ecb4fd6839f5eda6f21236024f14e08 100644 (file)
@@ -8,7 +8,7 @@
 # regression test, the filterwarnings() call has been added to
 # regrtest.py.
 
-from test.test_support import run_unittest, check_syntax_error
+from test.support import run_unittest, check_syntax_error
 import unittest
 import sys
 # testing import *
@@ -32,8 +32,10 @@ class TokenTests(unittest.TestCase):
         self.assertEquals(0o377, 255)
         self.assertEquals(2147483647, 0o17777777777)
         self.assertEquals(0b1001, 9)
+        # "0x" is not a valid literal
+        self.assertRaises(SyntaxError, eval, "0x")
         from sys import maxsize
-        if maxint == 2147483647:
+        if maxsize == 2147483647:
             self.assertEquals(-2147483647-1, -0o20000000000)
             # XXX -2147483648
             self.assert_(0o37777777777 > 0)
@@ -45,7 +47,7 @@ class TokenTests(unittest.TestCase):
                     x = eval(s)
                 except OverflowError:
                     self.fail("OverflowError on huge integer literal %r" % s)
-        elif maxint == 9223372036854775807:
+        elif maxsize == 9223372036854775807:
             self.assertEquals(-9223372036854775807-1, -0o1000000000000000000000)
             self.assert_(0o1777777777777777777777 > 0)
             self.assert_(0xffffffffffffffff > 0)
@@ -58,7 +60,7 @@ class TokenTests(unittest.TestCase):
                 except OverflowError:
                     self.fail("OverflowError on huge integer literal %r" % s)
         else:
-            self.fail('Weird maxint value %r' % maxint)
+            self.fail('Weird maxsize value %r' % maxsize)
 
     def testLongIntegers(self):
         x = 0
@@ -263,6 +265,14 @@ class GrammarTests(unittest.TestCase):
         d22v(*(1, 2, 3, 4))
         d22v(1, 2, *(3, 4, 5))
         d22v(1, *(2, 3), **{'d': 4})
+
+        # keyword argument type tests
+        try:
+            str('x', **{b'foo':1 })
+        except TypeError:
+            pass
+        else:
+            self.fail('Bytes should not work as keyword argument names')
         # keyword only argument tests
         def pos0key1(*, key): return key
         pos0key1(key=100)
@@ -274,6 +284,14 @@ class GrammarTests(unittest.TestCase):
         pos2key2dict(1,2,k2=100,tokwarg1=100,tokwarg2=200)
         pos2key2dict(1,2,tokwarg1=100,tokwarg2=200, k2=100)
 
+        # keyword arguments after *arglist
+        def f(*args, **kwargs):
+            return args, kwargs
+        self.assertEquals(f(1, x=2, *[3, 4], y=5), ((1, 3, 4),
+                                                    {'x':2, 'y':5}))
+        self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)")
+        self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)")
+
         # argument annotation tests
         def f(x) -> list: pass
         self.assertEquals(f.__annotations__, {'return': list})
@@ -308,6 +326,10 @@ class GrammarTests(unittest.TestCase):
         def f(*, k=1): return closure
         def f() -> int: return closure
 
+        # Check ast errors in *args and *kwargs
+        check_syntax_error(self, "f(*g(1=2))")
+        check_syntax_error(self, "f(**g(1=2))")
+
     def testLambdef(self):
         ### lambdef: 'lambda' [varargslist] ':' test
         l1 = lambda : 0
@@ -321,6 +343,7 @@ class GrammarTests(unittest.TestCase):
         self.assertEquals(l5(1, 2), 5)
         self.assertEquals(l5(1, 2, 3), 6)
         check_syntax_error(self, "lambda x: x = 2")
+        check_syntax_error(self, "lambda (None,): None")
         l6 = lambda x, y, *, k=20: x+y+k
         self.assertEquals(l6(1,2), 1+2+20)
         self.assertEquals(l6(1,2,k=10), 1+2+10)
@@ -498,6 +521,15 @@ class GrammarTests(unittest.TestCase):
         while 0: pass
         else: pass
 
+        # Issue1920: "while 0" is optimized away,
+        # ensure that the "else" clause is still present.
+        x = 0
+        while 0:
+            x = 1
+        else:
+            x = 2
+        self.assertEquals(x, 2)
+
     def testFor(self):
         # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
         for i in 1, 2, 3: pass
index eb5a93991c8908111abe3a5e74fe2682d665737d..91d51cfb1021cbddef4f3f82a0f3af4b849d89b2 100755 (executable)
@@ -385,6 +385,16 @@ class Test_print(FixerTestCase):
         a = """print()"""
         self.check(b, a)
 
+    def test_4(self):
+        # from bug 3000
+        b = """print whatever; print"""
+        a = """print(whatever); print()"""
+        self.check(b, a)
+
+    def test_5(self):
+        b = """print; print whatever;"""
+        a = """print(); print(whatever);"""
+
     def test_tuple(self):
         b = """print (a, b, c)"""
         a = """print((a, b, c))"""
@@ -2379,6 +2389,15 @@ class Test_numliterals(FixerTestCase):
         a = """b = 0x12"""
         self.check(b, a)
 
+    def test_comments_and_spacing(self):
+        b = """b =   0x12L"""
+        a = """b =   0x12"""
+        self.check(b, a)
+
+        b = """b = 0755 # spam"""
+        a = """b = 0o755 # spam"""
+        self.check(b, a)
+
     def test_unchanged_int(self):
         s = """5"""
         self.unchanged(s)
@@ -3430,6 +3449,133 @@ class Test_paren(FixerTestCase):
         s = """[i for i in m]"""
         self.unchanged(s)
 
+class Test_metaclass(FixerTestCase):
+
+    fixer = 'metaclass'
+
+    def test_unchanged(self):
+        self.unchanged("class X(): pass")
+        self.unchanged("class X(object): pass")
+        self.unchanged("class X(object1, object2): pass")
+        self.unchanged("class X(object1, object2, object3): pass")
+        self.unchanged("class X(metaclass=Meta): pass")
+        self.unchanged("class X(b, arg=23, metclass=Meta): pass")
+        self.unchanged("class X(b, arg=23, metaclass=Meta, other=42): pass")
+
+        s = """
+        class X:
+            def __metaclass__(self): pass
+        """
+        self.unchanged(s)
+
+    def test_comments(self):
+        b = """
+        class X:
+            # hi
+            __metaclass__ = AppleMeta
+        """
+        a = """
+        class X(metaclass=AppleMeta):
+            # hi
+            pass
+        """
+        self.check(b, a)
+
+        b = """
+        class X:
+            __metaclass__ = Meta
+            # Bedtime!
+        """
+        a = """
+        class X(metaclass=Meta):
+            pass
+            # Bedtime!
+        """
+        self.check(b, a)
+
+    def test_meta(self):
+        # no-parent class, odd body
+        b = """
+        class X():
+            __metaclass__ = Q
+            pass
+        """
+        a = """
+        class X(metaclass=Q):
+            pass
+        """
+        self.check(b, a)
+
+        # one parent class, no body
+        b = """class X(object): __metaclass__ = Q"""
+        a = """class X(object, metaclass=Q): pass"""
+        self.check(b, a)
+
+
+        # one parent, simple body
+        b = """
+        class X(object):
+            __metaclass__ = Meta
+            bar = 7
+        """
+        a = """
+        class X(object, metaclass=Meta):
+            bar = 7
+        """
+        self.check(b, a)
+
+        b = """
+        class X:
+            __metaclass__ = Meta; x = 4; g = 23
+        """
+        a = """
+        class X(metaclass=Meta):
+            x = 4; g = 23
+        """
+        self.check(b, a)
+
+        # one parent, simple body, __metaclass__ last
+        b = """
+        class X(object):
+            bar = 7
+            __metaclass__ = Meta
+        """
+        a = """
+        class X(object, metaclass=Meta):
+            bar = 7
+        """
+        self.check(b, a)
+
+        # redefining __metaclass__
+        b = """
+        class X():
+            __metaclass__ = A
+            __metaclass__ = B
+            bar = 7
+        """
+        a = """
+        class X(metaclass=B):
+            bar = 7
+        """
+        self.check(b, a)
+
+        # multiple inheritance, simple body
+        b = """
+        class X(clsA, clsB):
+            __metaclass__ = Meta
+            bar = 7
+        """
+        a = """
+        class X(clsA, clsB, metaclass=Meta):
+            bar = 7
+        """
+        self.check(b, a)
+
+        # keywords in the class statement
+        b = """class m(a, arg=23): __metaclass__ = Meta"""
+        a = """class m(a, arg=23, metaclass=Meta): pass"""
+        self.check(b, a)
+
 
 if __name__ == "__main__":
     import __main__