Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting parent of AST node in Python

I'm working with Abstract Syntax Trees in Python 3. The ast library gives many ways to get children of the node (you can use iter_child_nodes() or walk()) but no ways to get parent of one. Also, every node has links to its children, but it hasn't links to its parent.

How I can get the parent of AST node if I don't want to write some plugin to ast library?

What is the most correct way to do this?

like image 303
VeLKerr Avatar asked Jan 02 '16 21:01

VeLKerr


3 Answers

Here's some actual code:

for node in ast.walk(root):
    for child in ast.iter_child_nodes(node):
        child.parent = node

There's no need for a hash table, you can just put an attribute directly on the node.

like image 139
Alex Hall Avatar answered Sep 25 '22 01:09

Alex Hall


You might create some hash table associating AST nodes to AST nodes and scan (recursively) your topmost AST tree to register in that hash table the parent of each node.

like image 20
Basile Starynkevitch Avatar answered Sep 26 '22 01:09

Basile Starynkevitch


You can also use ast.NodeTransformer to achieve this:

Code:

import ast


class Parentage(ast.NodeTransformer):
    parent = None

    def visit(self, node):
        node.parent = self.parent
        self.parent = node
        node = super().visit(node)
        if isinstance(node, ast.AST):
            self.parent = node.parent
        return node

Usage:

module = Parentage().visit(ast.parse('def _(): ...'))
assert module.parent is None
assert module.body[0].parent is module

Later on when you want to edit the tree in some other way, you can subclass:

class SomeRefactoring(Parentage):
    def visit_XXX(node):
        self.generic_visit(node)
        f'do some work on {node.parent} here if you want'
        return node

Note:

Its worth noting that some nodes can have multiple parents. For example:

module = ast.parse("warnings.warn('Dinosaurs!')")
func = module.body[0].value.func
name, ctx = ast.iter_child_nodes(func)
assert ctx is next(ast.iter_child_nodes(name))

Which shows that the same ast.Load node ctx has two parents - func and name. The parent will be set by the last position that the node appears in in the tree.

like image 39
codeMonkey Avatar answered Sep 24 '22 01:09

codeMonkey