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:

  1. Forward pointer update: The parent’s successor list is updated via __update_fpointer (line 1037 in treelib/tree.py), adding the new child identifier to the parent’s children list.
  2. Backward pointer update: The child’s predecessor is set via __update_bpointer (line 1040 in treelib/tree.py), establishing the link back to the parent.
  3. Tree ID registration: The node records the tree’s unique identifier via set_initial_tree_id (line 1042 in treelib/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 by add_node() (line 998 in treelib/tree.py) if the identifier already exists in the tree.
  • MultipleRootError: Raised when attempting to add a second root node (parent is None but 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, or Tree.add_node() to attach existing Node objects.
  • Internal consistency: Both methods update bidirectional pointers (__update_fpointer and __update_bpointer in treelib/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_class to the Tree constructor and use add_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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →