Powerful and Lightweight Python Tree Data Structure with various plugins
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Multiple iteration strategies for traversing tree structures. This module provides different traversal algorithms with filtering and depth control options for comprehensive tree navigation.
Iterates over tree using pre-order strategy: visits node first, then its children. This is depth-first traversal where parent nodes are processed before their children.
class PreOrderIter(AbstractIter):
"""
Pre-order tree iteration (node, then children).
Args:
node: Starting node for iteration
filter_: Function called with every node as argument, node is returned if True
stop: Stop iteration at node if stop function returns True for node
maxlevel: Maximum descending in the node hierarchy
"""
def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...Usage Example:
from anytree import Node, PreOrderIter
root = Node("root")
sub0 = Node("sub0", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1 = Node("sub1", parent=root)
# Basic pre-order iteration
for node in PreOrderIter(root):
print(node.name)
# Output: root, sub0, sub0sub0, sub0sub1, sub1
# With filter
for node in PreOrderIter(root, filter_=lambda n: "sub0" in n.name):
print(node.name)
# Output: sub0, sub0sub0, sub0sub1
# With max level
for node in PreOrderIter(root, maxlevel=2):
print(f"{' ' * node.depth}{node.name}")Iterates over tree using post-order strategy: visits children first, then the node. Useful for operations that need to process children before parents (like deletion, size calculation).
class PostOrderIter(AbstractIter):
"""
Post-order tree iteration (children, then node).
Args:
node: Starting node for iteration
filter_: Function called with every node as argument, node is returned if True
stop: Stop iteration at node if stop function returns True for node
maxlevel: Maximum descending in the node hierarchy
"""
def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...Usage Example:
from anytree import Node, PostOrderIter
root = Node("root")
sub0 = Node("sub0", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1 = Node("sub1", parent=root)
# Post-order iteration - children before parents
for node in PostOrderIter(root):
print(node.name)
# Output: sub0sub0, sub0sub1, sub0, sub1, root
# Calculate subtree sizes using post-order
def calculate_sizes(node):
for n in PostOrderIter(node):
n.size = 1 + sum(child.size for child in n.children)
return node.size
size = calculate_sizes(root)
print(f"Total nodes: {size}")Iterates over tree using level-order (breadth-first) strategy: visits all nodes at depth N before visiting nodes at depth N+1.
class LevelOrderIter(AbstractIter):
"""
Level-order tree iteration (breadth-first).
Args:
node: Starting node for iteration
filter_: Function called with every node as argument, node is returned if True
stop: Stop iteration at node if stop function returns True for node
maxlevel: Maximum descending in the node hierarchy
"""
def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...Usage Example:
from anytree import Node, LevelOrderIter
root = Node("root")
sub0 = Node("sub0", parent=root)
sub1 = Node("sub1", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1sub0 = Node("sub1sub0", parent=sub1)
# Level-order iteration - breadth-first
for node in LevelOrderIter(root):
print(f"Level {node.depth}: {node.name}")
# Output:
# Level 0: root
# Level 1: sub0
# Level 1: sub1
# Level 2: sub0sub0
# Level 2: sub0sub1
# Level 2: sub1sub0Iterates over tree using level-order strategy but returns groups of nodes for each level. Each iteration yields a tuple of all nodes at the current depth.
class LevelOrderGroupIter(AbstractIter):
"""
Level-order tree iteration returning groups for each level.
Args:
node: Starting node for iteration
filter_: Function called with every node as argument, node is returned if True
stop: Stop iteration at node if stop function returns True for node
maxlevel: Maximum descending in the node hierarchy
"""
def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...Usage Example:
from anytree import Node, LevelOrderGroupIter
root = Node("root")
sub0 = Node("sub0", parent=root)
sub1 = Node("sub1", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
# Group iteration - one tuple per level
for level_nodes in LevelOrderGroupIter(root):
names = [node.name for node in level_nodes]
print(f"Level: {names}")
# Output:
# Level: ['root']
# Level: ['sub0', 'sub1']
# Level: ['sub0sub0', 'sub0sub1']
# Useful for level-based processing
for depth, level_nodes in enumerate(LevelOrderGroupIter(root)):
print(f"Processing {len(level_nodes)} nodes at depth {depth}")Iterates over tree using level-order strategy with alternating left-to-right and right-to-left direction for each level. Returns groups like LevelOrderGroupIter but alternates direction.
class ZigZagGroupIter(AbstractIter):
"""
ZigZag level-order iteration returning groups (alternating direction).
Args:
node: Starting node for iteration
filter_: Function called with every node as argument, node is returned if True
stop: Stop iteration at node if stop function returns True for node
maxlevel: Maximum descending in the node hierarchy
"""
def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...Usage Example:
from anytree import Node, ZigZagGroupIter
root = Node("root")
sub0 = Node("sub0", parent=root)
sub1 = Node("sub1", parent=root)
sub2 = Node("sub2", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1sub0 = Node("sub1sub0", parent=sub1)
# ZigZag iteration - alternating direction per level
for level_nodes in ZigZagGroupIter(root):
names = [node.name for node in level_nodes]
print(f"Level: {names}")
# Output:
# Level: ['root']
# Level: ['sub0', 'sub1', 'sub2'] (left-to-right)
# Level: ['sub1sub0', 'sub0sub1', 'sub0sub0'] (right-to-left)Base class for all tree iterators. Provides common functionality and interface for custom iteration strategies.
class AbstractIter:
"""
Base class for tree iteration.
"""
def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...
def __iter__(self): ...
def __next__(self): ...All iterators support filter functions for selective traversal:
from anytree import Node, PreOrderIter
root = Node("root")
Node("file.txt", parent=root, type="file")
Node("doc.pdf", parent=root, type="file")
Node("subdir", parent=root, type="directory")
# Filter by attribute
files_only = PreOrderIter(root, filter_=lambda n: getattr(n, 'type', None) == 'file')
for node in files_only:
print(node.name)
# Filter by name pattern
txt_files = PreOrderIter(root, filter_=lambda n: n.name.endswith('.txt'))
for node in txt_files:
print(node.name)
# Filter by depth
shallow_nodes = PreOrderIter(root, filter_=lambda n: n.depth <= 2)Control iteration termination with stop functions:
from anytree import Node, PreOrderIter
root = Node("root")
private_dir = Node("private", parent=root)
Node("secret.txt", parent=private_dir)
public_dir = Node("public", parent=root)
Node("readme.txt", parent=public_dir)
# Stop at private directories
public_only = PreOrderIter(root, stop=lambda n: n.name == 'private')
for node in public_only:
print(node.name)
# Output: root, public, readme.txt (skips private subtree)
# Stop when reaching max file count
file_count = 0
def stop_at_limit(node):
global file_count
if hasattr(node, 'type') and node.type == 'file':
file_count += 1
return file_count >= 3
limited_iter = PreOrderIter(root, stop=stop_at_limit)Control maximum traversal depth:
from anytree import Node, PreOrderIter
# Create deep tree
root = Node("level0")
current = root
for i in range(1, 6):
current = Node(f"level{i}", parent=current)
# Limit to first 3 levels
for node in PreOrderIter(root, maxlevel=3):
print(f"{' ' * node.depth}{node.name}")
# Output includes level0, level1, level2 onlyAll iterators are lazy and memory-efficient, yielding nodes on-demand rather than creating lists. For very large trees, prefer iterators over collecting results into lists:
# Memory efficient - processes one node at a time
for node in PreOrderIter(huge_tree):
process_node(node)
# Memory intensive - creates full list
all_nodes = list(PreOrderIter(huge_tree)) # Avoid for large treesInstall with Tessl CLI
npx tessl i tessl/pypi-anytree