0

I'm trying to work with the ast class in Python. I want to get all Function calls and their corresponding arguments.

How can I Implement that? The official Documentation on python.org is really vague.

I also tried implementing visit_Name and visit_Call, but that gives me more than the names of the Call. It would be nice if there were some documentation which attributes which nodes possesses. For example, id for Name-nodes and func for Call-nodes.

ballade4op52
  • 2,142
  • 5
  • 27
  • 42
WeGi
  • 1,908
  • 1
  • 21
  • 33
  • 1
    The [Abstract Grammar](http://docs.python.org/3/library/ast.html#abstract-grammar) is auto-generated from the Python source code and is as good as it gets, I'm afraid. – Martijn Pieters May 03 '13 at 14:58
  • Note that functions are not the only things that are callable. Classes are callable, types are callable, instances with a `__call__` method are callable. Since you cannot introspect the type of the item being called, you'll indeed get to see more than just functions being called. – Martijn Pieters May 03 '13 at 15:00
  • Note that the after a while of looking at the abstract grammer, it starts to become easier to understand what is going on in all of that (and what the attributes are of the various ast node types). – mgilson May 03 '13 at 15:13
  • 4
    Check this out: http://greentreesnakes.readthedocs.org/en/latest/ – Aivar May 25 '13 at 09:01

1 Answers1

2

I know of no other documentation, but a lot can be learned by studying examples, such as this one, by Alex Martelli. You could start by modifying it just slightly, this way:

import ast

class FuncVisit(ast.NodeVisitor):
    def __init__(self):
        self.calls = []
        self.names = []
    def generic_visit(self, node):
        # Uncomment this to see the names of visited nodes
        # print(type(node).__name__)
        ast.NodeVisitor.generic_visit(self, node)
    def visit_Name(self, node):
        self.names.append(node.id)
    def visit_Call(self, node):
        self.names = []
        ast.NodeVisitor.generic_visit(self, node)
        self.calls.append(self.names)
        self.names = []        
    def visit_keyword(self, node):
        self.names.append(node.arg)

tree = ast.parse('''\
x = foo(a, b)
x += 1
bar(c=2)''')
v = FuncVisit()
v.visit(tree)
print(v.calls)

yields

[['foo', 'a', 'b'], ['bar', 'c']]
Community
  • 1
  • 1
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • What is the purpose of defining `generic_visit` on the `Visit` class? – mgilson May 03 '13 at 15:14
  • Also, why are you not visiting `Load` nodes (or any of their children)? – mgilson May 03 '13 at 15:15
  • @mgilson: Those are vestigial organs left over from other code :) Thanks for pointing out the mistake! (`generic_visit` can be very useful for debugging, however, so I'm leaving that code in there with a print statement to show how it could be used.) – unutbu May 03 '13 at 18:12
  • Yeah, generic_visit can be super useful for various things. But having the implementation just call the parent class's method isn't very useful (unless you put other information in there to help OP in the form of comments, etc). I'm happy with this now. – mgilson May 03 '13 at 20:26