[Python-checkins] r54442 - in sandbox/trunk/2to3: README fixes/fix_next.py tests/test_fixers.py
collin.winter
python-checkins at python.org
Mon Mar 19 21:24:37 CET 2007
Author: collin.winter
Date: Mon Mar 19 21:24:35 2007
New Revision: 54442
Added:
sandbox/trunk/2to3/fixes/fix_next.py (contents, props changed)
Modified:
sandbox/trunk/2to3/README
sandbox/trunk/2to3/tests/test_fixers.py
Log:
Add a beta version of the next() fixer for PEP 3114.
Modified: sandbox/trunk/2to3/README
==============================================================================
--- sandbox/trunk/2to3/README (original)
+++ sandbox/trunk/2to3/README Mon Mar 19 21:24:35 2007
@@ -50,6 +50,8 @@
* **fix_ne** - convert the "<>" operator to "!=".
+* **fix_next** - fixer for it.next() -> next(it), per PEP 3114.
+
* **fix_print** - convert "print" statements to print() function calls.
* **fix_raise** - convert "raise" statements to Python 3 syntax.
Added: sandbox/trunk/2to3/fixes/fix_next.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/2to3/fixes/fix_next.py Mon Mar 19 21:24:35 2007
@@ -0,0 +1,183 @@
+"""Fixer for it.next() -> next(it), per PEP 3114."""
+# Author: Collin Winter
+
+# Things that currently aren't covered:
+# - listcomp "next" names aren't warned
+# - "with" statement targets aren't checked
+
+# Local imports
+import pytree
+from pgen2 import token
+from fixes import basefix
+from fixes.macros import Name, Call
+
+bind_warning = "Calls to builtin next() possibly shadowed by global binding"
+
+class DelayedStrNode(object):
+ def __init__(self, type, base):
+ self.parent = None
+ self.shadowed_next = False
+ self.base = base
+ self.type = type
+ self.value = ""
+
+ def __str__(self):
+ b = "".join([str(n) for n in self.base])
+ if self.shadowed_next:
+ return "%s.__next__()" % b
+ else:
+ return "next(%s)" % b
+
+class FixNext(basefix.BaseFix):
+ PATTERN = """
+ power< base=any+ trailer< '.' 'next' > trailer< '(' ')' > >
+ |
+ power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > >
+ |
+ classdef< 'class' any+ ':'
+ suite< any*
+ funcdef< 'def'
+ name='next'
+ parameters< '(' NAME ')' > any+ >
+ any* > >
+ |
+ global=global_stmt< 'global' any* 'next' any* >
+ |
+ mod=file_input< any+ >
+ """
+
+ def start_tree(self, tree, filename):
+ super(FixNext, self).start_tree(tree, filename)
+ self.shadowed_next = False
+ self.delayed = []
+
+ def transform(self, node):
+ syms = self.syms
+ results = self.match(node)
+ assert results
+
+ base = results.get("base")
+ attr = results.get("attr")
+ name = results.get("name")
+ mod = results.get("mod")
+
+ if base:
+ n = DelayedStrNode(syms.power, base)
+ node.replace(n)
+ self.delayed.append(n)
+ elif name:
+ n = Name("__next__")
+ n.set_prefix(name.get_prefix())
+ name.replace(n)
+ elif attr:
+ # We don't do this transformation if we're assignment to "x.next".
+ # Unfortunately, it doesn't seem possible to do this in PATTERN,
+ # so it's being done here.
+ if is_assign_target(syms, node):
+ head = results["head"]
+ if "".join([str(n) for n in head]).strip() == '__builtin__':
+ self.warning(node, bind_warning)
+ return
+ attr.replace(Name("__next__"))
+ elif "global" in results:
+ self.warning(node, bind_warning)
+ self.shadowed_next = True
+ elif mod:
+ n = find_binding(syms, 'next', mod)
+ if n:
+ self.warning(n, bind_warning)
+ self.shadowed_next = True
+
+ def finish_tree(self, tree, filename):
+ super(FixNext, self).finish_tree(tree, filename)
+ if self.shadowed_next:
+ for node in self.delayed:
+ node.shadowed_next = True
+
+
+### The following functions are to find module-level bindings
+
+def find_binding(syms, name, file_input):
+ for child in file_input.children:
+ if child.type == syms.for_stmt:
+ if find(name, child.children[1]):
+ return child
+ elif child.type == syms.funcdef and child.children[1].value == name:
+ return child
+ elif is_import_binding(syms, child, name):
+ return child
+ elif child.type == syms.simple_stmt:
+ if child.children[0].type == syms.expr_stmt:
+ n = find(name, child.children[0].children[0])
+ if n:
+ return n
+
+def find(name, node):
+ nodes = [node]
+ while nodes:
+ node = nodes.pop()
+ if isinstance(node, pytree.Node):
+ nodes.extend(node.children)
+ elif node.type == token.NAME and node.value == name:
+ return node
+ return None
+
+def is_import_binding(syms, node, name):
+ if node.type == syms.simple_stmt:
+ i = node.children[0]
+ if i.type == syms.import_name:
+ imp = i.children[1]
+ if imp.type == syms.dotted_as_names:
+ for child in imp.children:
+ if child.type == syms.dotted_as_name:
+ if child.children[2].value == name:
+ return i
+ elif imp.type == syms.dotted_as_name:
+ last = imp.children[-1]
+ if last.type == token.NAME and last.value == name:
+ return i
+ elif i.type == syms.import_from:
+ n = i.children[3]
+ if n.type == syms.import_as_names:
+ if find(name, n):
+ return i
+ elif n.type == token.NAME and n.value == name:
+ return i
+ return None
+
+
+### The following functions help test if node is part of an assignment
+### target.
+
+try:
+ any
+except NameError:
+ def any(l):
+ for o in l:
+ if o:
+ return True
+ return False
+
+def is_assign_target(syms, node):
+ assign = find_assign(syms, node)
+ if assign is None:
+ return False
+
+ for child in assign.children:
+ if child.type == token.EQUAL:
+ return False
+ elif is_subtree(child, node):
+ return True
+ return False
+
+def find_assign(syms, node):
+ if node.type == syms.expr_stmt:
+ return node
+ if node.type == syms.simple_stmt or node.parent is None:
+ return None
+ return find_assign(syms, node.parent)
+
+def is_subtree(root, node):
+ if root == node:
+ return True
+ return any([is_subtree(c, node) for c in root.children])
Modified: sandbox/trunk/2to3/tests/test_fixers.py
==============================================================================
--- sandbox/trunk/2to3/tests/test_fixers.py (original)
+++ sandbox/trunk/2to3/tests/test_fixers.py Mon Mar 19 21:24:35 2007
@@ -1228,6 +1228,365 @@
(d, e, f) = xxx_todo_changeme1
x = 5"""
self.check(b, a)
+
+class Test_next(FixerTestCase):
+ fixer = "next"
+
+ def test_1(self):
+ b = """it.next()"""
+ a = """next(it)"""
+ self.check(b, a)
+
+ def test_2(self):
+ b = """a.b.c.d.next()"""
+ a = """next(a.b.c.d)"""
+ self.check(b, a)
+
+ def test_3(self):
+ b = """(a + b).next()"""
+ a = """next((a + b))"""
+ self.check(b, a)
+
+ def test_4(self):
+ b = """a().next()"""
+ a = """next(a())"""
+ self.check(b, a)
+
+ def test_5(self):
+ b = """a().next() + b"""
+ a = """next(a()) + b"""
+ self.check(b, a)
+
+ def test_method_1(self):
+ b = """
+ class A:
+ def next(self):
+ pass
+ """
+ a = """
+ class A:
+ def __next__(self):
+ pass
+ """
+ self.check(b, a)
+
+ def test_method_2(self):
+ b = """
+ class A(object):
+ def next(self):
+ pass
+ """
+ a = """
+ class A(object):
+ def __next__(self):
+ pass
+ """
+ self.check(b, a)
+
+ def test_method_3(self):
+ b = """
+ class A:
+ def next(x):
+ pass
+ """
+ a = """
+ class A:
+ def __next__(x):
+ pass
+ """
+ self.check(b, a)
+
+ def test_method_4(self):
+ b = """
+ class A:
+ def __init__(self, foo):
+ self.foo = foo
+
+ def next(self):
+ pass
+
+ def __iter__(self):
+ return self
+ """
+ a = """
+ class A:
+ def __init__(self, foo):
+ self.foo = foo
+
+ def __next__(self):
+ pass
+
+ def __iter__(self):
+ return self
+ """
+ self.check(b, a)
+
+ def test_method_unchanged(self):
+ s = """
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.check(s, s)
+
+ def test_shadowing_assign_simple(self):
+ s = """
+ next = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_assign_tuple_1(self):
+ s = """
+ (next, a) = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_assign_tuple_2(self):
+ s = """
+ (a, (b, (next, c)), a) = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_assign_list_1(self):
+ s = """
+ [next, a] = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_assign_list_2(self):
+ s = """
+ [a, [b, [next, c]], a] = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_builtin_assign(self):
+ s = """
+ def foo():
+ __builtin__.next = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_builtin_assign_in_tuple(self):
+ s = """
+ def foo():
+ (a, __builtin__.next) = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_assign_to_next(self):
+ s = """
+ def foo():
+ A.next = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.check(s, s)
+
+ def test_assign_to_next_in_tuple(self):
+ s = """
+ def foo():
+ (a, A.next) = foo
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.check(s, s)
+
+ def test_shadowing_import_1(self):
+ s = """
+ import foo.bar as next
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_import_2(self):
+ s = """
+ import bar, bar.foo as next
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_import_3(self):
+ s = """
+ import bar, bar.foo as next, baz
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_import_from_1(self):
+ s = """
+ from x import next
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_import_from_2(self):
+ s = """
+ from x.a import next
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_import_from_3(self):
+ s = """
+ from x import a, next, b
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_import_from_4(self):
+ s = """
+ from x.a import a, next, b
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_funcdef_1(self):
+ s = """
+ def next(a):
+ pass
+
+ class A:
+ def next(self, a, b):
+ pass
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_funcdef_2(self):
+ b = """
+ def next(a):
+ pass
+
+ class A:
+ def next(self):
+ pass
+
+ it.next()
+ """
+ a = """
+ def next(a):
+ pass
+
+ class A:
+ def __next__(self):
+ pass
+
+ it.__next__()
+ """
+ self.warns(b, a, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_global_1(self):
+ s = """
+ def f():
+ global next
+ next = 5
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_global_2(self):
+ s = """
+ def f():
+ global a, next, b
+ next = 5
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_for_simple(self):
+ s = """
+ for next in it():
+ pass
+
+ b = 5
+ c = 6
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_for_tuple_1(self):
+ s = """
+ for next, b in it():
+ pass
+
+ b = 5
+ c = 6
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_shadowing_for_tuple_2(self):
+ s = """
+ for a, (next, c), b in it():
+ pass
+
+ b = 5
+ c = 6
+ """
+ self.warns(s, s, "Calls to builtin next() possibly shadowed")
+
+ def test_noncall_access_1(self):
+ b = """gnext = g.next"""
+ a = """gnext = g.__next__"""
+ self.check(b, a)
+
+ def test_noncall_access_2(self):
+ b = """f(g.next + 5)"""
+ a = """f(g.__next__ + 5)"""
+ self.check(b, a)
+
+ def test_noncall_access_3(self):
+ b = """f(g().next + 5)"""
+ a = """f(g().__next__ + 5)"""
+ self.check(b, a)
if __name__ == "__main__":
More information about the Python-checkins
mailing list