From: Tsize on
Hello,

I am hoping for a little help. I have been playing with the python
ast module and have run into
an issue that I need a little push on. I would like to be able to
change a specific element in a
specific node in an ast then compile the resulting ast. Consider the
simplified example below
with its output. In this example I would like a way to change a
specific addition operation. With the NodeTransformer I see how to
change every addition operator but not how to change a specific one.
I would like this to work on both the 2.6 and 3.1 branches. Ideally I
would like to read a file, count the instances of an operation of
interest and then use an index to make the
changes.

I am probably missing something simple but I am lost right now.

import ast

class SwitchMinusPlus(ast.NodeTransformer):

def visit_BinOp(self, node):
node = self.generic_visit(node)
if isinstance(node.op, ast.Add):
node.op = ast.Sub()
return node

myfile = open('trivial.py').read()
print myfile
tree = compile(myfile, '<string>', 'exec', ast.PyCF_ONLY_AST)
print ast.dump(tree, annotate_fields=False, include_attributes=False)
node = SwitchMinusPlus().visit(ast.parse(myfile))
print ast.dump(node, annotate_fields=False, include_attributes=False)

Which gives the following output: Note that this code changes the
addition operator to an
subtraction operator at the AST level for every instance.

a = 8
b = 6
c = b + a
d = c + a
Module([Assign([Name('a', Store())], Num(8)), Assign([Name('b', Store
())], Num(6)),
Assign([Name('c', Store())], BinOp(Name('b', Load()), Add(), Name('a',
Load()))),
Assign([Name('d', Store())], BinOp(Name('c', Load()), Add(), Name('a',
Load())))])

Module([Assign([Name('a', Store())], Num(8)), Assign([Name('b', Store
())], Num(6)),
Assign([Name('c', Store())], BinOp(Name('b', Load()), Sub(), Name('a',
Load()))),
Assign([Name('d', Store())], BinOp(Name('c', Load()), Sub(), Name('a',
Load())))])

Thanks in advance,
Thomas
From: Terry Reedy on
Tsize wrote:
> Hello,
>
> I am hoping for a little help. I have been playing with the python
> ast module and have run into
> an issue that I need a little push on. I would like to be able to
> change a specific element in a
> specific node in an ast then compile the resulting ast.

If you can identify the specific nodes you want to change, no problem

> Consider the simplified example below
> with its output. In this example I would like a way to change a
> specific addition operation. With the NodeTransformer I see how to
> change every addition operator but not how to change a specific one.

Which specific one or one?

> I would like this to work on both the 2.6 and 3.1 branches. Ideally I
> would like to read a file, count the instances of an operation of
> interest and then use an index to make the changes.

If 'specific one' means number i, great. In not, not.
>
> I am probably missing something simple but I am lost right now.

You have not said what 'specific one' means.
Nor what your general goal is, why you want to change asts.
>
> import ast
>
> class SwitchMinusPlus(ast.NodeTransformer):
>
> def visit_BinOp(self, node):
> node = self.generic_visit(node)
> if isinstance(node.op, ast.Add):

if isinstance(node.op, ast.Add) and isspecificnode(node):

> node.op = ast.Sub()
> return node
>
> myfile = open('trivial.py').read()
> print myfile
> tree = compile(myfile, '<string>', 'exec', ast.PyCF_ONLY_AST)
> print ast.dump(tree, annotate_fields=False, include_attributes=False)
> node = SwitchMinusPlus().visit(ast.parse(myfile))
> print ast.dump(node, annotate_fields=False, include_attributes=False)
>
> Which gives the following output: Note that this code changes the
> addition operator to an
> subtraction operator at the AST level for every instance.
>
> a = 8
> b = 6
> c = b + a
> d = c + a
> Module([Assign([Name('a', Store())], Num(8)), Assign([Name('b', Store
> ())], Num(6)),
> Assign([Name('c', Store())], BinOp(Name('b', Load()), Add(), Name('a',
> Load()))),
> Assign([Name('d', Store())], BinOp(Name('c', Load()), Add(), Name('a',
> Load())))])
>
> Module([Assign([Name('a', Store())], Num(8)), Assign([Name('b', Store
> ())], Num(6)),
> Assign([Name('c', Store())], BinOp(Name('b', Load()), Sub(), Name('a',
> Load()))),
> Assign([Name('d', Store())], BinOp(Name('c', Load()), Sub(), Name('a',
> Load())))])

From: Tsize on
Terry,

Thank you for responding. I actually figured out how to do this
shortly after posting the message. Sorry I wasn't quite clear enough
in my post, I will try to be a little more explict in the future.
Just to mention it I want to go to each node in the ast including
child nodes and change the values. I am making a limited mutation
analysis program. If it looks generally useful as I get further along
I will release the code. I did an early prototype that worked on the
text of the code itself but I thought that using the ast for this
would be better and maybe a little faster.

Regards,
Thomas