How to Add Nodes to a treelib Tree: A Complete Guide
Use Tree.create_node() to build and insert a node in one step, or Tree.add_node() to attach an existing Node object to your tree.
The treelib library (caesar0301/treelib) represents hierarchical data as a collection of Node objects managed by a Tree instance. Whether you are building an organizational chart, a file system, or an abstract syntax tree, understanding the two primary methods for adding nodes—create_node() and add_node()—ensures you can construct trees efficiently while maintaining internal consistency.
The Two Methods for Adding Nodes
treelib exposes two high-level APIs for node insertion in treelib/tree.py. Both perform identical internal bookkeeping, including pointer updates and validation, but differ in how the Node object is instantiated.
Tree.create_node(): Create and Add in One Step
The create_node() method (defined at line 825 in treelib/tree.py) constructs a fresh Node instance using the tree’s configured node_class and immediately attaches it to the hierarchy.
from treelib import Tree
tree = Tree()
# Create root node (parent=None, tree must be empty)
tree.create_node(tag="Company", identifier="company")
# Add children by specifying parent identifier
tree.create_node(tag="Engineering", identifier="eng", parent="company")
tree.create_node(tag="Sales", identifier="sales", parent="company")
When parent is None, the method validates that the tree is empty before establishing the root. If a parent is provided, treelib verifies that the parent identifier exists in the tree, raising NodeIDAbsentError from treelib/exceptions.py if not found.
Tree.add_node(): Insert Existing Node Objects
The add_node() method (defined at line 844 in treelib/tree.py) accepts an already-constructed Node object. This is essential when using custom Node subclasses or when nodes are built by external factories.
from treelib import Tree, Node
tree = Tree()
# Construct nodes manually
root = Node(tag="Root", identifier="root")
child = Node(tag="Child", identifier="child")
# Insert into tree
tree.add_node(root) # Becomes root
tree.add_node(child, parent="root") # Child of root
Both methods ultimately delegate to the same internal logic that updates forward and backward pointers, ensuring tree integrity.
Internal Mechanics of Node Addition
When you call either create_node() or add_node(), treelib performs several validation and bookkeeping steps in treelib/tree.py to maintain the tree structure.
Pointer Management and Tree Integrity
The library maintains bidirectional relationships between nodes:
- Forward pointer update: The parent’s successor list is updated via
__update_fpointer(line 1037 intreelib/tree.py), adding the new child identifier to the parent’s children list. - Backward pointer update: The child’s predecessor is set via
__update_bpointer(line 1040 intreelib/tree.py), establishing the link back to the parent. - Tree ID registration: The node records the tree’s unique identifier via
set_initial_tree_id(line 1042 intreelib/tree.py), enabling multi-tree support and preventing cross-tree contamination.
Validation and Error Handling
The treelib/exceptions.py module defines specific errors raised during node addition:
DuplicatedNodeIdError: Raised byadd_node()(line 998 intreelib/tree.py) if the identifier already exists in the tree.MultipleRootError: Raised when attempting to add a second root node (parent isNonebut tree is not empty).NodeIDAbsentError: Raised when the specified parent identifier does not exist in the tree.
These validations ensure that tree operations remain safe and deterministic.
Practical Code Examples
Building a Hierarchy with create_node()
This example demonstrates creating a complete organizational chart using the convenience method:
from treelib import Tree
tree = Tree()
tree.create_node("CEO", "ceo") # Root
tree.create_node("CTO", "cto", parent="ceo") # Level 1
tree.create_node("CFO", "cfo", parent="ceo") # Level 1
tree.create_node("Dev Lead", "dev_lead", parent="cto") # Level 2
tree.create_node("Developer", "dev1", parent="dev_lead") # Level 3
tree.show()
Output:
CEO
├── CTO
│ └── Dev Lead
│ └── Developer
└── CFO
Using Custom Node Subclasses
For advanced use cases, subclass Node and pass node_class to the Tree constructor:
from treelib import Tree, Node
class FileNode(Node):
def __init__(self, tag, identifier=None, data=None, file_size=0):
super().__init__(tag, identifier, data)
self.file_size = file_size
tree = Tree(node_class=FileNode)
# Create nodes manually then add them
root = FileNode("Root", "root", file_size=0)
file1 = FileNode("document.txt", "doc1", file_size=1024)
tree.add_node(root)
tree.add_node(file1, parent="root")
print(f"File size: {tree.get_node('doc1').file_size} bytes")
This approach leverages add_node() to insert pre-constructed custom objects while maintaining the tree structure defined in treelib/tree.py.
Summary
- Two entry points: Use
Tree.create_node()for one-step creation and insertion, orTree.add_node()to attach existingNodeobjects. - Internal consistency: Both methods update bidirectional pointers (
__update_fpointerand__update_bpointerintreelib/tree.py) and register the tree ID to prevent cross-tree contamination. - Robust validation: The library raises specific exceptions from
treelib/exceptions.py(DuplicatedNodeIdError,MultipleRootError,NodeIDAbsentError) to enforce tree integrity. - Extensibility: Pass a custom
node_classto theTreeconstructor and useadd_node()to insert specialized node types.
Frequently Asked Questions
What is the difference between create_node() and add_node() in treelib?
create_node() instantiates a new Node object internally and immediately adds it to the tree, accepting parameters like tag, identifier, and parent. add_node() requires you to construct the Node object yourself before passing it as an argument, which is necessary when using custom Node subclasses or when nodes are created by external factories. Both methods ultimately execute the same pointer-updating logic in treelib/tree.py.
Can I add a node without specifying a parent in treelib?
Yes, but only for the first node in an empty tree. When you call create_node() or add_node() with parent=None, treelib checks if the tree is empty (line 825 in treelib/tree.py). If the tree already has a root, the library raises MultipleRootError from treelib/exceptions.py to prevent creating a second root node.
How do I use a custom Node subclass when adding nodes to a treelib tree?
First, subclass Node from treelib.node to add your custom attributes or methods. Then, pass your subclass as the node_class parameter when initializing the Tree (line 69 in treelib/tree.py). Finally, use add_node() to insert instances of your custom class, as create_node() will also respect the node_class setting but add_node() gives you full control over the instantiation process.
What happens if I try to add a node with a duplicate identifier in treelib?
The library raises DuplicatedNodeIdError defined in treelib/exceptions.py. This check occurs in add_node() at line 998 of treelib/tree.py before any pointer updates are performed. Each node in a tree must have a unique identifier to maintain the integrity of the bidirectional pointer structure managed by __update_fpointer and __update_bpointer.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →