Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #47746 > unrolled thread
| Started by | Ronny Mandal <ronnyma@volatile.no> |
|---|---|
| First post | 2013-06-12 00:22 -0700 |
| Last post | 2013-06-12 03:36 -0700 |
| Articles | 3 — 2 participants |
Back to article view | Back to comp.lang.python
Modify code with AST Ronny Mandal <ronnyma@volatile.no> - 2013-06-12 00:22 -0700
Re: Modify code with AST Peter Otten <__peter__@web.de> - 2013-06-12 11:00 +0200
Re: Modify code with AST Ronny Mandal <ronnyma@volatile.no> - 2013-06-12 03:36 -0700
| From | Ronny Mandal <ronnyma@volatile.no> |
|---|---|
| Date | 2013-06-12 00:22 -0700 |
| Subject | Modify code with AST |
| Message-ID | <84561fb1-8784-47a6-b0ca-fc3449c1adf2@googlegroups.com> |
Hello,
I am trying to write a script which will parse a code segment (with ast.parse()), locate the correct function/method node (by name) in the resulting tree and replace this function (node) with another function (node), e.g.:
MyMod1.py:
class FooBar():
def Foo(self): #I want to replace this and only this
return 1
def Bar(self):
return 2
Here is the parser-class:
class FindAndTransform(NodeTransformer):
"""Visit the function and check name"""
def visit_FunctionDef(self, node):
if node.name == 'Foo': #Only replace if name is "Foo"
#Create a new function and assign it to node
node = parse('''
def add(n, m):
return n + m
''')
return node
When I run the parser on MyMod1.py and generate code (with codegen), the output is:
class FooBar():
def add(n, m):
return n + m
i.e. both methods are replaced. It seems like "node" in the parser contains all method bodies of class FooBar, not only Foo. When ran through a debugger, it iterates both methods. What I really wanted to do, was to replace only one method (Foo) and leave the other untouched.
I hope this was understandable conveyed.
Answers are highly appreciated.
Regards,
Ronny Mandal
[toc] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-06-12 11:00 +0200 |
| Message-ID | <mailman.3055.1371027635.3114.python-list@python.org> |
| In reply to | #47746 |
Ronny Mandal wrote:
> Hello,
>
> I am trying to write a script which will parse a code segment (with
> ast.parse()), locate the correct function/method node (by name) in the
> resulting tree and replace this function (node) with another function
> (node), e.g.:
>
> MyMod1.py:
>
> class FooBar():
> def Foo(self): #I want to replace this and only this
> return 1
>
> def Bar(self):
> return 2
>
> Here is the parser-class:
>
> class FindAndTransform(NodeTransformer):
> """Visit the function and check name"""
> def visit_FunctionDef(self, node):
> if node.name == 'Foo': #Only replace if name is "Foo"
> #Create a new function and assign it to node
> node = parse('''
> def add(n, m):
> return n + m
> ''')
> return node
>
> When I run the parser on MyMod1.py and generate code (with codegen), the
> output is:
>
> class FooBar():
> def add(n, m):
> return n + m
>
> i.e. both methods are replaced. It seems like "node" in the parser
> contains all method bodies of class FooBar, not only Foo. When ran through
> a debugger, it iterates both methods. What I really wanted to do, was to
> replace only one method (Foo) and leave the other untouched.
>
> I hope this was understandable conveyed.
I think the main problem is that you have to return the unchanged node (you
return None which might be an indentation accident). I also had to take the
add() FunctionDef out of the enclosing Module. So (I don't have codegen or
is it part of the stdlib?):
import ast
class FindAndTransform(ast.NodeTransformer):
def visit_FunctionDef(self, node):
if node.name == 'Foo':
node = ast.parse('''
def add(n, m):
return n + m
''').body[0]
return node
if __name__ == "__main__":
orig = """
class FooBar():
def Foo(self): #I want to replace this and only this
return 1
def Bar(self):
return 2
"""
p = ast.parse(orig)
q = FindAndTransform().visit(p)
qq = compile(q, "<nofile>", "exec")
exec(qq)
assert {n for n in dir(FooBar) if not n.startswith("_")} == {"Bar",
"add"}
[toc] | [prev] | [next] | [standalone]
| From | Ronny Mandal <ronnyma@volatile.no> |
|---|---|
| Date | 2013-06-12 03:36 -0700 |
| Message-ID | <59cc7d76-4310-49b9-bb73-153af7c34d6c@googlegroups.com> |
| In reply to | #47759 |
> I think the main problem is that you have to return the unchanged node (you
>
> return None which might be an indentation accident). I also had to take the
>
> add() FunctionDef out of the enclosing Module. So (I don't have codegen or
>
> is it part of the stdlib?):
Thank you, my problem is now solved. It was the indentation of the return statement which was the culprit. I forgot that visit() (in this context) is called once for each FunctionDef-node. I moved the return-statement one click to the left, then it worked.
codegen is not a part of the stdlib. It is written by Armin Ronacher (the same person who wrote ast) and it uses ast to generate python code from the AST.
Thanks!
Regards,
Ronny Mandal
>
>
>
> import ast
>
>
>
> class FindAndTransform(ast.NodeTransformer):
>
> def visit_FunctionDef(self, node):
>
> if node.name == 'Foo':
>
> node = ast.parse('''
>
> def add(n, m):
>
> return n + m
>
> ''').body[0]
>
> return node
>
>
>
> if __name__ == "__main__":
>
> orig = """
>
> class FooBar():
>
> def Foo(self): #I want to replace this and only this
>
> return 1
>
>
>
> def Bar(self):
>
> return 2
>
> """
>
>
>
> p = ast.parse(orig)
>
> q = FindAndTransform().visit(p)
>
> qq = compile(q, "<nofile>", "exec")
>
> exec(qq)
>
> assert {n for n in dir(FooBar) if not n.startswith("_")} == {"Bar",
>
> "add"}
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web