How do I find a specific Python anytree descendant?

28 views Asked by At

The following Python anytree construction

top = Node("top")
a = Node("a", parent=top)
b = Node("b", parent=top)
c = Node("c", parent=a)
d = Node("d", parent=a)
e1 = Node("e", parent=c)
e2 = Node("e", parent=a)
c1 = Node("c", parent=b)
e3 = Node("e", parent=c1)
print(RenderTree(top, style=AsciiStyle()).by_attr())

produces this tree:

top
|-- a
|   |-- c
|   |   +-- e
|   |-- d
|   +-- e
+-- b
    +-- c
        +-- e

I want to process node a/c/e under top if that node exists. If it doesn't exist, I want to get None.

Here is what I have implemented that does what I want:

gnode = anytree.search.find(top, lambda node : str(node)=="Node('/top/a/c/e')")
print(f"Exp match, rcv {gnode}")

gnode = anytree.search.find(top, lambda node : str(node)=="Node('/top/a/c/f')")
print(f"Exp None, rcv {gnode}")

The above code returns the following:

Exp match, rcv Node('/top/a/c/e')
Exp None, rcv None

Although the code works, I'm thinking there must be a better way to do it -- something like top.get_descendant("a/c/e") that would directly access that node instead of searching for it.

What's the right way to access node a/c/e under node top (and get None if it doesn't exist)?

1

There are 1 answers

0
larsks On BEST ANSWER

Reading through the docs it looks like you want the anytree.resolver module:

import sys
import anytree

top = anytree.Node("top")
a = anytree.Node("a", parent=top)
b = anytree.Node("b", parent=top)
c = anytree.Node("c", parent=a)
d = anytree.Node("d", parent=a)
e1 = anytree.Node("e", parent=c)
e2 = anytree.Node("e", parent=a)
c1 = anytree.Node("c", parent=b)
e3 = anytree.Node("e", parent=c1)

r = anytree.resolver.Resolver()

for path in sys.argv[1:]:
    try:
        node = r.get(top, path)
        print(f"path {path} exists: {node}")
    except anytree.resolver.ChildResolverError:
        print(f"path {path} does not exist")

Testing the above code with a path that exists:

$ python nodes.py /top/a/c/e
path /top/a/c/e exists: Node('/top/a/c/e')

And with a path that does not exist:

$ python nodes.py /top/a/e/c
path /top/a/e/c does not exist