Nutree is a Python library for tree data structures with an intuitive, yet powerful, API.
Nutree trees and nodes follow Python's container conventions where it makes sense for a tree structure, while deliberately diverging where a literal list/Sequence analogy would be misleading.
__len__ returns the total number of nodes in the tree (or direct children of a node),
__iter__ performs a depth-first traversal over descendants,
and __contains__ tests membership using the same matching rules as lookup.
__getitem__ is value-based rather than positional: an int is matched against id(node)
and node.data_id. Other values are matched against node.data.
A lookup that finds no match raises KeyError; one that finds more than one match
raises AmbiguousMatchError, which points you to find_first() or find_all() for
explicit control.
Because there is no meaningful notion of position in a tree, slicing and __reversed__
are intentionally not implemented — use traversal methods (iterate(),
order-specific walks) when you need directional or ordered access instead.
Nutree Facts
Handle multiple references of single objects ('clones')
Search by name pattern, id, or object reference
Compare two trees and calculate patches
Unobtrusive handling of arbitrary objects
Save as DOT file and graphwiz diagram
Nodes can be plain strings or objects
(De)Serialize to (compressed) JSON
Save as Mermaid flow diagram
Multiple traversal methods
Generate random trees
Convert to RDF graph
Fully type annotated
Typed child nodes
Memory efficient
Pretty print
Navigation
Filtering
Fast
Example
A simple tree, with text nodes
from nutree import Tree, Node
tree = Tree("Store")
n = tree.add("Records")
n.add("Let It Be")
n.add("Get Yer Ya-Ya's Out!")
n = tree.add("Books")
n.add("The Little Prince")
tree.print()Tree<'Store'>
├─── 'Records'
│ ├─── 'Let It Be'
│ ╰─── "Get Yer Ya-Ya's Out!"
╰─── 'Books'
╰─── 'The Little Prince'
Tree nodes wrap the data and also expose methods for navigation, searching, iteration, ...
records_node = tree["Records"]
assert isinstance(records_node, Node)
assert records_node.name == "Records"
print(records_node.first_child())Node<'Let It Be', data_id=510268653885439170>
Nodes may be strings or arbitrary objects:
alice = Person("Alice", age=23, guid="{123-456}")
tree.add(alice)
# Lookup nodes by object, data_id, name pattern, ...
assert isinstance(tree[alice].data, Person)
del tree[alice]Read the Docs for more.
