Index: Lib/lib2to3/pytree.py =================================================================== --- Lib/lib2to3/pytree.py (revision 77840) +++ Lib/lib2to3/pytree.py (working copy) @@ -132,6 +132,8 @@ def replace(self, new): """Replace this node with a new one in the parent.""" + if self is new: + return assert self.parent is not None, str(self) assert new is not None if not isinstance(new, list): @@ -149,9 +151,12 @@ assert found, (self.children, self, new) self.parent.changed() self.parent.children = l_children + # one of the new nodes may be self; + # make sure it doesn't lose its parent. + parent = self.parent + self.parent = None for x in new: - x.parent = self.parent - self.parent = None + x.parent = parent def get_lineno(self): """Return the line number which generated the invocant node.""" Index: Lib/lib2to3/tests/test_pytree.py =================================================================== --- Lib/lib2to3/tests/test_pytree.py (revision 77840) +++ Lib/lib2to3/tests/test_pytree.py (working copy) @@ -157,6 +157,8 @@ self.assertEqual(n1.children, [l1, l2, l3]) self.assertTrue(isinstance(n1.children, list)) self.assertFalse(n1.was_changed) + l2.replace(l2) + self.assertEqual(l2.parent, n1) l2new = pytree.Leaf(100, "-") l2.replace(l2new) self.assertEqual(n1.children, [l1, l2new, l3]) @@ -173,6 +175,22 @@ self.assertEqual(str(n1), "foo**bar") self.assertTrue(isinstance(n1.children, list)) + l1.replace([l1, l2, pytree.Leaf(100, "baz")]) + self.assertEqual(l1.parent, n1) + self.assertEqual(str(n1), "foo+baz**bar") + self.assertTrue(isinstance(n1.children, list)) + + l2.replace([pytree.Leaf(100, "*"), pytree.Leaf(100, "bar"), l2]) + self.assertEqual(l2.parent, n1) + self.assertEqual(str(n1), "foo*bar+baz**bar") + self.assertTrue(isinstance(n1.children, list)) + + l2.replace([pytree.Leaf(100, "*"), pytree.Leaf(100, "foo"), l2, + pytree.Leaf(100, "bar"), pytree.Leaf(100, "*")]) + self.assertEqual(l2.parent, n1) + self.assertEqual(str(n1), "foo*bar*foo+bar*baz**bar") + self.assertTrue(isinstance(n1.children, list)) + def test_post_order(self): l1 = pytree.Leaf(100, "foo") l2 = pytree.Leaf(100, "bar")