Source code for AlgoTree.node

"""
Modern node implementation using proper classes instead of dict inheritance.
"""
from typing import Any, Optional, List, Dict, Iterator, Callable
from uuid import uuid4


[docs] class Node: """ 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 """ def __init__( self, name: Optional[str] = None, parent: Optional['Node'] = None, **payload ): """ Initialize a node. Args: name: Unique identifier for the node. If None, generates a UUID. parent: Parent node reference. If provided, adds this node to parent's children. **payload: Arbitrary key-value pairs to store as node data. """ self.name = name if name is not None else str(uuid4()) self._parent: Optional[Node] = None self.children: List[Node] = [] self.payload: Dict[str, Any] = payload # Set parent (which also updates parent's children list) if parent is not None: self.parent = parent @property def parent(self) -> Optional['Node']: """Get the parent node.""" return self._parent @parent.setter def parent(self, new_parent: Optional['Node']): """ Set the parent node, updating both old and new parent's children lists. """ # Remove from old parent's children if self._parent is not None: self._parent.children.remove(self) # Set new parent self._parent = new_parent # Add to new parent's children if new_parent is not None: if self not in new_parent.children: new_parent.children.append(self) @property def root(self) -> 'Node': """Get the root node of the tree.""" node = self while node.parent is not None: node = node.parent return node @property def level(self) -> int: """Get the level (depth) of this node in the tree.""" level = 0 node = self.parent while node is not None: level += 1 node = node.parent return level @property def is_root(self) -> bool: """Check if this is a root node.""" return self.parent is None @property def is_leaf(self) -> bool: """Check if this is a leaf node.""" return len(self.children) == 0 @property def siblings(self) -> List['Node']: """Get list of sibling nodes.""" if self.parent is None: return [] return [child for child in self.parent.children if child != self]
[docs] def add_child(self, name: Optional[str] = None, **payload) -> 'Node': """ Add a child node. Args: name: Name for the child node. **payload: Data for the child node. Returns: The newly created child node. """ return Node(name=name, parent=self, **payload)
[docs] def remove_child(self, child: 'Node') -> None: """Remove a child node.""" if child in self.children: child._parent = None self.children.remove(child)
[docs] def traverse_preorder(self) -> Iterator['Node']: """Traverse tree in preorder (parent before children).""" yield self for child in self.children: yield from child.traverse_preorder()
[docs] def traverse_postorder(self) -> Iterator['Node']: """Traverse tree in postorder (children before parent).""" for child in self.children: yield from child.traverse_postorder() yield self
[docs] def traverse_levelorder(self) -> Iterator['Node']: """Traverse tree in level order (breadth-first).""" queue = [self] while queue: node = queue.pop(0) yield node queue.extend(node.children)
[docs] def find(self, predicate: Callable[['Node'], bool]) -> Optional['Node']: """ Find first node matching predicate. Args: predicate: Function that returns True for matching nodes. Returns: First matching node or None. """ for node in self.traverse_preorder(): if predicate(node): return node return None
[docs] def find_all(self, predicate: Callable[['Node'], bool]) -> List['Node']: """ Find all nodes matching predicate. Args: predicate: Function that returns True for matching nodes. Returns: List of matching nodes. """ return [node for node in self.traverse_preorder() if predicate(node)]
[docs] def get_path(self) -> List['Node']: """Get path from root to this node.""" path = [] node = self while node is not None: path.append(node) node = node.parent return list(reversed(path))
[docs] def to_dict(self) -> Dict[str, Any]: """ Convert tree to nested dictionary representation. Returns: Dictionary with node data and nested children. """ result = { 'name': self.name, **self.payload } if self.children: result['children'] = [child.to_dict() for child in self.children] return result
[docs] @classmethod def from_dict(cls, data: Dict[str, Any], parent: Optional['Node'] = None) -> 'Node': """ Create tree from nested dictionary representation. Args: data: Dictionary with node data and optional 'children' key. parent: Parent node for the created tree. Returns: Root node of created tree. """ children_data = data.pop('children', []) name = data.pop('name', None) node = cls(name=name, parent=parent, **data) for child_data in children_data: cls.from_dict(child_data, parent=node) return node
[docs] def clone(self) -> 'Node': """Create a deep copy of this node and its subtree.""" return self.from_dict(self.to_dict())
def __repr__(self) -> str: return f"Node(name={self.name!r}, payload={self.payload!r}, children={len(self.children)})" def __str__(self) -> str: """Return a simple string representation.""" return self.name