redbaron icon indicating copy to clipboard operation
redbaron copied to clipboard

How to get list of children?

Open yabberyabber opened this issue 7 years ago • 5 comments

Is there a way to get a list of a Node's children? Alternatively is it possible to get a list of which attributes of a Node are actually valid?

I'm writing code that recurses through a redbaron ast. At the moment, I have an if case for every subclass of Node, but it would be much simpler for me to have a default case that just recurses through all children.

This is a fantastic project and it's been extremely handy for me. Thank you!

yabberyabber avatar Jun 06 '17 02:06 yabberyabber

mmm, I am not sure that I get you clearly, but you can specify an argument recursive for find and find_all. As you can see in docs, it's already set up to True.

Could you be more specific, u wanna something like Visitor Pattern when u use ast module?

rojaster avatar Jun 06 '17 13:06 rojaster

Here's an example. I want to write a function that recursively visits each node in an ast

Let's say I have this bit of code that I want to recurse through.

def incX():
    global x
    x = x + 1
    return x

Right now my function looks like this. It's very long and there's a special case for every type of node and I'm probably going to forget to implement half the cases.

def visit_nodes(node):
    do_something(node)
    
    if isinstance(node, redbaron.nodes.DefNode):
        visit_nodes(node.decorators)
        visit_nodes(node.arguments)
        visit_nodes(node.value)
    elif isinstance(node, redbaron.base_nodes.LineProxyList):
        [visit_nodes(x) for x in node]
    elif isinstance(node, redbaron.nodes.GlobalNode):
        visit_nodes(node.value)
    elif isinstance(node, redbaron.base_nodes.CommaProxyList):
        [visit_nodes(x) for x in node]
    elif isinstance(node, redbaron.nodes.AssignmentNode):
        visit_nodes(node.target)
        visit_nodes(node.value)
    ...
    ...
    ...

It would be much cleaner for my purposes if there were some way to get the children of a node without needing to know anything about their relation. Here is what that code might look like:

def visit_nodes(node):
    do_something(node)
    
    for child in node.children():
        visit_nodes(child)

In reality, I want to recurse through two ast's at the same time so I can compare them. Is it possible to do this with the existing node.find() and node.find_all()?

yabberyabber avatar Jun 06 '17 17:06 yabberyabber

Hello,

There is actually no official API yet for that, you can find the internal way to do that there: https://github.com/PyCQA/redbaron/blob/master/redbaron/base_nodes.py#L271-L293 which I should really convert into something like a .walk method or something like that because it's a recurring demand (but test/docs takes time, feel free to submit a PR :))

Psycojoker avatar Jun 07 '17 00:06 Psycojoker

This is exactly what i was looking for, thank you so much!

Expect a PR from me in a few days. It's finals week at Poly and I need to procrastinate ;)

yabberyabber avatar Jun 07 '17 04:06 yabberyabber

@yabberyabber I can't get it, how that piece of code:

def visit_nodes(node):
    do_something(node)
    
    for child in node.children():
        visit_nodes(child)

could help you do not check a type of node? It's only a top-bottom recursive descent which could have done via node_list, cause, as I remember, It stores child nodes of the current element. And for your task, a Typed Visitor is much preferred.

But as @Psycojoker said, I would be happy to see something like that in redbaron)

rojaster avatar Jun 07 '17 10:06 rojaster