Prev: YIELD_VALUE Byte Code
Next: FYI: ConfigParser, ordered options, PEP 372 and OrderedDict + bigthank you
From: Tsize on 17 Nov 2009 09:55 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 17 Nov 2009 17:50 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 18 Nov 2009 08:32
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 |