AlgoTree package¶
Submodules¶
AlgoTree.dsl module¶
DSL (Domain Specific Language) for tree definition.
Supports multiple formats: - Visual tree format (with Unicode box characters) - Indent-based format (YAML-like) - S-expression format
- AlgoTree.dsl.parse_tree(text: str, format: str = 'auto') Node [source]¶
Convenience function to parse tree from DSL text.
- Parameters:
text – DSL text to parse.
format – Format to use (‘visual’, ‘indent’, ‘sexpr’, ‘auto’).
- Returns:
Root node of parsed tree.
Examples
# Visual format tree = parse_tree(‘’’
company ├── engineering │ ├── frontend │ └── backend └── sales
‘’’)
# Indent format tree = parse_tree(‘’’
- company
- engineering
frontend backend
sales
‘’’)
# S-expression format tree = parse_tree(‘’’
- (company
- (engineering
(frontend) (backend))
(sales))
‘’’)
AlgoTree.exporters module¶
Tree export functionality for various formats.
This module provides exporters to convert trees to different representations including GraphViz, Mermaid, ASCII/Unicode trees, and more.
- class AlgoTree.exporters.TreeExporter[source]¶
Bases:
object
Base class for tree exporters.
- static to_ascii(node: Node, style: str = 'ascii') str [source]¶
Export tree to ASCII/Unicode art.
- Parameters:
node – Root node of tree
style – “ascii” for ASCII characters, “unicode” for box drawing
- Returns:
String representation of tree
- static to_dict(node: Node) Dict[str, Any] [source]¶
Export tree to dictionary (already implemented in Node).
- static to_graphviz(node: Node, name: str = 'Tree', node_attr: Callable[[Node], Dict[str, str]] | None = None, edge_attr: Callable[[Node, Node], Dict[str, str]] | None = None, graph_attr: Dict[str, str] | None = None) str [source]¶
Export tree to GraphViz DOT format.
- Parameters:
node – Root node of tree
name – Graph name
node_attr – Function to generate node attributes
edge_attr – Function to generate edge attributes
graph_attr – Graph-level attributes
- Returns:
DOT format string
Example
- dot = TreeExporter.to_graphviz(tree,
node_attr=lambda n: {“label”: f”{n.name}n{n.payload.get(‘size’, ‘’)}”})
- static to_html(node: Node, include_styles: bool = True, collapsible: bool = True) str [source]¶
Export tree to interactive HTML.
- Parameters:
node – Root node of tree
include_styles – Include CSS styles
collapsible – Make tree nodes collapsible
- Returns:
HTML string representation
- static to_mermaid(node: Node, direction: str = 'TD', node_shape: str = 'round', node_text: Callable[[Node], str] | None = None) str [source]¶
Export tree to Mermaid diagram format.
- Parameters:
node – Root node of tree
direction – Graph direction (TD, TB, BT, RL, LR)
node_shape – Shape style (“round”, “square”, “circle”, “rhombus”, “stadium”)
node_text – Function to generate node text
- Returns:
Mermaid format string
Example
- mermaid = TreeExporter.to_mermaid(tree,
node_text=lambda n: f”{n.name}<br/>{n.payload.get(‘type’, ‘’)}”)
- static to_unicode(node: Node) str [source]¶
Export tree to Unicode box drawing (alias for to_ascii with unicode style).
- AlgoTree.exporters.export_tree(node: Node, format: str, **kwargs) str [source]¶
Export tree to specified format.
- Parameters:
node – Root node of tree
format – Export format (json, ascii, unicode, graphviz, mermaid, yaml, xml, html)
**kwargs – Format-specific options
- Returns:
String representation in specified format
- AlgoTree.exporters.save_tree(node: Node, filepath: str, format: str | None = None, **kwargs)[source]¶
Save tree to file in specified format.
- Parameters:
node – Root node of tree
filepath – Output file path
format – Export format (auto-detected from extension if not specified)
**kwargs – Format-specific options
AlgoTree.flat_forest module¶
- class AlgoTree.flat_forest.FlatForest(*args: Any, **kwargs: Any)[source]¶
Bases:
dict
A forest class that is also a standard dictionary.
This class represents a forest using a flat dictionary structure where each node has a unique name (key) and an optional ‘parent’ name (keY) to reference its parent node.
Nodes without a ‘parent’ key (or with a ‘parent’ key set to None) are root nodes of trees in the forest. Nodes with a ‘parent’ key set to a valid name (key) in the forest are children of the node with that name. Each node represents a tree rooted at that node, which we expose through the FlatForestNode class, which provides a proxy interface to the structure centered around nodes abstracted away from the dictionary structure.
The FlatForest class is a dictionary whose data represents a forest-like structure. It provides methods to manipulate the forest structure and validation methods to check its integrity, but is essentially a view of the dict object passed into it (or created with it).
We provide a FlatForestNode class which provides an interface centered around nodes in a tree. See flat_forest_node.py for more details.
- DETACHED_KEY = '__DETACHED__'¶
The name used to represent a detached node. This is a special name that is assumed to not exist in the tree. When a node is detached, its parent name is set to this value. Any descendants of the detached node are also detached.
- PARENT_KEY = 'parent'¶
The key used to store the parent key of a node. Modify this if you want to use a different key to store the parent key.
- add_child(name: str | None = None, *args, **kwargs) FlatForestNode [source]¶
Add a child node to the preferred root node.
- Parameters:
name – The name of the child node.
payload – The payload of the child node.
- Returns:
The child node.
- as_tree(root_name='__ROOT__') FlatForestNode [source]¶
Retrieve the forest as a single tree rooted at a logical root node.
- static check_valid(data) None [source]¶
Validate the forest structure to ensure the structural integrity of the trees.
This function performs the following validation checks:
No cycles exist in any trees.
All names (unique node identifiers) map to dictionary values.
All nodes have a parent key that is either None or a valid key in the tree.
- Parameters:
data – The forest data to validate.
- Returns:
None
- Raises:
ValueError – If the forest structure is invalid.
- child_names(name: str) List[str] [source]¶
Get the children names of a node with the given name.
- Parameters:
name – The name of the node to get the children of.
- Returns:
List of names of the children of the node.
- property children¶
Get the children of the preferred root node.
- Returns:
The children of the preferred root node.
- contains(name: str) bool [source]¶
Check if the tree rooted at the preferred root node contains a node with the given name.
- Parameters:
name – The name of the node.
- Returns:
True if the node is in the forest, False otherwise.
- detach(name: str) FlatForestNode [source]¶
Detach subtree rooted at node with the given name by setting its parent to FlatForest.DETACHED_KEY, which denotes a special name (key) that we assume doesn’t exist in the forest.
- Parameters:
name – The name of the node to detach.
- Returns:
The detached subtree rooted at the node.
- Raises:
KeyError – If the node is not found in the tree.
- property detached: FlatForestNode¶
Retrieve the detached tree. This is a special tree for which detached nodes are rooted at a logical node with the name FlatForest.DETACHED_KEY.
- Returns:
The detached logical root node.
- interior_node_names() List[str] [source]¶
Get interior node names, i.e., nodes that are not root nodes or logical nodes.
- Returns:
List of interior node names.
- static is_valid(data) bool [source]¶
Check if the given data is a valid FlatForest.
- Parameters:
data – The data to check.
- Returns:
True if the data is a valid FlatForest, False otherwise.
- logical_root_names() List[str] [source]¶
Get the logical nodes of the forest. These occur when a node has a parent that is not in the forest. A special case for this is the DETACHED_KEY which is used for detached nodes, i.e., when we detach a node, we set its parent to DETACHED_KEY.
- Returns:
List of logical root names.
- property name: str¶
Get the name of the preferred root node. This is just self.preferred_root.
- Returns:
The name of the preferred root node.
- node(name: str) FlatForestNode [source]¶
Get an ancestor node with the given name under the preferred root node.
- Parameters:
name – The name of the node.
- Returns:
The node.
- node_names() List[str] [source]¶
Get the unique names in the tree, even if they are not nodes in the tree but only parent names without corresponding nodes.
- Returns:
List of unique names in the tree.
- nodes() List[FlatForestNode] [source]¶
Get all the nodes in the forest.
- Returns:
A list of all the nodes in the forest.
- property parent: FlatForestNode | None¶
Get the parent of the preferred root node. This is always None since the preferred root node is a root node.
- property payload: dict¶
Get the payload of the preferred root node.
- Returns:
The payload of the preferred root node.
- property preferred_root: str¶
Get the preferred root node of the forest.
- Returns:
The preferred root node.
- Raises:
KeyError – If the preferred root node is not found.
- property root: FlatForestNode¶
Get the tree rooted at the preferred root node.
- Returns:
The root node.
- root_key(name: str) str [source]¶
Get the root key of the node with given name.
- Parameters:
key – The key of the node.
- Returns:
The key of the root node.
- Raises:
KeyError – If the key is not found in the tree.
- property root_names: List[str]¶
Retrieve the names of the root nodes. These are the nodes that have no parent.
- Returns:
The names of the root nodes.
- property roots: List[FlatForestNode]¶
Get the root nodes of the forest.
- Returns:
The root nodes of the forest.
- static spec() dict [source]¶
Get the JSON specification of the FlatForest data structure.
This method returns a dictionary representing the structure of the FlatForest. This is useful for documentation purposes and for understanding the structure of the data. The structure is as follows:
:return: A dict pattern representing the structure of the FlatForest.
- subtree(name: str | None = None) FlatForestNode [source]¶
Get sub-tree rooted at the node with the name name with the current node also set to that node. If name is None, the preferred root node is used.
NOTE: This behavior is different from the expected behavior of a tree, since this is a forest. If the forest has multiple trees, this method will return any subtree under any root node. We could instead return the subtree under the preferred root node, which would then replicate the expected behavior and be consistent with the other node-centric methods like node and children. However, we choose to return the subtree under any root node to provide more flexibility. Once you return a subtree, the FlatForestNode class provides a node-centric interface to the tree structure consistent with the expected behavior.
- Parameters:
name – The unique name of the node.
- Returns:
FlatForestNode proxy representing the node.
- to_dict() dict [source]¶
Convert the forest to a dictionary. Note this since this is already a dictionary, we just return a copy of the dictionary.
- Returns:
A dictionary representation of the forest.
- property trees: List[FlatForestNode]¶
Retrieve the trees in the forest.
- Returns:
The trees in the forest.
AlgoTree.flat_forest_node module¶
- class AlgoTree.flat_forest_node.FlatForestNode(name: str | None = None, parent: FlatForestNode | str | None = None, forest: FlatForest | None = None, payload: Dict | None = None, *args, **kwargs)[source]¶
Bases:
MutableMapping
- add_child(name: str | None = None, *args, **kwargs) FlatForestNode [source]¶
Add a child node. See __init__ for details on the arguments.
- Returns:
The child node, from the perspective of the subtree that contains the parent.
- property children: List[FlatForestNode]¶
Get the children of the node.
- Returns:
List of child nodes.
- clone(parent=None, clone_children=False) FlatForestNode [source]¶
Clone the node and, optionally, its children. If you want to clone the entire forest, see deepcopy. We allow the parent to be set to a new parent node to facilitate flexible cloning of nodes into new forest structures.
- Returns:
A new node (or subtree rooted at the node if clone_children is True)
- contains(name) bool [source]¶
Check if the the subtree rooted at the node contains any children with the given name
- Parameters:
key – The key to check.
- Returns:
True if the child node is present, False otherwise.
- detach() FlatForestNode [source]¶
Detach the node.
- Returns:
The detached node.
- property forest: FlatForest¶
Get the underlying FlatForest object.
- Returns:
The FlatForest object.
- property name¶
Get the unique name of the node.
- Returns:
The unique name of the node.
- node(name: str) FlatForestNode [source]¶
Get an ancestor node with the given name.
- Parameters:
name – The name of the node.
- Returns:
The node.
- property parent: FlatForestNode | None¶
Get the parent node of the node.
- Returns:
The parent node.
- property payload: Dict¶
Get the payload data of the node.
- Returns:
Dictionary representing the data of the node.
- static proxy(forest: FlatForest, node_key: str, root_key: str | None = None) FlatForestNode [source]¶
Create a proxy node for a node in a forest. The proxy node is a lightweight object that provides a node-centric abstraction of the tree that a node is a part of.
We do not check do any checks on the validity of the keys or the structure of the tree. This is a low-level method that should be used with caution. For instance, if node_key is not a descendent of root_key, the proxy node will not behave as expected.
- Parameters:
forest – The forest in which the proxy node exists (or logically exists).
node_key – The key of the node.
root_key – The key of the (real or logical) root node.
- property root: FlatForestNode¶
Get the root node of the subtree.
- Returns:
The root node.
- subtree(name: str | None = None) FlatForestNode [source]¶
Get a subtree rooted at the node with the name name. If name is None, the subtree is rooted at the current node.
- Parameters:
name – The name of the root node.
- Returns:
A subtree rooted at the given node.
AlgoTree.fluent module¶
Fluent API for tree construction and manipulation.
- class AlgoTree.fluent.FluentNode(node: Node | List[Node])[source]¶
Bases:
object
Wrapper for Node that provides fluent API for tree operations.
Example
- result = (FluentNode(tree)
.filter(lambda n: n.level <= 2) .map(lambda n: n.payload.get(‘size’, 0)) .where(lambda n: n > 5) .to_list())
- children() FluentNode [source]¶
Get all children of current nodes.
- Returns:
New FluentNode with all children.
- descendants() FluentNode [source]¶
Get all descendants of current nodes.
- Returns:
New FluentNode with all descendants.
- each(action: Callable[[Node], None]) FluentNode [source]¶
Execute an action on each node.
- Parameters:
action – Function to execute on each node.
- Returns:
Self for method chaining.
- filter(predicate: Callable[[Node], bool]) FluentNode [source]¶
Filter nodes by predicate.
- Parameters:
predicate – Function that returns True for nodes to keep.
- Returns:
New FluentNode with filtered nodes.
- leaves() FluentNode [source]¶
Get all leaf nodes from current nodes.
- Returns:
New FluentNode with leaf nodes only.
- map(transform: Callable[[Node], Any]) FluentNode [source]¶
Transform each node’s payload.
- Parameters:
transform – Function to transform each node.
- Returns:
Self for method chaining.
- match(pattern: str | Pattern | dict) FluentNode [source]¶
Find nodes matching a pattern.
- Parameters:
pattern – Pattern to match (string, Pattern object, or dict)
- Returns:
New FluentNode with matching nodes.
- prune(predicate: Callable[[Node], bool]) FluentNode [source]¶
Remove nodes matching predicate.
- Parameters:
predicate – Function that returns True for nodes to remove.
- Returns:
Self for method chaining.
- replace_matches(pattern: str | Pattern | dict, replacement: Node | Callable[[Node], Node]) FluentNode [source]¶
Replace nodes matching a pattern.
- Parameters:
pattern – Pattern to match
replacement – Node or function to generate replacement
- Returns:
Self for method chaining.
- sort(key: Callable[[Node], Any] | None = None, reverse: bool = False) FluentNode [source]¶
Sort children of each node.
- Parameters:
key – Function to extract sort key from each node.
reverse – Whether to sort in reverse order.
- Returns:
Self for method chaining.
- to_dict() dict | List[dict] [source]¶
Convert to dictionary representation.
- Returns:
Dictionary or list of dictionaries.
- where(predicate: Callable[[Node], bool]) FluentNode [source]¶
Filter current nodes by predicate (alias for filter on current set).
- Parameters:
predicate – Function that returns True for nodes to keep.
- Returns:
New FluentNode with filtered nodes.
- class AlgoTree.fluent.TreeBuilder[source]¶
Bases:
object
Fluent API for building trees with method chaining.
Example
- tree = (TreeBuilder()
.root(“company”, type=”corporation”) .child(“engineering”, head=”Alice”)
.child(“frontend”, team_size=5) .sibling(“backend”, team_size=8) .up()
.sibling(“sales”, head=”Bob”) .build())
- child(name: str, **payload) TreeBuilder [source]¶
Add a child to the current node and move to it.
- Parameters:
name – Name for the child node.
**payload – Data for the child node.
- Returns:
Self for method chaining.
- root(name: str, **payload) TreeBuilder [source]¶
Create the root node.
- Parameters:
name – Name for the root node.
**payload – Data for the root node.
- Returns:
Self for method chaining.
- sibling(name: str, **payload) TreeBuilder [source]¶
Add a sibling to the current node.
- Parameters:
name – Name for the sibling node.
**payload – Data for the sibling node.
- Returns:
Self for method chaining.
- to_root() TreeBuilder [source]¶
Move to the root node.
- Returns:
Self for method chaining.
- up(levels: int = 1) TreeBuilder [source]¶
Move up in the tree by specified levels.
- Parameters:
levels – Number of levels to move up. Default is 1.
- Returns:
Self for method chaining.
AlgoTree.node module¶
Modern node implementation using proper classes instead of dict inheritance.
- class AlgoTree.node.Node(name: str | None = None, parent: Node | None = None, **payload)[source]¶
Bases:
object
A tree node with proper attributes instead of dict inheritance.
This class represents a single node in a tree structure with: - A unique name/identifier - Optional parent reference - List of children - Arbitrary payload data
- add_child(name: str | None = None, **payload) Node [source]¶
Add a child node.
- Parameters:
name – Name for the child node.
**payload – Data for the child node.
- Returns:
The newly created child node.
- find(predicate: Callable[[Node], bool]) Node | None [source]¶
Find first node matching predicate.
- Parameters:
predicate – Function that returns True for matching nodes.
- Returns:
First matching node or None.
- find_all(predicate: Callable[[Node], bool]) List[Node] [source]¶
Find all nodes matching predicate.
- Parameters:
predicate – Function that returns True for matching nodes.
- Returns:
List of matching nodes.
- classmethod from_dict(data: Dict[str, Any], parent: Node | None = None) Node [source]¶
Create tree from nested dictionary representation.
- Parameters:
data – Dictionary with node data and optional ‘children’ key.
parent – Parent node for the created tree.
- Returns:
Root node of created tree.
- property is_leaf: bool¶
Check if this is a leaf node.
- property is_root: bool¶
Check if this is a root node.
- property level: int¶
Get the level (depth) of this node in the tree.
AlgoTree.node_hasher module¶
- class AlgoTree.node_hasher.NodeHasher(hash_fn: Callable[[Any], int] | None = None)[source]¶
Bases:
object
A class providing various hash functions for tree nodes.
- static name(node: Any) int [source]¶
Compute a hash based on the name of the node.
Use Case: - Useful when you want to compare nodes solely based on their names, ignoring their position and other attributes.
Example: - Checking if two nodes represent the same entity based on their name.
- Parameters:
node – The node for which to compute the hash.
- Returns:
The hash value for the node’s name.
- static node(node: Any) int [source]¶
Compute a hash based on the name and payload of the node.
Use Case: - This is the most common notion of node equality, focusing on the node’s intrinsic properties and ignoring its position in the tree. - Useful when you want to compare nodes by both name and payload, but not their position in the tree.
Example: - Checking if two nodes are equivalent in terms of both their name and the data they carry, without considering their location in the tree structure.
- Parameters:
node – The node for which to compute the hash.
- Returns:
The hash value for the node’s name and payload.
- static path(node: Any) int [source]¶
Compute a hash based on the path of the node in the tree.
Use Case: - Useful when the position of the node in the tree is more important than its name or payload.
Example: - Determining if two nodes occupy the same position in the same or different trees.
- Parameters:
node – The node for which to compute the hash.
- Returns:
The hash value for the node’s path in the tree.
- static payload(node: Any) int [source]¶
Compute a hash based on the payload of the node.
Use Case: - Useful when comparing nodes based on their payload, ignoring their name and position in the tree.
Example: - Identifying nodes that carry the same data.
- Parameters:
node – The node for which to compute the hash.
- Returns:
The hash value for the node’s payload.
AlgoTree.pattern_matcher module¶
Tree pattern matching functionality.
This module provides pattern matching capabilities for tree structures, allowing users to search for specific structural patterns within trees.
- class AlgoTree.pattern_matcher.MatchType(*values)[source]¶
Bases:
Enum
Types of pattern matching.
- EXACT = 'exact'¶
- PARTIAL = 'partial'¶
- WILDCARD = 'wildcard'¶
- class AlgoTree.pattern_matcher.Pattern(name: str | None = None, attributes: ~typing.Dict[str, ~typing.Any] = <factory>, children: ~typing.List[~AlgoTree.pattern_matcher.Pattern] = <factory>, is_wildcard: bool = False, is_deep_wildcard: bool = False, min_children: int | None = None, max_children: int | None = None, predicate: ~typing.Callable[[~AlgoTree.node.Node], bool] | None = None)[source]¶
Bases:
object
Represents a tree pattern to match against.
Patterns can include: - Exact node matches - Wildcards (*) that match any single node - Deep wildcards (**) that match any subtree - Attribute constraints
- attributes: Dict[str, Any]¶
- static from_dict(pattern_dict: Dict[str, Any]) Pattern [source]¶
Create a pattern from dictionary representation.
Example
- {
“name”: “parent”, “attributes”: {“type”: “container”}, “children”: [
{“name”: “child1”}, {“name”: “*”} # Wildcard child
]
}
- static from_string(pattern_str: str) Pattern [source]¶
Parse a pattern from string notation.
Examples
“root” # Match node named ‘root’ “*” # Match any single node “**” # Match any subtree “node[type=foo]” # Match node with attribute “parent(child1, child2)” # Match parent with specific children “root.branch.leaf” # Dot notation path “app.*.test” # Dot notation with wildcard “root.**.target” # Dot notation with deep wildcard
- is_deep_wildcard: bool = False¶
- is_wildcard: bool = False¶
- max_children: int | None = None¶
- min_children: int | None = None¶
- name: str | None = None¶
- class AlgoTree.pattern_matcher.PatternMatcher(match_type: MatchType = MatchType.PARTIAL)[source]¶
Bases:
object
Matches patterns against tree structures.
- find_all(tree: Node, pattern: Pattern) List[Node] [source]¶
Find all nodes in tree that match the pattern.
- Parameters:
tree – Root node of tree to search
pattern – Pattern to match
- Returns:
List of nodes that match the pattern
- find_first(tree: Node, pattern: Pattern) Node | None [source]¶
Find first node that matches the pattern.
- Parameters:
tree – Root node of tree to search
pattern – Pattern to match
- Returns:
First matching node or None
- match(node: Node, pattern: Pattern) bool [source]¶
Check if a node matches a pattern.
- Parameters:
node – Node to match against
pattern – Pattern to match
- Returns:
True if node matches pattern
- replace(tree: Node, pattern: Pattern, replacement: Node | Callable[[Node], Node]) int [source]¶
Replace all nodes matching pattern with replacement.
- Parameters:
tree – Root node of tree
pattern – Pattern to match
replacement – Node or function to generate replacement
- Returns:
Number of replacements made
- AlgoTree.pattern_matcher.dotcount(tree: Node, dot_path: str) int [source]¶
Count nodes matching a path pattern.
- Parameters:
tree – Tree to count in
dot_path – Dot notation path pattern
- Returns:
Number of matching nodes
- AlgoTree.pattern_matcher.dotexists(tree: Node, dot_path: str) bool [source]¶
Check if a path exists in the tree.
Inspired by dotsuite’s dotexists from the Truth pillar.
- Parameters:
tree – Tree to check
dot_path – Dot notation path
- Returns:
True if path exists, False otherwise
- AlgoTree.pattern_matcher.dotfilter(tree: Node, filter_expr: str) List[Node] [source]¶
Filter tree nodes using advanced expressions.
Supports: - Comparison operators: >, <, >=, <=, ==, != - Logical operators: and, or, not - Path expressions: @.property - Functions: contains(), startswith(), endswith()
- Parameters:
tree – Tree to filter
filter_expr – Filter expression
- Returns:
List of matching nodes
Examples
# Size greater than 100 dotfilter(tree, “@.size > 100”)
# Name contains “test” and has children dotfilter(tree, “contains(@.name, ‘test’) and @.children.length > 0”)
- AlgoTree.pattern_matcher.dotmatch(tree: Node, dot_path: str, return_paths: bool = False) List[Node] | List[str] [source]¶
Match nodes using dot notation paths, inspired by dotsuite.
This provides a clean, intuitive way to navigate and match tree paths using dot notation similar to JSONPath or object property access.
- Parameters:
tree – Tree to search
dot_path – Dot notation path (e.g., “root.branch.*.leaf”, “app.**.test”)
return_paths – If True, return dot paths to matches instead of nodes
- Returns:
List of matching nodes or their dot paths
Examples
# Find all test files dotmatch(tree, “src.**.test_*”)
# Find specific path dotmatch(tree, “app.models.user”)
# Find with wildcards dotmatch(tree, “data.*.value”)
# Get paths instead of nodes paths = dotmatch(tree, “**.config”, return_paths=True) # Returns: [“app.config”, “modules.auth.config”, …]
- AlgoTree.pattern_matcher.dotpluck(tree: Node, *dot_paths: str) List[Any] [source]¶
Extract values from tree using dot notation paths.
Inspired by dotsuite’s dotpluck, this extracts payload values from nodes at specified paths.
- Parameters:
tree – Tree to extract from
*dot_paths – Variable number of dot notation paths
- Returns:
List of values (payload or None for missing paths)
Examples
# Extract multiple values values = dotpluck(tree, “user.name”, “user.age”, “user.email”)
# Extract with wildcards (returns all matching values) values = dotpluck(tree, “users.*.name”)
- AlgoTree.pattern_matcher.pattern_match(tree: Node, pattern: str | Dict | Pattern, match_type: MatchType = MatchType.PARTIAL) List[Node] [source]¶
Convenience function to find all matches of a pattern in a tree.
- Parameters:
tree – Tree to search
pattern – Pattern as string, dict, or Pattern object
match_type – Type of matching
- Returns:
List of matching nodes
AlgoTree.pretty_tree module¶
- class AlgoTree.pretty_tree.PrettyTree(style: ~typing.Dict[str, str] | None = None, node_name: ~typing.Callable[[~typing.Any], str] = <function PrettyTree.<lambda>>, indent: int = 7, mark: ~typing.List[str] | None = None, node_details: ~typing.Callable[[~typing.Any], ~typing.Any] | None = None)[source]¶
Bases:
object
A class to print a tree in a more readable way.
- default_style = {'child_connector': '├', 'horizontal': '─', 'last_child_connector': '└', 'markers': ['🔵', '🔴', '🟢', '🟣', '🟠', '🟡', '🟤', '⚫', '⚪', '⭕', '🔘'], 'payload_connector': '◄', 'spacer': ' ', 'vertical': '│'}¶
AlgoTree.serialization module¶
Serialization for AlgoTree - Modern Pythonic Approach.
Philosophy: - JSON is the native format (human-readable, universal) - Trees are naturally hierarchical, so nested JSON is default - Support other formats only when there’s a clear use case - Don’t reinvent the wheel - use standard libraries
The Node class already provides to_dict() and from_dict() methods that work seamlessly with Python’s json module. This module adds: - Convenience functions for file I/O - Optional compression - Streaming for large trees - Integration with modern data formats (Parquet for analytics)
- AlgoTree.serialization.dumps(tree: Node, **json_kwargs) str [source]¶
Serialize tree to JSON string.
- Parameters:
tree – Tree to serialize
**json_kwargs – Arguments passed to json.dumps (indent, sort_keys, etc.)
- Returns:
JSON string
Example
json_str = dumps(tree, indent=2, sort_keys=True)
- AlgoTree.serialization.from_parquet(path: str | Path) Node [source]¶
Load tree from Parquet format.
Reconstructs tree structure from tabular data.
- Parameters:
path – Parquet file path
- Returns:
Root node of tree
- AlgoTree.serialization.from_pickle(data: bytes) Node [source]¶
Deserialize tree from pickle.
- Parameters:
data – Pickled bytes
- Returns:
Tree root node
- AlgoTree.serialization.iter_nodes(path: str | Path) Iterator[Dict[str, Any]] [source]¶
Iterate over nodes in a JSON file without loading entire tree.
Useful for processing large trees.
- Parameters:
path – Path to JSON file
- Yields:
Node dictionaries
Example
- for node_data in iter_nodes(“large_tree.json”):
- if node_data.get(“type”) == “file”:
process_file(node_data)
- AlgoTree.serialization.load(path: str | Path) Node [source]¶
Load tree from JSON file.
Automatically handles gzip compression if file ends with .gz
- Parameters:
path – File path
- Returns:
Root node of loaded tree
Example
tree = load(“my_tree.json”) tree = load(“my_tree.json.gz”) # Auto-detects compression
- AlgoTree.serialization.loads(json_str: str) Node [source]¶
Deserialize tree from JSON string.
- Parameters:
json_str – JSON string
- Returns:
Root node of tree
Example
tree = loads(‘{“name”: “root”, “children”: […]}’)
- AlgoTree.serialization.register_json_encoder()[source]¶
Register Node class with json module for seamless serialization.
- After calling this, you can use json.dumps directly on Node objects:
register_json_encoder() json.dumps(tree) # Works without calling to_dict()
- AlgoTree.serialization.save(tree: Node, path: str | Path, compress: bool = False) None [source]¶
Save tree to JSON file.
This is the recommended way to persist trees. Uses the natural hierarchical JSON representation.
- Parameters:
tree – Tree to save
path – File path (can be string or Path object)
compress – If True, use gzip compression
Example
save(tree, “my_tree.json”) save(tree, “my_tree.json.gz”, compress=True)
- AlgoTree.serialization.stream_writer(path: str | Path, compress: bool = False)[source]¶
Context manager for streaming tree writes.
Useful for very large trees that shouldn’t be held entirely in memory.
Example
- with stream_writer(“large_tree.json”) as writer:
writer.write_node(root) for subtree in generate_subtrees():
writer.write_subtree(subtree)
- AlgoTree.serialization.to_parquet(tree: Node, path: str | Path, include_path: bool = True) None [source]¶
Export tree to Parquet format for analytics.
Parquet is columnar format excellent for analytical queries. Each node becomes a row with its attributes as columns.
- Parameters:
tree – Tree to export
path – Output file path
include_path – Include full path from root as column
Example
to_parquet(tree, “tree_data.parquet”) # Then analyze with pandas, Spark, DuckDB, etc. df = pd.read_parquet(“tree_data.parquet”) df[df[‘type’] == ‘file’].groupby(‘extension’).size()
AlgoTree.tree_converter module¶
- class AlgoTree.tree_converter.TreeConverter[source]¶
Bases:
object
Utility class for converting between tree representations.
- static convert(source: ~typing.Any, target_type: ~typing.Type, node_name: ~typing.Callable[[~typing.Any], str] = <staticmethod(<function TreeConverter.default_node_name>)>, extract: ~typing.Callable[[~typing.Any], ~typing.Dict[str, ~typing.Any] | None] = <staticmethod(<function TreeConverter.default_extract>)>) Any [source]¶
Convert a tree rooted at node to a target tree type representation.
- Parameters:
src_node – The root node of the tree to convert.
target_type – The target tree type to convert to.
node_name – The function to map nodes to unique keys.
extract – A callable to extract relevant data from a node.
- Returns:
The converted tree.
- static copy_under(node: ~typing.Any, under: ~typing.Any, node_name: ~typing.Callable[[~typing.Any], str] = <staticmethod(<function TreeConverter.default_node_name>)>, extract: ~typing.Callable[[~typing.Any], ~typing.Dict[str, ~typing.Any] | None] = <staticmethod(<function TreeConverter.default_extract>)>, max_tries: int = 1000) Any [source]¶
Copy the subtree rooted at node as a child of under, where the copy takes on the node type of under. It returns the subtree that contains under with current node at under.
- Parameters:
node – The subtree rooted at node to copy.
under – The node to copy the subtree under.
node_name – The function to map nodes to names.
extract – A callable to extract relevant payload from a node.
max_tries – The maximum number of tries to generate a unique name if a name conflict occurs.
- Returns:
A subtree extending under with the copied nodes.
- static default_extract(node: Any) Dict[str, Any] | None [source]¶
Default extractor of relevant payload from a node.
- Parameters:
node – The node to extract payload data from.
- Returns:
The extracted data.
- static default_node_name(node: Any) str [source]¶
Default function to map nodes to unique keys. If the node has a name attribute, then it is used as the unique key. Otherwise, a random UUID is generated.
- Parameters:
node – The node to map to a unique key.
- Returns:
The unique key for the node.
- static to_dict(node, node_name: ~typing.Callable = <staticmethod(<function TreeConverter.default_node_name>)>, extract: ~typing.Callable = <staticmethod(<function TreeConverter.default_extract>)>, **kwargs) Dict [source]¶
Convert the subtree rooted at node to a dictionary.
- Parameters:
node – The root node of the subtree to convert.
node_name – The function to map nodes to unique keys.
extract – A callable to extract relevant data from a node.
- Returns:
A dictionary representation of the subtree.
AlgoTree.tree_hasher module¶
- class AlgoTree.tree_hasher.TreeHasher(hash_fn: Callable[[Any], int] | None = None)[source]¶
Bases:
object
A class that provides various hash functions for trees, with a default hashing strategy.
AlgoTree.tree_shaper module¶
Tree shaping functionality for open transformations.
This module provides reshaping capabilities for transforming trees into arbitrary structures (open transformations), inspired by dotsuite’s Shape pillar.
- AlgoTree.tree_shaper.dotcollect(tree: Node, collector: Callable[[Node, Any], Any], initial: Any = None, dot_path: str = '**') Any [source]¶
Collect data from tree using a collector function.
Similar to reduce but more focused on building collections.
- Parameters:
tree – Tree to collect from
collector – Function (node, accumulator) -> new_accumulator
initial – Initial accumulator value
dot_path – Pattern to match nodes
- Returns:
Final collected value
Examples
# Collect into a dict by type by_type = dotcollect(tree,
- lambda n, acc: {
**acc, n.payload.get(“type”, “unknown”):
acc.get(n.payload.get(“type”, “unknown”), []) + [n.name]
}, initial={})
# Collect statistics stats = dotcollect(tree,
- lambda n, acc: {
“count”: acc[“count”] + 1, “total_size”: acc[“total_size”] + n.payload.get(“size”, 0), “max_depth”: max(acc[“max_depth”], n.level)
}, initial={“count”: 0, “total_size”: 0, “max_depth”: 0})
- AlgoTree.tree_shaper.dotextract(tree: Node, extractor: Callable[[Node], Any], dot_path: str = '**', flatten: bool = True) List[Any] | Dict[str, Any] [source]¶
Extract data from tree nodes using custom extractor.
- Parameters:
tree – Tree to extract from
extractor – Function to extract data from each node
dot_path – Pattern to match nodes
flatten – If True, return flat list; if False, preserve structure
- Returns:
Extracted data as list or structured dict
Examples
# Extract all sizes sizes = dotextract(tree, lambda n: n.payload.get(“size”))
# Extract node info for files files = dotextract(tree,
lambda n: {“name”: n.name, “size”: n.payload[“size”]}, dot_path=”**[type=file]”)
- AlgoTree.tree_shaper.dotgroup(tree: Node, grouper: str | Callable[[Node], Any], dot_path: str = '**') Dict[Any, List[Node]] [source]¶
Group tree nodes by a key.
- Parameters:
tree – Tree to group nodes from
grouper – Either: - String: payload key to group by - Callable: function to compute group key
dot_path – Pattern to match nodes
- Returns:
Dictionary mapping group keys to lists of nodes
Examples
# Group by type by_type = dotgroup(tree, “type”)
# Group by custom function by_level = dotgroup(tree, lambda n: n.level)
# Group files by extension by_ext = dotgroup(tree,
lambda n: n.name.split(“.”)[-1] if “.” in n.name else “no_ext”, dot_path=”**[type=file]”)
- AlgoTree.tree_shaper.dotpartition(tree: Node, predicate: Callable[[Node], bool], dot_path: str = '**') Tuple[List[Node], List[Node]] [source]¶
Partition nodes into two groups based on predicate.
- Parameters:
tree – Tree to partition
predicate – Function returning True for first group, False for second
dot_path – Pattern to match nodes
- Returns:
Tuple of (matching_nodes, non_matching_nodes)
Examples
# Partition by size large, small = dotpartition(tree, lambda n: n.payload.get(“size”, 0) > 1000)
# Partition enabled/disabled enabled, disabled = dotpartition(tree,
lambda n: n.payload.get(“enabled”, False), dot_path=”app.modules.*”)
- AlgoTree.tree_shaper.dotpipe(tree: Node, *transformers: Callable | Tuple[str, Callable]) Any [source]¶
Pipe tree through a series of transformations.
This is the main function for open transformations - converting trees to any structure through a pipeline of operations.
- Parameters:
tree – Tree to transform
*transformers – Variable number of transformers, each can be: - Callable: Applied to entire result of previous stage - Tuple[str, Callable]: (dot_path, transformer) applies to matched nodes
- Returns:
Result of the final transformation (can be any type)
Examples
# Extract all names as a list names = dotpipe(tree,
lambda t: [n.name for n in t.traverse_preorder()])
# Pipeline of transformations result = dotpipe(tree,
(”**.config”, lambda n: n.payload), # Extract config payloads lambda configs: {c.get(“name”): c for c in configs}, # Dict by name lambda d: list(d.values())) # Back to list
# Convert tree to nested dict data = dotpipe(tree, to_dict)
# Extract and process specific data totals = dotpipe(tree,
(”**[type=file]”, lambda n: n.payload.get(“size”, 0)), sum) # Sum all sizes
- AlgoTree.tree_shaper.dotproject(tree: Node, projection: List[str] | Dict[str, str], dot_path: str = '**') List[Dict[str, Any]] [source]¶
Project specific fields from nodes (like SQL SELECT).
- Parameters:
tree – Tree to project from
projection – Either: - List of field names to include - Dict mapping field names to aliases
dot_path – Pattern to match nodes
- Returns:
List of projected dictionaries
Examples
# Select specific fields data = dotproject(tree, [“name”, “size”, “type”])
# With aliases data = dotproject(tree, {
“name”: “file_name”, “size”: “file_size”, “type”: “file_type”
})
- AlgoTree.tree_shaper.to_adjacency_list(node: Node) Dict[str, List[str]] [source]¶
Convert tree to adjacency list representation.
- Parameters:
node – Root node
- Returns:
Dictionary mapping node names to lists of child names
Examples
adj = to_adjacency_list(tree) # {“app”: [“config”, “database”], “config”: [], …}
- AlgoTree.tree_shaper.to_dict(node: Node, include_children: bool = True, include_parent: bool = False, key_mapper: Callable[[str], str] | None = None) Dict[str, Any] [source]¶
Convert tree node to dictionary representation.
- Parameters:
node – Node to convert
include_children – If True, recursively include children
include_parent – If True, include parent reference (careful: can be circular)
key_mapper – Optional function to transform keys
- Returns:
Dictionary representation of the node
Examples
# Simple conversion data = to_dict(tree)
# Without children (just this node) node_data = to_dict(tree, include_children=False)
# With key transformation data = to_dict(tree, key_mapper=str.upper)
- AlgoTree.tree_shaper.to_edge_list(node: Node, include_root: bool = False) List[Tuple[str, str]] [source]¶
Convert tree to edge list representation.
- Parameters:
node – Root node
include_root – If True, include edge from None to root
- Returns:
List of (parent, child) tuples
Examples
edges = to_edge_list(tree) # [(“app”, “config”), (“app”, “database”), …]
- AlgoTree.tree_shaper.to_graphviz_data(tree: Node) Dict[str, Any] [source]¶
Convert tree to GraphViz data structure.
Returns dict with ‘nodes’ and ‘edges’ suitable for visualization.
- AlgoTree.tree_shaper.to_json_schema(tree: Node, type_key: str = 'type', required_key: str = 'required') Dict[str, Any] [source]¶
Convert tree to JSON Schema-like structure.
Useful for representing configuration schemas or data models.
- AlgoTree.tree_shaper.to_list(node: Node, traverse_order: str = 'preorder', include_data: bool = True) List[str | Dict[str, Any]] [source]¶
Convert tree to flat list representation.
- Parameters:
node – Root node
traverse_order – Traversal order (“preorder”, “postorder”, “levelorder”)
include_data – If True, include full node data; if False, just names
- Returns:
List of nodes (as dicts or names)
Examples
# List of all node names names = to_list(tree, include_data=False)
# List of node data in level order nodes = to_list(tree, traverse_order=”levelorder”)
- AlgoTree.tree_shaper.to_nested_lists(node: Node) List [source]¶
Convert tree to nested list structure (like S-expressions).
- Parameters:
node – Root node
- Returns:
Nested list representation
Examples
nested = to_nested_lists(tree) # [“app”, [“config”], [“database”], [“modules”, [“auth”], [“api”]]]
- AlgoTree.tree_shaper.to_paths(node: Node, path_separator: str = '.', include_payload: bool = False) List[str] | Dict[str, Any] [source]¶
Convert tree to path representations.
- Parameters:
node – Root node
path_separator – Separator for path components
include_payload – If True, return dict mapping paths to payloads
- Returns:
List of paths or dict mapping paths to payloads
Examples
# List of all paths paths = to_paths(tree) # [“app”, “app.config”, “app.database”, …]
# Paths with payloads path_data = to_paths(tree, include_payload=True) # {“app”: {…}, “app.config”: {…}, …}
# Using different separator paths = to_paths(tree, path_separator=”/”) # [“app”, “app/config”, “app/database”, …]
- AlgoTree.tree_shaper.to_table(node: Node, columns: List[str] | None = None, include_path: bool = True) List[Dict[str, Any]] [source]¶
Convert tree to tabular/relational format.
- Parameters:
node – Root node
columns – Specific payload columns to include (None = all)
include_path – If True, include full path to node
- Returns:
List of row dictionaries suitable for DataFrame or CSV
Examples
# Convert to table format rows = to_table(tree, columns=[“type”, “size”, “enabled”])
# Can be used with pandas: # df = pd.DataFrame(rows)
AlgoTree.tree_transformer module¶
Tree transformation functionality.
This module provides transformation capabilities for tree structures, allowing users to modify trees while preserving their structure (closed transformations). Inspired by dotsuite’s Shape pillar.
- AlgoTree.tree_transformer.dotannotate(tree: Node, annotator: Callable[[Node], Dict[str, Any]] | Dict[str, Any], annotation_key: str = '_annotation', dot_path: str = '**', in_place: bool = False) Node [source]¶
Add annotations to nodes in the tree.
- Parameters:
tree – Tree to annotate
annotator – Either: - Function that returns annotation dict for each node - Static annotation dict to add to all matching nodes
annotation_key – Key to store annotations under in payload
dot_path – Pattern for nodes to annotate
in_place – If True, modify tree in place
- Returns:
Annotated tree
Examples
# Add computed annotations tree = dotannotate(tree,
- lambda n: {
“depth”: n.level, “has_children”: len(n.children) > 0, “path”: “.”.join(p.name for p in n.get_path())
})
# Add static annotations to specific nodes tree = dotannotate(tree,
{“reviewed”: True, “version”: “1.0”}, dot_path=”**.critical_*”)
- AlgoTree.tree_transformer.dotflatten(tree: Node, flatten_pattern: str = '**', max_depth: int | None = None) List[Node] [source]¶
Flatten tree structure into a list of nodes.
- Parameters:
tree – Tree to flatten
flatten_pattern – Pattern for nodes to include
max_depth – Maximum depth to flatten to
- Returns:
List of nodes (flattened)
Examples
# Get all nodes as flat list all_nodes = dotflatten(tree)
# Get only file nodes files = dotflatten(tree, “**[type=file]”)
# Flatten only top 3 levels top_nodes = dotflatten(tree, max_depth=3)
- AlgoTree.tree_transformer.dotgraft(tree: Node, graft_point: str, subtree: Node, position: int | str = 'append', in_place: bool = False) Node [source]¶
Graft a subtree onto a tree at specified point(s).
- Parameters:
tree – Tree to graft onto
graft_point – Dot path to graft point(s)
subtree – Subtree to graft
position – Where to add the subtree: - “append”: Add at end of children (default) - “prepend”: Add at beginning of children - int: Insert at specific index - “replace”: Replace existing children
in_place – If True, modify tree in place
- Returns:
Tree with grafted subtree
Examples
# Add new module to app new_module = Node(“auth”, type=”module”) tree = dotgraft(tree, “app.modules”, new_module)
# Insert at specific position tree = dotgraft(tree, “app.modules”, new_module, position=0)
# Replace children tree = dotgraft(tree, “app.old_modules”, new_modules, position=”replace”)
- AlgoTree.tree_transformer.dotmap(tree: Node, mapper: Callable[[Node], Dict[str, Any]] | Dict[str, Callable], dot_path: str = '**', in_place: bool = False) Node [source]¶
Map a transformation function over nodes matching a pattern.
This is a convenience function that applies the same transformation to all nodes matching a pattern.
- Parameters:
tree – Tree to transform
mapper – Either: - Function that takes a node and returns dict to update payload - Dict mapping payload keys to transformation functions
dot_path – Pattern to match nodes (default “**” for all nodes)
in_place – If True, modify tree in place
- Returns:
Transformed tree
Examples
# Double all sizes tree = dotmap(tree, lambda n: {“size”: n.payload.get(“size”, 0) * 2})
# Transform specific fields tree = dotmap(tree, {
“size”: lambda v: v * 2, “name”: lambda v: v.upper(), “timestamp”: lambda v: str(v)
})
# Apply only to specific nodes tree = dotmap(tree,
lambda n: {“processed”: True}, dot_path=”app.data.**”)
- AlgoTree.tree_transformer.dotmerge(tree1: Node, tree2: Node, merge_strategy: str = 'overlay', conflict_resolver: Callable[[Node, Node], Node] | None = None, in_place: bool = False) Node [source]¶
Merge two trees using various strategies.
- Parameters:
tree1 – First tree (base)
tree2 – Second tree (overlay)
merge_strategy – Strategy for merging: - “overlay”: tree2 values override tree1 - “underlay”: tree1 values take precedence - “combine”: merge payloads, keeping both values - “custom”: use conflict_resolver function
conflict_resolver – Function to resolve conflicts (for custom strategy)
in_place – If True, modify tree1 in place
- Returns:
Merged tree
Examples
# Simple overlay merge merged = dotmerge(tree1, tree2, “overlay”)
# Custom conflict resolution def resolver(node1, node2):
# Combine arrays, prefer tree2 for other values merged_payload = {} for key in set(node1.payload.keys()) | set(node2.payload.keys()):
- if key in node1.payload and key in node2.payload:
val1, val2 = node1.payload[key], node2.payload[key] if isinstance(val1, list) and isinstance(val2, list):
merged_payload[key] = val1 + val2
- else:
merged_payload[key] = val2
- elif key in node1.payload:
merged_payload[key] = node1.payload[key]
- else:
merged_payload[key] = node2.payload[key]
return Node(node2.name, **merged_payload)
merged = dotmerge(tree1, tree2, “custom”, conflict_resolver=resolver)
- AlgoTree.tree_transformer.dotmod(tree: Node, transformations: Dict[str, Any] | List[Tuple[str, Any]], in_place: bool = False) Node [source]¶
Apply closed tree-to-tree transformations using dot notation paths.
This function modifies nodes in the tree based on dot notation paths, preserving the tree structure (closed transformation).
- Parameters:
tree – Tree to transform
transformations – Either: - Dict mapping dot paths to transformations - List of (dot_path, transformation) tuples
in_place – If True, modify tree in place; otherwise create a copy
- Returns:
Transformed tree (same object if in_place=True, copy otherwise)
- Transformations can be:
Dict: Update node payload with dict contents
Callable: Apply function to node (receives node, returns dict to update payload)
String: Rename the node
None: Clear the payload (but keep the node)
Examples
# Update specific nodes tree = dotmod(tree, {
“app.config”: {“version”: “2.0”, “debug”: False}, “app.database”: {“host”: “localhost”, “port”: 5432}
})
# Rename nodes tree = dotmod(tree, {
“app.oldname”: “newname”
})
# Apply functions tree = dotmod(tree, {
“app.**.file”: lambda n: {“size”: n.payload.get(“size”, 0) * 2}
})
# Multiple transformations to same path pattern tree = dotmod(tree, [
(“app.**.test_*”, lambda n: {“tested”: True}), (“app.**.test_*”, lambda n: {“priority”: “high”})
])
- AlgoTree.tree_transformer.dotnormalize(tree: Node, normalizer: Callable[[str], str] | None = None, normalize_payload: bool = False, in_place: bool = False) Node [source]¶
Normalize node names and optionally payload keys.
- Parameters:
tree – Tree to normalize
normalizer – Function to normalize names (default: lowercase + underscore)
normalize_payload – If True, also normalize payload keys
in_place – If True, modify tree in place
- Returns:
Normalized tree
Examples
# Default normalization (lowercase, spaces to underscores) tree = dotnormalize(tree)
# Custom normalization tree = dotnormalize(tree,
normalizer=lambda s: s.lower().replace(“-”, “_”))
# Also normalize payload keys tree = dotnormalize(tree, normalize_payload=True)
- AlgoTree.tree_transformer.dotprune(tree: Node, condition: str | Callable[[Node], bool], keep_structure: bool = False, in_place: bool = False) Node [source]¶
Prune nodes from tree based on condition.
- Parameters:
tree – Tree to prune
condition – Either: - Dot path pattern of nodes to remove - Predicate function (returns True for nodes to remove)
keep_structure – If True, replace pruned nodes with empty placeholders
in_place – If True, modify tree in place
- Returns:
Pruned tree
Examples
# Remove all test files tree = dotprune(tree, “**.test_*”)
# Remove empty directories tree = dotprune(tree, lambda n: n.payload.get(“type”) == “dir” and len(n.children) == 0)
# Keep structure but clear nodes tree = dotprune(tree, “**.deprecated”, keep_structure=True)
- AlgoTree.tree_transformer.dotreduce(tree: Node, reducer: Callable[[Any, Node], Any], initial: Any = None, traverse_pattern: str = '**') Any [source]¶
Reduce tree to a single value using a reducer function.
- Parameters:
tree – Tree to reduce
reducer – Function (accumulator, node) -> new_accumulator
initial – Initial value for accumulator
traverse_pattern – Pattern for nodes to include in reduction
- Returns:
Reduced value
Examples
# Sum all sizes total_size = dotreduce(tree,
lambda acc, n: acc + n.payload.get(“size”, 0), initial=0)
# Collect all names names = dotreduce(tree,
lambda acc, n: acc + [n.name], initial=[])
# Find maximum depth max_depth = dotreduce(tree,
lambda acc, n: max(acc, n.level), initial=0)
- AlgoTree.tree_transformer.dotsplit(tree: Node, split_point: str, include_point: bool = True) Tuple[Node, List[Node]] [source]¶
Split tree at specified point(s), extracting subtrees.
- Parameters:
tree – Tree to split
split_point – Dot path to split point(s)
include_point – If True, include split point in extracted subtrees
- Returns:
Tuple of (modified tree, list of extracted subtrees)
Examples
# Extract all test modules tree, test_modules = dotsplit(tree, “**.tests”)
# Extract but keep the container node tree, extracted = dotsplit(tree, “app.deprecated”, include_point=False)
- AlgoTree.tree_transformer.dotvalidate(tree: Node, validator: Callable[[Node], bool] | Dict[str, Any], dot_path: str = '**', raise_on_invalid: bool = True) bool | List[Node] [source]¶
Validate nodes in the tree against criteria.
- Parameters:
tree – Tree to validate
validator – Either: - Predicate function returning True for valid nodes - Dict of required attributes and values
dot_path – Pattern for nodes to validate
raise_on_invalid – If True, raise exception on first invalid node
- Returns:
List of invalid nodes (empty if all valid) If raise_on_invalid=True: True if all valid (raises otherwise)
- Return type:
If raise_on_invalid=False
Examples
# Validate with function dotvalidate(tree,
lambda n: n.payload.get(“size”, 0) < 1000000, dot_path=”**[type=file]”)
# Validate required attributes dotvalidate(tree,
{“type”: “file”, “tested”: True}, dot_path=”app.src.**”)
# Get list of invalid nodes invalid = dotvalidate(tree,
lambda n: len(n.name) <= 255, raise_on_invalid=False)
AlgoTree.treenode module¶
- class AlgoTree.treenode.TreeNode(parent: TreeNode | None = None, name: str | None = None, payload: Any | None = None, *args, **kwargs)[source]¶
Bases:
dict
A tree node class. This class stores a nested representation of the tree. Each node is a TreeNode object, and if a node is a child of another node, it is stored in the parent node’s children attribute.
- add_child(name: str | None = None, payload: Any | None = None, *args, **kwargs) TreeNode [source]¶
Add a child node to the tree. Just invokes __init__. See __init__ for details.
- clone() TreeNode [source]¶
Clone the tree node (sub-tree) rooted at the current node.
- Returns:
A new TreeNode object with the same data as the current node.
- static from_dict(data: Dict) TreeNode [source]¶
Create a TreeNode from a dictionary.
- Parameters:
data – The dictionary to convert to a TreeNode.
- Returns:
A TreeNode object.
- static is_valid(data) bool [source]¶
Check if the given data is a valid TreeNode data.
- Parameters:
data – The data to check.
- Returns:
True if the data is a valid TreeNode, False otherwise.
- node(name: str) TreeNode [source]¶
Get the node with the given name in the current sub-tree. The sub-tree remains the same, we just change the current node position. If the name is not found, raise a KeyError.
- Parameters:
name – The name of the node.
- Returns:
The node with the given name.
- nodes() List[TreeNode] [source]¶
Get all the nodes in the current sub-tree.
- Returns:
A list of all the nodes in the current sub-tree.
- subtree(name: str) TreeNode [source]¶
Get the subtree rooted at the node with the given name. This is not a view, but a new tree rooted at the node with the given name. This is different from the node method, which just changes the current node position. It’s also different from the subtree method in the FlatForestNode class, which returns a view of the tree.
- Parameters:
name – The name of the node.
- Returns:
The subtree rooted at the node with the given name.
AlgoTree.treenode_api module¶
- class AlgoTree.treenode_api.TreeNodeApi[source]¶
Bases:
object
A class to check if a tree object models the concept of a tree node. The tree node concept is defined as follows:
children property
Represents a list of child nodes for the current node that can be accessed and modified.
parent property
Represents the parent node of the current node that can be accessed and modified.
Suppose we have the subtree G at node G:
B (root) ├── D └── E (parent) └── G (current node)
Then, G.parent should refer node E. G.root.parent should be None since root is the root node of subtree G and the root node has no parent. This is true even if subtree G is a subtree view of a larger tree.
If we set G.parent = D, then the tree structure changes to:
B (root) ├── D │ └── G (current node) └── E
This also changes the view of the sub-tree, since we changed the underlying tree structure. However, the same nodes are still accessible from the sub-tree.
If we had set G.parent = X where X is not in the subtree G, then we would have an invalid subtree view even if is is a well-defined operation on the underlying tree structure. It is undefined behavior to set a parent that is not in the subtree, but leave it up to each implementation to decide how to handle such cases.
node(name: str) -> NodeType method.
Returns a node in the current subtree that the current node belongs to. The returned node should be the node with the given name, if it exists. If the node does not exist, it should raise a KeyError.
The node-centric view of the returned node should be consistent with the view of the current node, i.e., if the current node belongs to a specific sub-tree rooted at some other node, the returned node should also belong to the same sub-tree (i.e., with the same root), just pointing to the new node, but it should be possible to use parent and children to go up and down the sub-tree to reach the same nodes. Any node that is an ancestor of the root of the sub-tree remains inaccessible.
Example: Suppose we have the sub-tree t rooted at A and the current node is B:
A (root) ├── B (current node) │ ├── D │ └── E | └── G └── C └── F
If we get node F, t.node(F), then the sub-tree t remains the same, but the current node is now F:
A (root) ├── B │ ├── D │ └── E | └── G └── C └── F (current node)
subtree(node: Optional[NodeType] = None) -> NodeType method.
Returns a view of another sub-tree rooted at node where node is contained in the original sub-tree view. If node is None, the method will return the sub-tree rooted at the current node.
subtree is a partial function over the the nodes in the sub-tree, which means it is only well-defined when node is a descendant of the root of the sub-tree. We do not specify how to deal with the case when this condition is not met, but one approach would be to raise an exception.
Example: Suppose we have the sub-tree t rooted at A and the current node is C:
A (root) ├── B │ ├── D │ └── E | └── G └── C (current node) └── F
The subtree t.subtree(B) returns a new subtree:
B (root, current node) ├── D └── E └── G
root property
An immutable property that represents the root node of the sub-tree.
Suppose we have the subtree G at node G:
B (root) ├── D └── E └── G (current node)
Then, G.root should refer node B.
payload property
Returns the payload of the current node. The payload is the data associated with the node but not with the structure of the tree, e.g., it does not include the parent or children of the node.
name property
Returns the name of the current node. The name is an identifier for the node within the tree. It is not necessarily unique, and nor is it necessarily even a meaningful identifier, e.g., a random UUID.
contains(name) -> bool method.
Returns True if the sub-tree contains a node with the given name, otherwise False.
- static check(node: Any, require_props: List[str] = ['name', 'root', 'children', 'parent', 'node', 'subtree', 'payload', 'contains']) Any [source]¶
- static is_valid(value: Any, require_props: List[str] = ['name', 'root', 'children', 'parent', 'node', 'subtree', 'payload', 'contains']) bool [source]¶
- static missing(node: Any, require_props: List[str] = ['name', 'root', 'children', 'parent', 'node', 'subtree', 'payload', 'contains']) List[str] [source]¶
- properties: List[str] = ['name', 'root', 'children', 'parent', 'node', 'subtree', 'payload', 'contains']¶
AlgoTree.utils module¶
- AlgoTree.utils.ancestors(node: Any) List[Any] [source]¶
Get the ancestors of a node.
We could have used the path function, but we want to show potentially more efficient use of the parent property. As a tree, each node has at most one parent, so we can traverse the tree by following the parent relationship without having to search for the path from the root to the node. If parent pointers are not available but children pointers are, we can use the path function. In our implementations of trees, we implement both parent and children pointers.
- Parameters:
node – The root node.
- Returns:
List of ancestor nodes.
- AlgoTree.utils.average_distance(node: Any) float [source]¶
Compute the average distance between all pairs of nodes in the subtree rooted at the current node.
- Parameters:
node – The node.
- Returns:
The average distance between all pairs of nodes.
- AlgoTree.utils.breadth_first(node: Any, func: Callable[[Any], bool], max_lvl: int | None = None, **kwargs) bool [source]¶
Traverse the tree in breadth-first order. The function func is called on each node and level. The function should have a side-effect you want to achieve, and if it returns True, the traversal will stop. The keyword arguments are passed to func.
If func returns True, the traversal will stop and the traversal will return True immediately. Otherwise, it will return False after traversing all nodes. This is useful if you want to find a node that satisfies a condition, and you want to stop the traversal as soon as you find it.
Requirement:
This function requires that the node has a children property that is iterable.
The function func should have the signature:
func(node: Any, **kwargs) -> bool
- Parameters:
node – The root node.
func – The function to call on each node and any additional keyword arguments. We augment kwargs with a level key, too, which specifies the level of the node in the tree.
max_lvl – The maximum number of levels to descend. If None, the traversal will continue until all nodes are visited or until func returns True.
kwargs – Additional keyword arguments to pass to func.
- Raises:
TypeError – If func is not callable.
AttributeError – If the node does not have a ‘children’.
- Returns:
None
- AlgoTree.utils.breadth_first_undirected(node: Any, max_hops: int | float = inf) List[Any] [source]¶
Traverse the tree in breadth-first order. It treats the tree as an undirected graph, where each node is connected to its parent and children.
- AlgoTree.utils.depth(node) int [source]¶
Get the depth of a node in its subtree view.
- Parameters:
node – The node.
- Returns:
The depth of the node.
- AlgoTree.utils.descendants(node: Any) List[Any] [source]¶
Get the descendants of a node.
- Parameters:
node – The root node.
- Returns:
List of descendant nodes.
- AlgoTree.utils.distance(node1: Any, node2: Any) int [source]¶
Find the distance between two nodes.
- Parameters:
node1 – The first node.
node2 – The second node.
- Returns:
The distance between the two nodes.
- AlgoTree.utils.find_node(node: Any, pred: Callable[[Any], bool], **kwargs) Any [source]¶
Find closest descendent node of node that satisfies a predicate (where distance is defined with respect to path length). Technically, an order defined by path length is a partial order, sine many desendents that satisfy the condition may be at the same distance from node. We leave it up to each implementation to define which among these nodes to return. Use find_nodes if you want to return all nodes that satisfy the condition (return all the nodes in the partial order).
The predicate function pred should return True if the node satisfies the condition. It can also accept any additional keyword arguments, which are passed to the predicate. Note that we also augment the keyword arguments with a level key, which specifies the level of the node in the tree, so you can use this information in your predicate function.
- Parameters:
pred – The predicate function which returns True if the node satisfies the condition.
kwargs – Additional keyword arguments to pass to pred.
- Returns:
The node that satisfies the predicate.
- AlgoTree.utils.find_nodes(node: Any, pred: Callable[[Any], bool], **kwargs) List[Any] [source]¶
Find nodes that satisfy a predicate.
- Parameters:
pred – The predicate function.
kwargs – Additional keyword arguments to pass to pred.
- Returns:
List of nodes that satisfy the predicate.
- AlgoTree.utils.find_path(source: Any, dest: Any, bidirectional: bool = False) List[Any] [source]¶
Find the path from a source node to a destination node.
- Parameters:
source – The source node.
dest – The destination node.
- Returns:
The path from the source node to the destination node.
- AlgoTree.utils.height(node) int [source]¶
Get the height of a subtree (containing the node node, but any other node in the subtree would return the same height)
- Parameters:
node – The subtree containing node.
- Returns:
The height of the subtree.
- AlgoTree.utils.is_internal(node) bool [source]¶
Check if a node is an internal node.
- Parameters:
node – The node to check.
- Returns:
True if the node is an internal node, False otherwise.
- AlgoTree.utils.is_isomorphic(node1: Any, node2: Any) bool [source]¶
Check if two (sub)trees are isomorphic. To check if two trees are isomorphic, just pass in the root nodes of the trees.
This is another kind of equivalence: two nodes are equivalent if they have the same substructure (extensic relations), but the names and payloads of the nodes (intrinsic relations) can be different.
We ignore the parents of the nodes in this comparison. If we also included the parents, this would be the same as calling is_isomorphic on the root nodes of the trees.
- Parameters:
node1 – The root node of the first tree.
node2 – The root node of the second tree.
- Returns:
True if the trees are isomorphic, False otherwise.
- AlgoTree.utils.is_leaf(node) bool [source]¶
Check if a node is a leaf node.
- Parameters:
node – The node to check.
- Returns:
True if the node is a leaf node, False otherwise.
- AlgoTree.utils.is_root(node) bool [source]¶
Check if a node is a root node.
- Parameters:
node – The node to check.
- Returns:
True if the node is a root node, False otherwise.
- AlgoTree.utils.lca(node1: Any, node2: Any, hash_fn: Callable[[Any], int] | None = None) Any [source]¶
Find the lowest common ancestor of two nodes.
- Parameters:
node1 – The first node.
node2 – The second node.
- Returns:
The lowest common ancestor of the two nodes.
- AlgoTree.utils.leaves(node: Any) List[Any] [source]¶
Get the leaves of a node.
- Parameters:
node – The root node.
- Returns:
List of leaf nodes.
- AlgoTree.utils.map(node: Any, func: Callable[[Any], Any], order: str = 'post', **kwargs) Any [source]¶
Map a function over the nodes in the tree rooted at node. It is a map operation over trees. In particular, the function func, of type:
func : Node -> Node,
is called on each node in pre or post order traversal. The function should return a new node. The tree rooted at node will be replaced (in-place) with the tree rooted at the new node. The order of traversal can be specified as ‘pre’ or ‘post’.
Requirement:
This function requires that the node has a children property that is iterable and assignable, e.g., node.children = [child1, child2, …].
- Parameters:
node – The root node to start the traversal.
func – The function to call on each node. The function should take a single argument, the node, and return a new node (or have some other side effect you want to achieve).
order – The order of traversal (pre or post).
kwargs – Additional keyword arguments to pass to func.
- Raises:
ValueError – If the order is not ‘pre’ or ‘post’.
TypeError – If func is not callable.
- Returns:
The modified node. If func returns a new node, the tree rooted at node will be replaced with the tree rooted at the new node.
- AlgoTree.utils.node_stats(node: ~typing.Any, node_name: ~typing.Callable[[~typing.Any], str] = <function <lambda>>, payload: ~typing.Callable[[~typing.Any], ~typing.Any] = <function <lambda>>) Dict[str, Any] [source]¶
Gather statistics about the current node and its subtree.
- Parameters:
node – The current node in the subtree.
node_name – A function that returns the name of a node. Defaults to returning the node’s name property.
payload – A function that returns the payload of a node. Defaults to returning the node’s payload property.
- Returns:
A dictionary containing the statistics.
- AlgoTree.utils.node_to_leaf_paths(node: Any) List[List[Any]] [source]¶
List all node-to-leaf paths in a tree. Each path is a list of nodes from the current node node to a leaf node.
Example: Suppose we have the following sub-tree structure for node A:
A ├── B │ ├── D │ └── E └── C └── F
Invoking node_to_leaf_paths(A) enumerates the following list of paths:
[[A, B, D], [A, B, E], [A, C, F]]
- Parameters:
node – The current node.
- Returns:
List of paths in the tree under the current node.
- AlgoTree.utils.path(node: Any) List[Any] [source]¶
Get the path from the root node to the given node.
- Parameters:
node – The node.
- Returns:
The path from the root node to the given node.
- AlgoTree.utils.paths_to_tree(paths: List[List[str]], type: Type, max_tries: int = 1000) Any [source]¶
Convert a list of paths to a tree structure. Each path is a list of nodes from the root to a leaf node. (A tree can be uniquely identified by this list of paths.)
Example: Suppose we have the following list of paths:
paths = [ ["A", "B", "D"], ["A", "B", "E"], ["A", "C", "F"] ]
We can convert this list of paths to a tree structure using the following code:
tree = paths_to_tree(paths, TreeNode)
This will create the following tree structure:
A ├── B │ ├── D │ └── E └── C └── F
For some tree-like data structures, it may be the case that the names of nodes must be unique. We can use the max_tries parameter to try to create a node with a unique name like the one provided by suffixing the name with an integer.
- Parameters:
paths – The list of paths.
type – The type of the tree node.
max_tries – The maximum number of tries to create a node with a unique name.
- AlgoTree.utils.prune(node: Any, pred: Callable[[Any], bool], **kwargs) Any [source]¶
Prune the tree rooted at node by removing nodes that satisfy a predicate. The predicate function should return True if the node should be pruned. It can also accept any additional keyword arguments, which are passed to the predicate.
- Parameters:
node – The root node.
pred – The predicate function which returns True if the node should be pruned.
kwargs – Additional keyword arguments to pass to pred.
- Returns:
The pruned tree.
- AlgoTree.utils.siblings(node: Any) List[Any] [source]¶
Get the siblings of a node.
- Parameters:
node – The node.
- Returns:
List of sibling nodes.
- AlgoTree.utils.size(node: Any) int [source]¶
Get the size of the subtree under the current node.
- Parameters:
node – The node.
- Returns:
The number of descendents of the node.
- AlgoTree.utils.subtree_centered_at(node: Any, max_hops: int) Any [source]¶
Get the subtree centered at a node within a certain number of hops from the node. We return a subtree rooted at some ancestor of the node, or the node itself, that contains all nodes within max_hops hops from the node.
- Parameters:
node – The node.
- Returns:
The subtree centered at the node.
- AlgoTree.utils.subtree_rooted_at(node: Any, max_lvl: int) Any [source]¶
Get the subtree rooted at a node whose descendents are within a certain number of hops it. We return a subtree rooted the node itself, that contains all nodes within max_hops hops from the node.
- Parameters:
node – The node.
- Returns:
The subtree centered at the node.
- AlgoTree.utils.visit(node: Any, func: Callable[[Any], bool], order: str = 'post', max_hops: int = inf, **kwargs) bool [source]¶
Visit the nodes in the tree rooted at node in a pre-order or post-order traversal. The procedure proc should have a side-effect you want to achieve, such as printing the node or mutating the node in some way.
If func returns True, the traversal will stop and the traversal will return True immediately. Otherwise, it will return False after traversing all nodes.
Requirement:
This function requires that the node has a children property that is iterable.
- Parameters:
node – The root node to start the traversal.
func – The function to call on each node. The function should take a single argument, the node. It should have some side-effect you want to achieve. See map if you want to return a new node to rewrite the sub-tree rooted at node.
max_hops – The maximum number of hops to traverse.
order – The order of traversal (pre, post, or level).
kwargs – Additional keyword arguments to pass to func.
- Raises:
ValueError – If the order is not valid.
TypeError – If func is not callable.
AttributeError – If the node does not have a ‘children’.
Module contents¶
- class AlgoTree.FluentNode(node: Node | List[Node])[source]¶
Bases:
object
Wrapper for Node that provides fluent API for tree operations.
Example
- result = (FluentNode(tree)
.filter(lambda n: n.level <= 2) .map(lambda n: n.payload.get(‘size’, 0)) .where(lambda n: n > 5) .to_list())
- children() FluentNode [source]¶
Get all children of current nodes.
- Returns:
New FluentNode with all children.
- descendants() FluentNode [source]¶
Get all descendants of current nodes.
- Returns:
New FluentNode with all descendants.
- each(action: Callable[[Node], None]) FluentNode [source]¶
Execute an action on each node.
- Parameters:
action – Function to execute on each node.
- Returns:
Self for method chaining.
- filter(predicate: Callable[[Node], bool]) FluentNode [source]¶
Filter nodes by predicate.
- Parameters:
predicate – Function that returns True for nodes to keep.
- Returns:
New FluentNode with filtered nodes.
- leaves() FluentNode [source]¶
Get all leaf nodes from current nodes.
- Returns:
New FluentNode with leaf nodes only.
- map(transform: Callable[[Node], Any]) FluentNode [source]¶
Transform each node’s payload.
- Parameters:
transform – Function to transform each node.
- Returns:
Self for method chaining.
- match(pattern: str | Pattern | dict) FluentNode [source]¶
Find nodes matching a pattern.
- Parameters:
pattern – Pattern to match (string, Pattern object, or dict)
- Returns:
New FluentNode with matching nodes.
- prune(predicate: Callable[[Node], bool]) FluentNode [source]¶
Remove nodes matching predicate.
- Parameters:
predicate – Function that returns True for nodes to remove.
- Returns:
Self for method chaining.
- replace_matches(pattern: str | Pattern | dict, replacement: Node | Callable[[Node], Node]) FluentNode [source]¶
Replace nodes matching a pattern.
- Parameters:
pattern – Pattern to match
replacement – Node or function to generate replacement
- Returns:
Self for method chaining.
- sort(key: Callable[[Node], Any] | None = None, reverse: bool = False) FluentNode [source]¶
Sort children of each node.
- Parameters:
key – Function to extract sort key from each node.
reverse – Whether to sort in reverse order.
- Returns:
Self for method chaining.
- to_dict() dict | List[dict] [source]¶
Convert to dictionary representation.
- Returns:
Dictionary or list of dictionaries.
- where(predicate: Callable[[Node], bool]) FluentNode [source]¶
Filter current nodes by predicate (alias for filter on current set).
- Parameters:
predicate – Function that returns True for nodes to keep.
- Returns:
New FluentNode with filtered nodes.
- class AlgoTree.MatchType(*values)[source]¶
Bases:
Enum
Types of pattern matching.
- EXACT = 'exact'¶
- PARTIAL = 'partial'¶
- WILDCARD = 'wildcard'¶
- class AlgoTree.Node(name: str | None = None, parent: Node | None = None, **payload)[source]¶
Bases:
object
A tree node with proper attributes instead of dict inheritance.
This class represents a single node in a tree structure with: - A unique name/identifier - Optional parent reference - List of children - Arbitrary payload data
- add_child(name: str | None = None, **payload) Node [source]¶
Add a child node.
- Parameters:
name – Name for the child node.
**payload – Data for the child node.
- Returns:
The newly created child node.
- find(predicate: Callable[[Node], bool]) Node | None [source]¶
Find first node matching predicate.
- Parameters:
predicate – Function that returns True for matching nodes.
- Returns:
First matching node or None.
- find_all(predicate: Callable[[Node], bool]) List[Node] [source]¶
Find all nodes matching predicate.
- Parameters:
predicate – Function that returns True for matching nodes.
- Returns:
List of matching nodes.
- classmethod from_dict(data: Dict[str, Any], parent: Node | None = None) Node [source]¶
Create tree from nested dictionary representation.
- Parameters:
data – Dictionary with node data and optional ‘children’ key.
parent – Parent node for the created tree.
- Returns:
Root node of created tree.
- property is_leaf: bool¶
Check if this is a leaf node.
- property is_root: bool¶
Check if this is a root node.
- property level: int¶
Get the level (depth) of this node in the tree.
- class AlgoTree.Pattern(name: str | None = None, attributes: ~typing.Dict[str, ~typing.Any] = <factory>, children: ~typing.List[~AlgoTree.pattern_matcher.Pattern] = <factory>, is_wildcard: bool = False, is_deep_wildcard: bool = False, min_children: int | None = None, max_children: int | None = None, predicate: ~typing.Callable[[~AlgoTree.node.Node], bool] | None = None)[source]¶
Bases:
object
Represents a tree pattern to match against.
Patterns can include: - Exact node matches - Wildcards (*) that match any single node - Deep wildcards (**) that match any subtree - Attribute constraints
- attributes: Dict[str, Any]¶
- static from_dict(pattern_dict: Dict[str, Any]) Pattern [source]¶
Create a pattern from dictionary representation.
Example
- {
“name”: “parent”, “attributes”: {“type”: “container”}, “children”: [
{“name”: “child1”}, {“name”: “*”} # Wildcard child
]
}
- static from_string(pattern_str: str) Pattern [source]¶
Parse a pattern from string notation.
Examples
“root” # Match node named ‘root’ “*” # Match any single node “**” # Match any subtree “node[type=foo]” # Match node with attribute “parent(child1, child2)” # Match parent with specific children “root.branch.leaf” # Dot notation path “app.*.test” # Dot notation with wildcard “root.**.target” # Dot notation with deep wildcard
- is_deep_wildcard: bool = False¶
- is_wildcard: bool = False¶
- max_children: int | None = None¶
- min_children: int | None = None¶
- name: str | None = None¶
- class AlgoTree.PatternMatcher(match_type: MatchType = MatchType.PARTIAL)[source]¶
Bases:
object
Matches patterns against tree structures.
- find_all(tree: Node, pattern: Pattern) List[Node] [source]¶
Find all nodes in tree that match the pattern.
- Parameters:
tree – Root node of tree to search
pattern – Pattern to match
- Returns:
List of nodes that match the pattern
- find_first(tree: Node, pattern: Pattern) Node | None [source]¶
Find first node that matches the pattern.
- Parameters:
tree – Root node of tree to search
pattern – Pattern to match
- Returns:
First matching node or None
- match(node: Node, pattern: Pattern) bool [source]¶
Check if a node matches a pattern.
- Parameters:
node – Node to match against
pattern – Pattern to match
- Returns:
True if node matches pattern
- replace(tree: Node, pattern: Pattern, replacement: Node | Callable[[Node], Node]) int [source]¶
Replace all nodes matching pattern with replacement.
- Parameters:
tree – Root node of tree
pattern – Pattern to match
replacement – Node or function to generate replacement
- Returns:
Number of replacements made
- class AlgoTree.PrettyTree(style: ~typing.Dict[str, str] | None = None, node_name: ~typing.Callable[[~typing.Any], str] = <function PrettyTree.<lambda>>, indent: int = 7, mark: ~typing.List[str] | None = None, node_details: ~typing.Callable[[~typing.Any], ~typing.Any] | None = None)[source]¶
Bases:
object
A class to print a tree in a more readable way.
- default_style = {'child_connector': '├', 'horizontal': '─', 'last_child_connector': '└', 'markers': ['🔵', '🔴', '🟢', '🟣', '🟠', '🟡', '🟤', '⚫', '⚪', '⭕', '🔘'], 'payload_connector': '◄', 'spacer': ' ', 'vertical': '│'}¶
- class AlgoTree.TreeBuilder[source]¶
Bases:
object
Fluent API for building trees with method chaining.
Example
- tree = (TreeBuilder()
.root(“company”, type=”corporation”) .child(“engineering”, head=”Alice”)
.child(“frontend”, team_size=5) .sibling(“backend”, team_size=8) .up()
.sibling(“sales”, head=”Bob”) .build())
- child(name: str, **payload) TreeBuilder [source]¶
Add a child to the current node and move to it.
- Parameters:
name – Name for the child node.
**payload – Data for the child node.
- Returns:
Self for method chaining.
- root(name: str, **payload) TreeBuilder [source]¶
Create the root node.
- Parameters:
name – Name for the root node.
**payload – Data for the root node.
- Returns:
Self for method chaining.
- sibling(name: str, **payload) TreeBuilder [source]¶
Add a sibling to the current node.
- Parameters:
name – Name for the sibling node.
**payload – Data for the sibling node.
- Returns:
Self for method chaining.
- to_root() TreeBuilder [source]¶
Move to the root node.
- Returns:
Self for method chaining.
- up(levels: int = 1) TreeBuilder [source]¶
Move up in the tree by specified levels.
- Parameters:
levels – Number of levels to move up. Default is 1.
- Returns:
Self for method chaining.
- class AlgoTree.TreeExporter[source]¶
Bases:
object
Base class for tree exporters.
- static to_ascii(node: Node, style: str = 'ascii') str [source]¶
Export tree to ASCII/Unicode art.
- Parameters:
node – Root node of tree
style – “ascii” for ASCII characters, “unicode” for box drawing
- Returns:
String representation of tree
- static to_dict(node: Node) Dict[str, Any] [source]¶
Export tree to dictionary (already implemented in Node).
- static to_graphviz(node: Node, name: str = 'Tree', node_attr: Callable[[Node], Dict[str, str]] | None = None, edge_attr: Callable[[Node, Node], Dict[str, str]] | None = None, graph_attr: Dict[str, str] | None = None) str [source]¶
Export tree to GraphViz DOT format.
- Parameters:
node – Root node of tree
name – Graph name
node_attr – Function to generate node attributes
edge_attr – Function to generate edge attributes
graph_attr – Graph-level attributes
- Returns:
DOT format string
Example
- dot = TreeExporter.to_graphviz(tree,
node_attr=lambda n: {“label”: f”{n.name}n{n.payload.get(‘size’, ‘’)}”})
- static to_html(node: Node, include_styles: bool = True, collapsible: bool = True) str [source]¶
Export tree to interactive HTML.
- Parameters:
node – Root node of tree
include_styles – Include CSS styles
collapsible – Make tree nodes collapsible
- Returns:
HTML string representation
- static to_mermaid(node: Node, direction: str = 'TD', node_shape: str = 'round', node_text: Callable[[Node], str] | None = None) str [source]¶
Export tree to Mermaid diagram format.
- Parameters:
node – Root node of tree
direction – Graph direction (TD, TB, BT, RL, LR)
node_shape – Shape style (“round”, “square”, “circle”, “rhombus”, “stadium”)
node_text – Function to generate node text
- Returns:
Mermaid format string
Example
- mermaid = TreeExporter.to_mermaid(tree,
node_text=lambda n: f”{n.name}<br/>{n.payload.get(‘type’, ‘’)}”)
- static to_unicode(node: Node) str [source]¶
Export tree to Unicode box drawing (alias for to_ascii with unicode style).
- AlgoTree.dotannotate(tree: Node, annotator: Callable[[Node], Dict[str, Any]] | Dict[str, Any], annotation_key: str = '_annotation', dot_path: str = '**', in_place: bool = False) Node [source]¶
Add annotations to nodes in the tree.
- Parameters:
tree – Tree to annotate
annotator – Either: - Function that returns annotation dict for each node - Static annotation dict to add to all matching nodes
annotation_key – Key to store annotations under in payload
dot_path – Pattern for nodes to annotate
in_place – If True, modify tree in place
- Returns:
Annotated tree
Examples
# Add computed annotations tree = dotannotate(tree,
- lambda n: {
“depth”: n.level, “has_children”: len(n.children) > 0, “path”: “.”.join(p.name for p in n.get_path())
})
# Add static annotations to specific nodes tree = dotannotate(tree,
{“reviewed”: True, “version”: “1.0”}, dot_path=”**.critical_*”)
- AlgoTree.dotcollect(tree: Node, collector: Callable[[Node, Any], Any], initial: Any = None, dot_path: str = '**') Any [source]¶
Collect data from tree using a collector function.
Similar to reduce but more focused on building collections.
- Parameters:
tree – Tree to collect from
collector – Function (node, accumulator) -> new_accumulator
initial – Initial accumulator value
dot_path – Pattern to match nodes
- Returns:
Final collected value
Examples
# Collect into a dict by type by_type = dotcollect(tree,
- lambda n, acc: {
**acc, n.payload.get(“type”, “unknown”):
acc.get(n.payload.get(“type”, “unknown”), []) + [n.name]
}, initial={})
# Collect statistics stats = dotcollect(tree,
- lambda n, acc: {
“count”: acc[“count”] + 1, “total_size”: acc[“total_size”] + n.payload.get(“size”, 0), “max_depth”: max(acc[“max_depth”], n.level)
}, initial={“count”: 0, “total_size”: 0, “max_depth”: 0})
- AlgoTree.dotcount(tree: Node, dot_path: str) int [source]¶
Count nodes matching a path pattern.
- Parameters:
tree – Tree to count in
dot_path – Dot notation path pattern
- Returns:
Number of matching nodes
- AlgoTree.dotexists(tree: Node, dot_path: str) bool [source]¶
Check if a path exists in the tree.
Inspired by dotsuite’s dotexists from the Truth pillar.
- Parameters:
tree – Tree to check
dot_path – Dot notation path
- Returns:
True if path exists, False otherwise
- AlgoTree.dotextract(tree: Node, extractor: Callable[[Node], Any], dot_path: str = '**', flatten: bool = True) List[Any] | Dict[str, Any] [source]¶
Extract data from tree nodes using custom extractor.
- Parameters:
tree – Tree to extract from
extractor – Function to extract data from each node
dot_path – Pattern to match nodes
flatten – If True, return flat list; if False, preserve structure
- Returns:
Extracted data as list or structured dict
Examples
# Extract all sizes sizes = dotextract(tree, lambda n: n.payload.get(“size”))
# Extract node info for files files = dotextract(tree,
lambda n: {“name”: n.name, “size”: n.payload[“size”]}, dot_path=”**[type=file]”)
- AlgoTree.dotfilter(tree: Node, filter_expr: str) List[Node] [source]¶
Filter tree nodes using advanced expressions.
Supports: - Comparison operators: >, <, >=, <=, ==, != - Logical operators: and, or, not - Path expressions: @.property - Functions: contains(), startswith(), endswith()
- Parameters:
tree – Tree to filter
filter_expr – Filter expression
- Returns:
List of matching nodes
Examples
# Size greater than 100 dotfilter(tree, “@.size > 100”)
# Name contains “test” and has children dotfilter(tree, “contains(@.name, ‘test’) and @.children.length > 0”)
- AlgoTree.dotflatten(tree: Node, flatten_pattern: str = '**', max_depth: int | None = None) List[Node] [source]¶
Flatten tree structure into a list of nodes.
- Parameters:
tree – Tree to flatten
flatten_pattern – Pattern for nodes to include
max_depth – Maximum depth to flatten to
- Returns:
List of nodes (flattened)
Examples
# Get all nodes as flat list all_nodes = dotflatten(tree)
# Get only file nodes files = dotflatten(tree, “**[type=file]”)
# Flatten only top 3 levels top_nodes = dotflatten(tree, max_depth=3)
- AlgoTree.dotgraft(tree: Node, graft_point: str, subtree: Node, position: int | str = 'append', in_place: bool = False) Node [source]¶
Graft a subtree onto a tree at specified point(s).
- Parameters:
tree – Tree to graft onto
graft_point – Dot path to graft point(s)
subtree – Subtree to graft
position – Where to add the subtree: - “append”: Add at end of children (default) - “prepend”: Add at beginning of children - int: Insert at specific index - “replace”: Replace existing children
in_place – If True, modify tree in place
- Returns:
Tree with grafted subtree
Examples
# Add new module to app new_module = Node(“auth”, type=”module”) tree = dotgraft(tree, “app.modules”, new_module)
# Insert at specific position tree = dotgraft(tree, “app.modules”, new_module, position=0)
# Replace children tree = dotgraft(tree, “app.old_modules”, new_modules, position=”replace”)
- AlgoTree.dotgroup(tree: Node, grouper: str | Callable[[Node], Any], dot_path: str = '**') Dict[Any, List[Node]] [source]¶
Group tree nodes by a key.
- Parameters:
tree – Tree to group nodes from
grouper – Either: - String: payload key to group by - Callable: function to compute group key
dot_path – Pattern to match nodes
- Returns:
Dictionary mapping group keys to lists of nodes
Examples
# Group by type by_type = dotgroup(tree, “type”)
# Group by custom function by_level = dotgroup(tree, lambda n: n.level)
# Group files by extension by_ext = dotgroup(tree,
lambda n: n.name.split(“.”)[-1] if “.” in n.name else “no_ext”, dot_path=”**[type=file]”)
- AlgoTree.dotmap(tree: Node, mapper: Callable[[Node], Dict[str, Any]] | Dict[str, Callable], dot_path: str = '**', in_place: bool = False) Node [source]¶
Map a transformation function over nodes matching a pattern.
This is a convenience function that applies the same transformation to all nodes matching a pattern.
- Parameters:
tree – Tree to transform
mapper – Either: - Function that takes a node and returns dict to update payload - Dict mapping payload keys to transformation functions
dot_path – Pattern to match nodes (default “**” for all nodes)
in_place – If True, modify tree in place
- Returns:
Transformed tree
Examples
# Double all sizes tree = dotmap(tree, lambda n: {“size”: n.payload.get(“size”, 0) * 2})
# Transform specific fields tree = dotmap(tree, {
“size”: lambda v: v * 2, “name”: lambda v: v.upper(), “timestamp”: lambda v: str(v)
})
# Apply only to specific nodes tree = dotmap(tree,
lambda n: {“processed”: True}, dot_path=”app.data.**”)
- AlgoTree.dotmatch(tree: Node, dot_path: str, return_paths: bool = False) List[Node] | List[str] [source]¶
Match nodes using dot notation paths, inspired by dotsuite.
This provides a clean, intuitive way to navigate and match tree paths using dot notation similar to JSONPath or object property access.
- Parameters:
tree – Tree to search
dot_path – Dot notation path (e.g., “root.branch.*.leaf”, “app.**.test”)
return_paths – If True, return dot paths to matches instead of nodes
- Returns:
List of matching nodes or their dot paths
Examples
# Find all test files dotmatch(tree, “src.**.test_*”)
# Find specific path dotmatch(tree, “app.models.user”)
# Find with wildcards dotmatch(tree, “data.*.value”)
# Get paths instead of nodes paths = dotmatch(tree, “**.config”, return_paths=True) # Returns: [“app.config”, “modules.auth.config”, …]
- AlgoTree.dotmerge(tree1: Node, tree2: Node, merge_strategy: str = 'overlay', conflict_resolver: Callable[[Node, Node], Node] | None = None, in_place: bool = False) Node [source]¶
Merge two trees using various strategies.
- Parameters:
tree1 – First tree (base)
tree2 – Second tree (overlay)
merge_strategy – Strategy for merging: - “overlay”: tree2 values override tree1 - “underlay”: tree1 values take precedence - “combine”: merge payloads, keeping both values - “custom”: use conflict_resolver function
conflict_resolver – Function to resolve conflicts (for custom strategy)
in_place – If True, modify tree1 in place
- Returns:
Merged tree
Examples
# Simple overlay merge merged = dotmerge(tree1, tree2, “overlay”)
# Custom conflict resolution def resolver(node1, node2):
# Combine arrays, prefer tree2 for other values merged_payload = {} for key in set(node1.payload.keys()) | set(node2.payload.keys()):
- if key in node1.payload and key in node2.payload:
val1, val2 = node1.payload[key], node2.payload[key] if isinstance(val1, list) and isinstance(val2, list):
merged_payload[key] = val1 + val2
- else:
merged_payload[key] = val2
- elif key in node1.payload:
merged_payload[key] = node1.payload[key]
- else:
merged_payload[key] = node2.payload[key]
return Node(node2.name, **merged_payload)
merged = dotmerge(tree1, tree2, “custom”, conflict_resolver=resolver)
- AlgoTree.dotmod(tree: Node, transformations: Dict[str, Any] | List[Tuple[str, Any]], in_place: bool = False) Node [source]¶
Apply closed tree-to-tree transformations using dot notation paths.
This function modifies nodes in the tree based on dot notation paths, preserving the tree structure (closed transformation).
- Parameters:
tree – Tree to transform
transformations – Either: - Dict mapping dot paths to transformations - List of (dot_path, transformation) tuples
in_place – If True, modify tree in place; otherwise create a copy
- Returns:
Transformed tree (same object if in_place=True, copy otherwise)
- Transformations can be:
Dict: Update node payload with dict contents
Callable: Apply function to node (receives node, returns dict to update payload)
String: Rename the node
None: Clear the payload (but keep the node)
Examples
# Update specific nodes tree = dotmod(tree, {
“app.config”: {“version”: “2.0”, “debug”: False}, “app.database”: {“host”: “localhost”, “port”: 5432}
})
# Rename nodes tree = dotmod(tree, {
“app.oldname”: “newname”
})
# Apply functions tree = dotmod(tree, {
“app.**.file”: lambda n: {“size”: n.payload.get(“size”, 0) * 2}
})
# Multiple transformations to same path pattern tree = dotmod(tree, [
(“app.**.test_*”, lambda n: {“tested”: True}), (“app.**.test_*”, lambda n: {“priority”: “high”})
])
- AlgoTree.dotnormalize(tree: Node, normalizer: Callable[[str], str] | None = None, normalize_payload: bool = False, in_place: bool = False) Node [source]¶
Normalize node names and optionally payload keys.
- Parameters:
tree – Tree to normalize
normalizer – Function to normalize names (default: lowercase + underscore)
normalize_payload – If True, also normalize payload keys
in_place – If True, modify tree in place
- Returns:
Normalized tree
Examples
# Default normalization (lowercase, spaces to underscores) tree = dotnormalize(tree)
# Custom normalization tree = dotnormalize(tree,
normalizer=lambda s: s.lower().replace(“-”, “_”))
# Also normalize payload keys tree = dotnormalize(tree, normalize_payload=True)
- AlgoTree.dotpartition(tree: Node, predicate: Callable[[Node], bool], dot_path: str = '**') Tuple[List[Node], List[Node]] [source]¶
Partition nodes into two groups based on predicate.
- Parameters:
tree – Tree to partition
predicate – Function returning True for first group, False for second
dot_path – Pattern to match nodes
- Returns:
Tuple of (matching_nodes, non_matching_nodes)
Examples
# Partition by size large, small = dotpartition(tree, lambda n: n.payload.get(“size”, 0) > 1000)
# Partition enabled/disabled enabled, disabled = dotpartition(tree,
lambda n: n.payload.get(“enabled”, False), dot_path=”app.modules.*”)
- AlgoTree.dotpipe(tree: Node, *transformers: Callable | Tuple[str, Callable]) Any [source]¶
Pipe tree through a series of transformations.
This is the main function for open transformations - converting trees to any structure through a pipeline of operations.
- Parameters:
tree – Tree to transform
*transformers – Variable number of transformers, each can be: - Callable: Applied to entire result of previous stage - Tuple[str, Callable]: (dot_path, transformer) applies to matched nodes
- Returns:
Result of the final transformation (can be any type)
Examples
# Extract all names as a list names = dotpipe(tree,
lambda t: [n.name for n in t.traverse_preorder()])
# Pipeline of transformations result = dotpipe(tree,
(”**.config”, lambda n: n.payload), # Extract config payloads lambda configs: {c.get(“name”): c for c in configs}, # Dict by name lambda d: list(d.values())) # Back to list
# Convert tree to nested dict data = dotpipe(tree, to_dict)
# Extract and process specific data totals = dotpipe(tree,
(”**[type=file]”, lambda n: n.payload.get(“size”, 0)), sum) # Sum all sizes
- AlgoTree.dotpluck(tree: Node, *dot_paths: str) List[Any] [source]¶
Extract values from tree using dot notation paths.
Inspired by dotsuite’s dotpluck, this extracts payload values from nodes at specified paths.
- Parameters:
tree – Tree to extract from
*dot_paths – Variable number of dot notation paths
- Returns:
List of values (payload or None for missing paths)
Examples
# Extract multiple values values = dotpluck(tree, “user.name”, “user.age”, “user.email”)
# Extract with wildcards (returns all matching values) values = dotpluck(tree, “users.*.name”)
- AlgoTree.dotproject(tree: Node, projection: List[str] | Dict[str, str], dot_path: str = '**') List[Dict[str, Any]] [source]¶
Project specific fields from nodes (like SQL SELECT).
- Parameters:
tree – Tree to project from
projection – Either: - List of field names to include - Dict mapping field names to aliases
dot_path – Pattern to match nodes
- Returns:
List of projected dictionaries
Examples
# Select specific fields data = dotproject(tree, [“name”, “size”, “type”])
# With aliases data = dotproject(tree, {
“name”: “file_name”, “size”: “file_size”, “type”: “file_type”
})
- AlgoTree.dotprune(tree: Node, condition: str | Callable[[Node], bool], keep_structure: bool = False, in_place: bool = False) Node [source]¶
Prune nodes from tree based on condition.
- Parameters:
tree – Tree to prune
condition – Either: - Dot path pattern of nodes to remove - Predicate function (returns True for nodes to remove)
keep_structure – If True, replace pruned nodes with empty placeholders
in_place – If True, modify tree in place
- Returns:
Pruned tree
Examples
# Remove all test files tree = dotprune(tree, “**.test_*”)
# Remove empty directories tree = dotprune(tree, lambda n: n.payload.get(“type”) == “dir” and len(n.children) == 0)
# Keep structure but clear nodes tree = dotprune(tree, “**.deprecated”, keep_structure=True)
- AlgoTree.dotreduce(tree: Node, reducer: Callable[[Any, Node], Any], initial: Any = None, traverse_pattern: str = '**') Any [source]¶
Reduce tree to a single value using a reducer function.
- Parameters:
tree – Tree to reduce
reducer – Function (accumulator, node) -> new_accumulator
initial – Initial value for accumulator
traverse_pattern – Pattern for nodes to include in reduction
- Returns:
Reduced value
Examples
# Sum all sizes total_size = dotreduce(tree,
lambda acc, n: acc + n.payload.get(“size”, 0), initial=0)
# Collect all names names = dotreduce(tree,
lambda acc, n: acc + [n.name], initial=[])
# Find maximum depth max_depth = dotreduce(tree,
lambda acc, n: max(acc, n.level), initial=0)
- AlgoTree.dotsplit(tree: Node, split_point: str, include_point: bool = True) Tuple[Node, List[Node]] [source]¶
Split tree at specified point(s), extracting subtrees.
- Parameters:
tree – Tree to split
split_point – Dot path to split point(s)
include_point – If True, include split point in extracted subtrees
- Returns:
Tuple of (modified tree, list of extracted subtrees)
Examples
# Extract all test modules tree, test_modules = dotsplit(tree, “**.tests”)
# Extract but keep the container node tree, extracted = dotsplit(tree, “app.deprecated”, include_point=False)
- AlgoTree.dotvalidate(tree: Node, validator: Callable[[Node], bool] | Dict[str, Any], dot_path: str = '**', raise_on_invalid: bool = True) bool | List[Node] [source]¶
Validate nodes in the tree against criteria.
- Parameters:
tree – Tree to validate
validator – Either: - Predicate function returning True for valid nodes - Dict of required attributes and values
dot_path – Pattern for nodes to validate
raise_on_invalid – If True, raise exception on first invalid node
- Returns:
List of invalid nodes (empty if all valid) If raise_on_invalid=True: True if all valid (raises otherwise)
- Return type:
If raise_on_invalid=False
Examples
# Validate with function dotvalidate(tree,
lambda n: n.payload.get(“size”, 0) < 1000000, dot_path=”**[type=file]”)
# Validate required attributes dotvalidate(tree,
{“type”: “file”, “tested”: True}, dot_path=”app.src.**”)
# Get list of invalid nodes invalid = dotvalidate(tree,
lambda n: len(n.name) <= 255, raise_on_invalid=False)
- AlgoTree.dumps(tree: Node, **json_kwargs) str [source]¶
Serialize tree to JSON string.
- Parameters:
tree – Tree to serialize
**json_kwargs – Arguments passed to json.dumps (indent, sort_keys, etc.)
- Returns:
JSON string
Example
json_str = dumps(tree, indent=2, sort_keys=True)
- AlgoTree.export_tree(node: Node, format: str, **kwargs) str [source]¶
Export tree to specified format.
- Parameters:
node – Root node of tree
format – Export format (json, ascii, unicode, graphviz, mermaid, yaml, xml, html)
**kwargs – Format-specific options
- Returns:
String representation in specified format
- AlgoTree.load(path: str | Path) Node [source]¶
Load tree from JSON file.
Automatically handles gzip compression if file ends with .gz
- Parameters:
path – File path
- Returns:
Root node of loaded tree
Example
tree = load(“my_tree.json”) tree = load(“my_tree.json.gz”) # Auto-detects compression
- AlgoTree.loads(json_str: str) Node [source]¶
Deserialize tree from JSON string.
- Parameters:
json_str – JSON string
- Returns:
Root node of tree
Example
tree = loads(‘{“name”: “root”, “children”: […]}’)
- AlgoTree.parse_tree(text: str, format: str = 'auto') Node [source]¶
Convenience function to parse tree from DSL text.
- Parameters:
text – DSL text to parse.
format – Format to use (‘visual’, ‘indent’, ‘sexpr’, ‘auto’).
- Returns:
Root node of parsed tree.
Examples
# Visual format tree = parse_tree(‘’’
company ├── engineering │ ├── frontend │ └── backend └── sales
‘’’)
# Indent format tree = parse_tree(‘’’
- company
- engineering
frontend backend
sales
‘’’)
# S-expression format tree = parse_tree(‘’’
- (company
- (engineering
(frontend) (backend))
(sales))
‘’’)
- AlgoTree.pattern_match(tree: Node, pattern: str | Dict | Pattern, match_type: MatchType = MatchType.PARTIAL) List[Node] [source]¶
Convenience function to find all matches of a pattern in a tree.
- Parameters:
tree – Tree to search
pattern – Pattern as string, dict, or Pattern object
match_type – Type of matching
- Returns:
List of matching nodes
- AlgoTree.pretty_tree(node, **kwargs) str [source]¶
Converts a tree to a pretty string representation.
- Parameters:
kwargs – Key-word arguments. See PrettyTree for more details.
- Returns:
A pretty string representation of the tree.
- AlgoTree.save(tree: Node, path: str | Path, compress: bool = False) None [source]¶
Save tree to JSON file.
This is the recommended way to persist trees. Uses the natural hierarchical JSON representation.
- Parameters:
tree – Tree to save
path – File path (can be string or Path object)
compress – If True, use gzip compression
Example
save(tree, “my_tree.json”) save(tree, “my_tree.json.gz”, compress=True)
- AlgoTree.save_tree(node: Node, filepath: str, format: str | None = None, **kwargs)[source]¶
Save tree to file in specified format.
- Parameters:
node – Root node of tree
filepath – Output file path
format – Export format (auto-detected from extension if not specified)
**kwargs – Format-specific options
- AlgoTree.to_adjacency_list(node: Node) Dict[str, List[str]] [source]¶
Convert tree to adjacency list representation.
- Parameters:
node – Root node
- Returns:
Dictionary mapping node names to lists of child names
Examples
adj = to_adjacency_list(tree) # {“app”: [“config”, “database”], “config”: [], …}
- AlgoTree.to_dict(node: Node, include_children: bool = True, include_parent: bool = False, key_mapper: Callable[[str], str] | None = None) Dict[str, Any] [source]¶
Convert tree node to dictionary representation.
- Parameters:
node – Node to convert
include_children – If True, recursively include children
include_parent – If True, include parent reference (careful: can be circular)
key_mapper – Optional function to transform keys
- Returns:
Dictionary representation of the node
Examples
# Simple conversion data = to_dict(tree)
# Without children (just this node) node_data = to_dict(tree, include_children=False)
# With key transformation data = to_dict(tree, key_mapper=str.upper)
- AlgoTree.to_edge_list(node: Node, include_root: bool = False) List[Tuple[str, str]] [source]¶
Convert tree to edge list representation.
- Parameters:
node – Root node
include_root – If True, include edge from None to root
- Returns:
List of (parent, child) tuples
Examples
edges = to_edge_list(tree) # [(“app”, “config”), (“app”, “database”), …]
- AlgoTree.to_graphviz_data(tree: Node) Dict[str, Any] [source]¶
Convert tree to GraphViz data structure.
Returns dict with ‘nodes’ and ‘edges’ suitable for visualization.
- AlgoTree.to_json_schema(tree: Node, type_key: str = 'type', required_key: str = 'required') Dict[str, Any] [source]¶
Convert tree to JSON Schema-like structure.
Useful for representing configuration schemas or data models.
- AlgoTree.to_list(node: Node, traverse_order: str = 'preorder', include_data: bool = True) List[str | Dict[str, Any]] [source]¶
Convert tree to flat list representation.
- Parameters:
node – Root node
traverse_order – Traversal order (“preorder”, “postorder”, “levelorder”)
include_data – If True, include full node data; if False, just names
- Returns:
List of nodes (as dicts or names)
Examples
# List of all node names names = to_list(tree, include_data=False)
# List of node data in level order nodes = to_list(tree, traverse_order=”levelorder”)
- AlgoTree.to_nested_lists(node: Node) List [source]¶
Convert tree to nested list structure (like S-expressions).
- Parameters:
node – Root node
- Returns:
Nested list representation
Examples
nested = to_nested_lists(tree) # [“app”, [“config”], [“database”], [“modules”, [“auth”], [“api”]]]
- AlgoTree.to_paths(node: Node, path_separator: str = '.', include_payload: bool = False) List[str] | Dict[str, Any] [source]¶
Convert tree to path representations.
- Parameters:
node – Root node
path_separator – Separator for path components
include_payload – If True, return dict mapping paths to payloads
- Returns:
List of paths or dict mapping paths to payloads
Examples
# List of all paths paths = to_paths(tree) # [“app”, “app.config”, “app.database”, …]
# Paths with payloads path_data = to_paths(tree, include_payload=True) # {“app”: {…}, “app.config”: {…}, …}
# Using different separator paths = to_paths(tree, path_separator=”/”) # [“app”, “app/config”, “app/database”, …]
- AlgoTree.to_table(node: Node, columns: List[str] | None = None, include_path: bool = True) List[Dict[str, Any]] [source]¶
Convert tree to tabular/relational format.
- Parameters:
node – Root node
columns – Specific payload columns to include (None = all)
include_path – If True, include full path to node
- Returns:
List of row dictionaries suitable for DataFrame or CSV
Examples
# Convert to table format rows = to_table(tree, columns=[“type”, “size”, “enabled”])
# Can be used with pandas: # df = pd.DataFrame(rows)