def test_basic_patterns(self): # Build a tree l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "bar") l3 = pytree.Leaf(100, "foo") n1 = pytree.Node(1000, [l1, l2]) n2 = pytree.Node(1000, [l3]) root = pytree.Node(1000, [n1, n2]) # Build a pattern matching a leaf pl = pytree.LeafPattern(100, "foo", name="pl") r = {} self.assertFalse(pl.match(root, results=r)) self.assertEqual(r, {}) self.assertFalse(pl.match(n1, results=r)) self.assertEqual(r, {}) self.assertFalse(pl.match(n2, results=r)) self.assertEqual(r, {}) self.assertTrue(pl.match(l1, results=r)) self.assertEqual(r, {"pl": l1}) r = {} self.assertFalse(pl.match(l2, results=r)) self.assertEqual(r, {}) # Build a pattern matching a node pn = pytree.NodePattern(1000, [pl], name="pn") self.assertFalse(pn.match(root, results=r)) self.assertEqual(r, {}) self.assertFalse(pn.match(n1, results=r)) self.assertEqual(r, {}) self.assertTrue(pn.match(n2, results=r)) self.assertEqual(r, {"pn": n2, "pl": l3}) r = {} self.assertFalse(pn.match(l1, results=r)) self.assertEqual(r, {}) self.assertFalse(pn.match(l2, results=r)) self.assertEqual(r, {})
def test_changed(self): l1 = pytree.Leaf(100, "f") self.assertFalse(l1.was_changed) l1.changed() self.assertTrue(l1.was_changed) l1 = pytree.Leaf(100, "f") n1 = pytree.Node(1000, [l1]) self.assertFalse(n1.was_changed) n1.changed() self.assertTrue(n1.was_changed) l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "+") l3 = pytree.Leaf(100, "bar") n1 = pytree.Node(1000, [l1, l2, l3]) n2 = pytree.Node(1000, [n1]) self.assertFalse(l1.was_changed) self.assertFalse(n1.was_changed) self.assertFalse(n2.was_changed) n1.changed() self.assertTrue(n1.was_changed) self.assertTrue(n2.was_changed) self.assertFalse(l1.was_changed)
def test_wildcard(self): # Build a tree for testing l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "bar") l3 = pytree.Leaf(100, "foo") n1 = pytree.Node(1000, [l1, l2]) n2 = pytree.Node(1000, [l3]) root = pytree.Node(1000, [n1, n2]) # Build a pattern pl = pytree.LeafPattern(100, "foo", name="pl") pn = pytree.NodePattern(1000, [pl], name="pn") pw = pytree.WildcardPattern([[pn], [pl, pl]], name="pw") r = {} self.assertFalse(pw.match_seq([root], r)) self.assertEqual(r, {}) self.assertFalse(pw.match_seq([n1], r)) self.assertEqual(r, {}) self.assertTrue(pw.match_seq([n2], r)) # These are easier to debug self.assertEqual(sorted(r.keys()), ["pl", "pn", "pw"]) self.assertEqual(r["pl"], l1) self.assertEqual(r["pn"], n2) self.assertEqual(r["pw"], [n2]) # But this is equivalent self.assertEqual(r, {"pl": l1, "pn": n2, "pw": [n2]}) r = {} self.assertTrue(pw.match_seq([l1, l3], r)) self.assertEqual(r, {"pl": l3, "pw": [l1, l3]}) self.assertIs(r["pl"], l3) r = {}
def transform(self, node, results): head = results["head"] method = results["method"][0] # Extract node for method name tail = results["tail"] syms = self.syms method_name = method.value isiter = method_name.startswith("iter") isview = method_name.startswith("view") if isiter or isview: method_name = method_name[4:] assert method_name in ("keys", "items", "values"), repr(method) head = [n.clone() for n in head] tail = [n.clone() for n in tail] special = not tail and self.in_special_context(node, isiter) args = head + [ pytree.Node(syms.trailer, [Dot(), Name(method_name, prefix=method.prefix)]), results["parens"].clone(), ] new = pytree.Node(syms.power, args) if not (special or isview): new.prefix = "" new = Call(Name("iter" if isiter else "list"), [new]) if tail: new = pytree.Node(syms.power, [new] + tail) new.prefix = node.prefix return new
def test_pre_order(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "bar") l3 = pytree.Leaf(100, "fooey") c1 = pytree.Node(1000, [l1, l2]) n1 = pytree.Node(1000, [c1, l3]) self.assertEqual(list(n1.pre_order()), [n1, c1, l1, l2, l3])
def transform(self, node, results): single = results.get("single") if single: # Make a fake listmaker fake = pytree.Node(syms.listmaker, [single.clone()]) single.replace(fake) items = fake else: items = results["items"] # Build the contents of the literal literal = [pytree.Leaf(token.LBRACE, "{")] literal.extend(n.clone() for n in items.children) literal.append(pytree.Leaf(token.RBRACE, "}")) # Set the prefix of the right brace to that of the ')' or ']' literal[-1].prefix = items.next_sibling.prefix maker = pytree.Node(syms.dictsetmaker, literal) maker.prefix = node.prefix # If the original was a one tuple, we need to remove the extra comma. if len(maker.children) == 4: n = maker.children[2] n.remove() maker.children[-1].prefix = n.prefix # Finally, replace the set call with our shiny new literal. return maker
def test_node_prev_sibling(self): n1 = pytree.Node(1000, []) n2 = pytree.Node(1000, []) p1 = pytree.Node(1000, [n1, n2]) self.assertIs(n2.prev_sibling, n1) self.assertEqual(n1.prev_sibling, None) self.assertEqual(p1.prev_sibling, None)
def test_leaves(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "bar") l3 = pytree.Leaf(100, "fooey") n2 = pytree.Node(1000, [l1, l2]) n3 = pytree.Node(1000, [l3]) n1 = pytree.Node(1000, [n2, n3]) self.assertEqual(list(n1.leaves()), [l1, l2, l3])
def test_node_recursive_equality(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "foo") n1 = pytree.Node(1000, [l1]) n2 = pytree.Node(1000, [l2]) self.assertEqual(n1, n2) l3 = pytree.Leaf(100, "bar") n3 = pytree.Node(1000, [l3]) self.assertNotEqual(n1, n3)
def test_depth(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "bar") n2 = pytree.Node(1000, [l1, l2]) n3 = pytree.Node(1000, []) n1 = pytree.Node(1000, [n2, n3]) self.assertEqual(l1.depth(), 2) self.assertEqual(n3.depth(), 1) self.assertEqual(n1.depth(), 0)
def transform(self, node, results): syms = self.syms exc = results["exc"].clone() if exc.type == token.STRING: msg = "Python 3 does not support string exceptions" self.cannot_convert(node, msg) return # Python 2 supports # raise ((((E1, E2), E3), E4), E5), V # as a synonym for # raise E1, V # Since Python 3 will not support this, we recurse down any tuple # literals, always taking the first element. if is_tuple(exc): while is_tuple(exc): # exc.children[1:-1] is the unparenthesized tuple # exc.children[1].children[0] is the first element of the tuple exc = exc.children[1].children[0].clone() exc.prefix = " " if "val" not in results: # One-argument raise new = pytree.Node(syms.raise_stmt, [Name("raise"), exc]) new.prefix = node.prefix return new val = results["val"].clone() if is_tuple(val): args = [c.clone() for c in val.children[1:-1]] else: val.prefix = "" args = [val] if "tb" in results: tb = results["tb"].clone() tb.prefix = "" e = exc # If there's a traceback and None is passed as the value, then don't # add a call, since the user probably just wants to add a # traceback. See issue #9661. if val.type != token.NAME or val.value != "None": e = Call(exc, args) with_tb = Attr(e, Name("with_traceback")) + [ArgList([tb])] new = pytree.Node(syms.simple_stmt, [Name("raise")] + with_tb) new.prefix = node.prefix return new else: return pytree.Node(syms.raise_stmt, [Name("raise"), Call(exc, args)], prefix=node.prefix)
def transform(self, node, results): assert results syms = self.syms if node.parent.type == syms.not_test and self.pattern.match( node.parent): # Don't transform a node matching the first alternative of the # pattern when its parent matches the second alternative return None negation = results.get("negation") anchor = results["anchor"] prefix = node.prefix before = [n.clone() for n in results["before"]] arg = results["arg"].clone() after = results.get("after") if after: after = [n.clone() for n in after] if arg.type in ( syms.comparison, syms.not_test, syms.and_test, syms.or_test, syms.test, syms.lambdef, syms.argument, ): arg = parenthesize(arg) if len(before) == 1: before = before[0] else: before = pytree.Node(syms.power, before) before.prefix = " " n_op = Name("in", prefix=" ") if negation: n_not = Name("not", prefix=" ") n_op = pytree.Node(syms.comp_op, (n_not, n_op)) new = pytree.Node(syms.comparison, (arg, n_op, before)) if after: new = parenthesize(new) new = pytree.Node(syms.power, (new, ) + tuple(after)) if node.parent.type in ( syms.comparison, syms.expr, syms.xor_expr, syms.and_expr, syms.shift_expr, syms.arith_expr, syms.term, syms.factor, syms.power, ): new = parenthesize(new) new.prefix = prefix return new
def test_get_suffix(self): l1 = pytree.Leaf(100, "foo", prefix="a") l2 = pytree.Leaf(100, "bar", prefix="b") n1 = pytree.Node(1000, [l1, l2]) self.assertEqual(l1.get_suffix(), l2.prefix) self.assertEqual(l2.get_suffix(), "") self.assertEqual(n1.get_suffix(), "") l3 = pytree.Leaf(100, "bar", prefix="c") n2 = pytree.Node(1000, [n1, l3]) self.assertEqual(n1.get_suffix(), l3.prefix) self.assertEqual(l3.get_suffix(), "") self.assertEqual(n2.get_suffix(), "")
def transform(self, node, results): syms = self.syms exc = results["exc"].clone() if exc.type is token.STRING: self.cannot_convert(node, "Python 3 does not support string exceptions") return # Leave "g.throw(E)" alone val = results.get("val") if val is None: return val = val.clone() if is_tuple(val): args = [c.clone() for c in val.children[1:-1]] else: val.prefix = "" args = [val] throw_args = results["args"] if "tb" in results: tb = results["tb"].clone() tb.prefix = "" e = Call(exc, args) with_tb = Attr(e, Name("with_traceback")) + [ArgList([tb])] throw_args.replace(pytree.Node(syms.power, with_tb)) else: throw_args.replace(Call(exc, args))
def test_generate_matches(self): la = pytree.Leaf(1, "a") lb = pytree.Leaf(1, "b") lc = pytree.Leaf(1, "c") ld = pytree.Leaf(1, "d") le = pytree.Leaf(1, "e") lf = pytree.Leaf(1, "f") leaves = [la, lb, lc, ld, le, lf] root = pytree.Node(1000, leaves) pa = pytree.LeafPattern(1, "a", "pa") pb = pytree.LeafPattern(1, "b", "pb") pc = pytree.LeafPattern(1, "c", "pc") pd = pytree.LeafPattern(1, "d", "pd") pe = pytree.LeafPattern(1, "e", "pe") pf = pytree.LeafPattern(1, "f", "pf") pw = pytree.WildcardPattern( [[pa, pb, pc], [pd, pe], [pa, pb], [pc, pd], [pe, pf]], min=1, max=4, name="pw") self.assertEqual([x[0] for x in pw.generate_matches(leaves)], [3, 5, 2, 4, 6]) pr = pytree.NodePattern(type=1000, content=[pw], name="pr") matches = list(pytree.generate_matches([pr], [root])) self.assertEqual(len(matches), 1) c, r = matches[0] self.assertEqual(c, 1) self.assertEqual(str(r["pr"]), "abcdef") self.assertEqual(r["pw"], [la, lb, lc, ld, le, lf]) for c in "abcdef": self.assertEqual(r["p" + c], pytree.Leaf(1, c))
def test_remove_parentless(self): n1 = pytree.Node(1000, []) n1.remove() self.assertEqual(n1.parent, None) l1 = pytree.Leaf(100, "foo") l1.remove() self.assertEqual(l1.parent, None)
def test_node_prefix(self): l1 = pytree.Leaf(100, "foo") self.assertEqual(l1.prefix, "") n1 = pytree.Node(1000, [l1]) self.assertEqual(n1.prefix, "") n1.prefix = " " self.assertEqual(n1.prefix, " ") self.assertEqual(l1.prefix, " ")
def test_leaf_prev_sibling(self): l1 = pytree.Leaf(100, "a") l2 = pytree.Leaf(100, "b") p1 = pytree.Node(1000, [l1, l2]) self.assertIs(l2.prev_sibling, l1) self.assertEqual(l1.prev_sibling, None) self.assertEqual(p1.prev_sibling, None)
def test_replace_with_list(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "+") l3 = pytree.Leaf(100, "bar") n1 = pytree.Node(1000, [l1, l2, l3]) l2.replace([pytree.Leaf(100, "*"), pytree.Leaf(100, "*")]) self.assertEqual(str(n1), "foo**bar") self.assertIsInstance(n1.children, list)
def test_node_constructor_prefix(self): for prefix in ("xyz_", ""): l1 = pytree.Leaf(100, "self") l2 = pytree.Leaf(100, "foo", prefix="_") n1 = pytree.Node(1000, [l1, l2], prefix=prefix) self.assertTrue(str(n1), prefix + "self_foo") self.assertEqual(n1.prefix, prefix) self.assertEqual(l1.prefix, prefix) self.assertEqual(l2.prefix, "_")
def add_kwarg(self, l_nodes, s_kwd, n_expr): # XXX All this prefix-setting may lose comments (though rarely) n_expr.prefix = "" n_argument = pytree.Node( self.syms.argument, (Name(s_kwd), pytree.Leaf(token.EQUAL, "="), n_expr)) if l_nodes: l_nodes.append(Comma()) n_argument.prefix = " " l_nodes.append(n_argument)
def handle_tuple(tuple_arg, add_prefix=False): n = Name(self.new_name()) arg = tuple_arg.clone() arg.prefix = "" stmt = Assign(arg, n.clone()) if add_prefix: n.prefix = " " tuple_arg.replace(n) new_lines.append(pytree.Node(syms.simple_stmt, [stmt, end.clone()]))
def test_has_key_example(self): pattern = pytree.NodePattern( 331, (pytree.LeafPattern(7), pytree.WildcardPattern(name="args"), pytree.LeafPattern(8))) l1 = pytree.Leaf(7, "(") l2 = pytree.Leaf(3, "x") l3 = pytree.Leaf(8, ")") node = pytree.Node(331, [l1, l2, l3]) r = {} self.assertTrue(pattern.match(node, r)) self.assertEqual(r["args"], [l2])
def test_node_set_child(self): l1 = pytree.Leaf(100, "foo") n1 = pytree.Node(1000, [l1]) l2 = pytree.Leaf(100, "bar") n1.set_child(0, l2) self.assertEqual(l1.parent, None) self.assertEqual(l2.parent, n1) self.assertEqual(n1.children, [l2]) n2 = pytree.Node(1000, [l1]) n2.set_child(0, n1) self.assertEqual(l1.parent, None) self.assertEqual(n1.parent, n2) self.assertEqual(n2.parent, None) self.assertEqual(n2.children, [n1]) self.assertRaises(IndexError, n1.set_child, 4, l2) # I don't care what it raises, so long as it's an exception self.assertRaises(Exception, n1.set_child, 0, list)
def test_remove(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "foo") n1 = pytree.Node(1000, [l1, l2]) n2 = pytree.Node(1000, [n1]) self.assertEqual(n1.remove(), 0) self.assertEqual(n2.children, []) self.assertEqual(l1.parent, n1) self.assertEqual(n1.parent, None) self.assertEqual(n2.parent, None) self.assertFalse(n1.was_changed) self.assertTrue(n2.was_changed) self.assertEqual(l2.remove(), 1) self.assertEqual(l1.remove(), 0) self.assertEqual(n1.children, []) self.assertEqual(l1.parent, None) self.assertEqual(n1.parent, None) self.assertEqual(n2.parent, None) self.assertTrue(n1.was_changed) self.assertTrue(n2.was_changed)
def test_replace(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "+") l3 = pytree.Leaf(100, "bar") n1 = pytree.Node(1000, [l1, l2, l3]) self.assertEqual(n1.children, [l1, l2, l3]) self.assertIsInstance(n1.children, list) self.assertFalse(n1.was_changed) l2new = pytree.Leaf(100, "-") l2.replace(l2new) self.assertEqual(n1.children, [l1, l2new, l3]) self.assertIsInstance(n1.children, list) self.assertTrue(n1.was_changed)
def transform(self, node, results): # First, find the sys import. We'll just hope it's global scope. if "sys_import" in results: if self.sys_import is None: self.sys_import = results["sys_import"] return func = results["func"].clone() func.prefix = "" register = pytree.Node(syms.power, Attr(Name("atexit"), Name("register"))) call = Call(register, [func], node.prefix) node.replace(call) if self.sys_import is None: # That's interesting. self.warning( node, "Can't find sys import; Please add an atexit import at the top of your file." ) return # Now add an atexit import after the sys import. names = self.sys_import.children[1] if names.type == syms.dotted_as_names: names.append_child(Comma()) names.append_child(Name("atexit", " ")) else: containing_stmt = self.sys_import.parent position = containing_stmt.children.index(self.sys_import) stmt_container = containing_stmt.parent new_import = pytree.Node( syms.import_name, [Name("import"), Name("atexit", " ")]) new = pytree.Node(syms.simple_stmt, [new_import]) containing_stmt.insert_child(position + 1, Newline()) containing_stmt.insert_child(position + 2, new)
def test_node_append_child(self): n1 = pytree.Node(1000, []) l1 = pytree.Leaf(100, "foo") n1.append_child(l1) self.assertEqual(l1.parent, n1) self.assertEqual(n1.children, [l1]) l2 = pytree.Leaf(100, "bar") n1.append_child(l2) self.assertEqual(l2.parent, n1) self.assertEqual(n1.children, [l1, l2]) # I don't care what it raises, so long as it's an exception self.assertRaises(Exception, n1.append_child, list)
def test_node_insert_child(self): l1 = pytree.Leaf(100, "foo") n1 = pytree.Node(1000, [l1]) l2 = pytree.Leaf(100, "bar") n1.insert_child(0, l2) self.assertEqual(l2.parent, n1) self.assertEqual(n1.children, [l2, l1]) l3 = pytree.Leaf(100, "abc") n1.insert_child(2, l3) self.assertEqual(n1.children, [l2, l1, l3]) # I don't care what it raises, so long as it's an exception self.assertRaises(Exception, n1.insert_child, 0, list)
def transform(self, node, results): syms = self.syms tail = [n.clone() for n in results["tail"]] try_cleanup = [ch.clone() for ch in results["cleanup"]] for except_clause, e_suite in find_excepts(try_cleanup): if len(except_clause.children) == 4: (E, comma, N) = except_clause.children[1:4] comma.replace(Name("as", prefix=" ")) if N.type != token.NAME: # Generate a new N for the except clause new_N = Name(self.new_name(), prefix=" ") target = N.clone() target.prefix = "" N.replace(new_N) new_N = new_N.clone() # Insert "old_N = new_N" as the first statement in # the except body. This loop skips leading whitespace # and indents # TODO(cwinter) suite-cleanup suite_stmts = e_suite.children for i, stmt in enumerate(suite_stmts): if isinstance(stmt, pytree.Node): break # The assignment is different if old_N is a tuple or list # In that case, the assignment is old_N = new_N.args if is_tuple(N) or is_list(N): assign = Assign(target, Attr(new_N, Name("args"))) else: assign = Assign(target, new_N) # TODO(cwinter) stopgap until children becomes a smart list for child in reversed(suite_stmts[:i]): e_suite.insert_child(0, child) e_suite.insert_child(i, assign) elif N.prefix == "": # No space after a comma is legal; no space after "as", # not so much. N.prefix = " " # TODO(cwinter) fix this when children becomes a smart list children = [c.clone() for c in node.children[:3]] + try_cleanup + tail return pytree.Node(node.type, children)