or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-export.mdindex.mdtree-construction.mdtree-modification.mdtree-traversal.mdvisualization.md

tree-modification.mddocs/

0

# Tree Modification Operations

1

2

Comprehensive functionality for dynamically modifying tree structures including moving nodes, removing branches, copying subtrees, and updating node properties while maintaining data integrity and relationships.

3

4

## Capabilities

5

6

### Node Movement and Reorganization

7

8

Move nodes within the tree to reorganize structure while preserving subtree relationships.

9

10

```python { .api }

11

def move_node(source, destination) -> None:

12

"""

13

Move a node and its subtree to a new parent.

14

15

Parameters:

16

- source: str, identifier of node to move

17

- destination: str, identifier of new parent node

18

19

Raises:

20

LoopError if move would create circular reference

21

NodeIDAbsentError if source or destination doesn't exist

22

"""

23

```

24

25

**Usage Examples:**

26

27

```python

28

# Move employee to different department

29

tree.move_node("alice", "sales_dept")

30

31

# Reorganize departments

32

tree.move_node("engineering", "technology_division")

33

34

# Move multiple nodes

35

employees_to_transfer = ["bob", "carol", "dave"]

36

for emp_id in employees_to_transfer:

37

tree.move_node(emp_id, "new_department")

38

39

# Move with error handling

40

try:

41

tree.move_node("manager", "subordinate") # Would create loop

42

except LoopError:

43

print("Cannot move manager under subordinate")

44

```

45

46

### Node and Subtree Removal

47

48

Remove individual nodes or entire subtrees from the tree structure.

49

50

```python { .api }

51

def remove_node(identifier) -> int:

52

"""

53

Remove a node and all its descendants from the tree.

54

55

Parameters:

56

- identifier: str, node identifier to remove

57

58

Returns:

59

int, number of nodes removed (including descendants)

60

61

Raises:

62

NodeIDAbsentError if node doesn't exist

63

"""

64

65

def link_past_node(nid) -> None:

66

"""

67

Remove node while connecting its children to its parent.

68

69

Parameters:

70

- nid: str, node identifier to remove

71

72

Raises:

73

LinkPastRootNodeError if attempting to link past root

74

NodeIDAbsentError if node doesn't exist

75

"""

76

```

77

78

**Usage Examples:**

79

80

```python

81

# Remove employee and report structure

82

removed_count = tree.remove_node("manager_leaving")

83

print(f"Removed {removed_count} nodes from organization")

84

85

# Remove department but keep employees

86

tree.link_past_node("temp_department") # Employees move up to parent

87

88

# Conditional removal

89

nodes_to_remove = []

90

for node_id in tree.expand_tree():

91

node = tree[node_id]

92

if node.data and node.data.get("status") == "inactive":

93

nodes_to_remove.append(node_id)

94

95

for node_id in nodes_to_remove:

96

tree.remove_node(node_id)

97

98

# Safe removal with validation

99

if "old_project" in tree:

100

if not tree.children("old_project"): # Check if has children

101

tree.remove_node("old_project")

102

else:

103

print("Cannot remove project with active sub-projects")

104

```

105

106

### Node Property Updates

107

108

Update node attributes and data while maintaining tree structure.

109

110

```python { .api }

111

def update_node(nid, **attrs) -> None:

112

"""

113

Update node attributes.

114

115

Parameters:

116

- nid: str, node identifier

117

- **attrs: keyword arguments for node attributes (tag, data, etc.)

118

119

Raises:

120

NodeIDAbsentError if node doesn't exist

121

"""

122

```

123

124

**Usage Examples:**

125

126

```python

127

# Update node tag (display name)

128

tree.update_node("emp_001", tag="Alice Smith (Senior Engineer)")

129

130

# Update node data

131

tree.update_node("emp_001", data={

132

"name": "Alice Smith",

133

"role": "Senior Engineer",

134

"salary": 125000,

135

"department": "Engineering"

136

})

137

138

# Multiple attribute update

139

tree.update_node("project_x",

140

tag="Project X - Phase 2",

141

data={"status": "active", "budget": 500000})

142

143

# Conditional updates

144

for node_id in tree.expand_tree():

145

node = tree[node_id]

146

if node.data and node.data.get("role") == "intern":

147

tree.update_node(node_id,

148

tag=f"{node.tag} (Full-time)",

149

data={**node.data, "role": "junior"})

150

```

151

152

### Subtree Operations

153

154

Create, extract, and manipulate subtrees as independent tree structures.

155

156

```python { .api }

157

def subtree(nid, identifier=None) -> Tree:

158

"""

159

Create a shallow copy of subtree rooted at specified node.

160

161

Parameters:

162

- nid: str, root node identifier for subtree

163

- identifier: str, identifier for new tree (optional)

164

165

Returns:

166

Tree, new tree containing the subtree

167

168

Raises:

169

NodeIDAbsentError if node doesn't exist

170

"""

171

172

def remove_subtree(nid, identifier=None) -> Tree:

173

"""

174

Extract subtree from tree (removes from original).

175

176

Parameters:

177

- nid: str, root node identifier for subtree

178

- identifier: str, identifier for extracted tree (optional)

179

180

Returns:

181

Tree, extracted subtree as independent tree

182

"""

183

```

184

185

**Usage Examples:**

186

187

```python

188

# Create copy of department subtree

189

eng_dept_copy = tree.subtree("engineering")

190

eng_dept_copy.show()

191

192

# Extract department for restructuring

193

sales_dept = tree.remove_subtree("sales")

194

print(f"Extracted {sales_dept.size()} person sales department")

195

196

# Process subtrees independently

197

all_departments = ["engineering", "sales", "hr"]

198

dept_trees = {}

199

for dept_id in all_departments:

200

if dept_id in tree:

201

dept_trees[dept_id] = tree.subtree(dept_id)

202

203

# Analyze subtrees

204

for dept_name, dept_tree in dept_trees.items():

205

employee_count = dept_tree.size() - 1 # Exclude department head

206

print(f"{dept_name}: {employee_count} employees")

207

```

208

209

### Tree Merging and Pasting

210

211

Combine trees and paste subtrees to build complex structures.

212

213

```python { .api }

214

def paste(nid, new_tree, deep=False) -> None:

215

"""

216

Paste another tree as subtree under specified node.

217

218

Parameters:

219

- nid: str, parent node identifier where tree will be pasted

220

- new_tree: Tree, tree to paste as subtree

221

- deep: bool, perform deep copy if True

222

223

Raises:

224

NodeIDAbsentError if parent node doesn't exist

225

"""

226

227

def merge(nid, new_tree, deep=False) -> None:

228

"""

229

Merge another tree's children under specified node.

230

231

Parameters:

232

- nid: str, parent node identifier

233

- new_tree: Tree, tree whose children will be merged

234

- deep: bool, perform deep copy if True

235

"""

236

```

237

238

**Usage Examples:**

239

240

```python

241

# Create new subsidiary structure

242

subsidiary = Tree()

243

subsidiary.create_node("Subsidiary Corp", "sub_corp")

244

subsidiary.create_node("Sub Engineering", "sub_eng", parent="sub_corp")

245

subsidiary.create_node("Sub Sales", "sub_sales", parent="sub_corp")

246

247

# Paste entire subsidiary under main company

248

tree.paste("company", subsidiary)

249

250

# Merge departments from acquired company

251

acquired_company = Tree()

252

acquired_company.create_node("Acquired Corp", "acq_corp")

253

acquired_company.create_node("R&D Department", "rd", parent="acq_corp")

254

acquired_company.create_node("Marketing", "marketing", parent="acq_corp")

255

256

# Merge just the departments (not the company node)

257

tree.merge("company", acquired_company)

258

259

# Deep copy for independent data

260

secure_backup = tree.subtree("sensitive_project")

261

tree.paste("backup_location", secure_backup, deep=True)

262

```

263

264

### Advanced Modification Patterns

265

266

Complex modification scenarios and bulk operations.

267

268

**Usage Examples:**

269

270

```python

271

# Bulk reorganization

272

def reorganize_by_role():

273

# Group employees by role

274

roles = {}

275

for node_id in tree.expand_tree():

276

node = tree[node_id]

277

if node.data and "role" in node.data:

278

role = node.data["role"]

279

if role not in roles:

280

roles[role] = []

281

roles[role].append(node_id)

282

283

# Create role-based departments

284

for role, employee_ids in roles.items():

285

dept_id = f"{role}_dept"

286

tree.create_node(f"{role.title()} Department", dept_id, parent="company")

287

for emp_id in employee_ids:

288

tree.move_node(emp_id, dept_id)

289

290

# Conditional restructuring

291

def flatten_single_child_branches():

292

"""Remove nodes that have only one child by linking past them."""

293

nodes_to_remove = []

294

for node_id in tree.expand_tree():

295

children = tree.children(node_id)

296

if len(children) == 1 and not tree.is_root(node_id):

297

nodes_to_remove.append(node_id)

298

299

for node_id in nodes_to_remove:

300

tree.link_past_node(node_id)

301

302

# Tree surgery - replace subtree

303

def replace_subtree(old_root_id, new_subtree):

304

"""Replace an existing subtree with a new one."""

305

parent_id = tree.parent(old_root_id).identifier if tree.parent(old_root_id) else None

306

tree.remove_node(old_root_id)

307

if parent_id:

308

tree.paste(parent_id, new_subtree)

309

else:

310

# Replacing root - more complex operation

311

tree.nodes.clear()

312

tree.paste(None, new_subtree)

313

314

# Batch updates with transaction-like behavior

315

def batch_update(updates):

316

"""Apply multiple updates with rollback on error."""

317

backup = Tree(tree, deep=True) # Create backup

318

try:

319

for update_type, *args in updates:

320

if update_type == "move":

321

tree.move_node(*args)

322

elif update_type == "remove":

323

tree.remove_node(*args)

324

elif update_type == "update":

325

tree.update_node(*args)

326

except Exception as e:

327

# Rollback on error

328

tree.nodes = backup.nodes

329

tree.root = backup.root

330

raise e

331

332

# Usage of batch update

333

updates = [

334

("move", "alice", "new_dept"),

335

("update", "bob", {"role": "senior"}),

336

("remove", "old_project")

337

]

338

batch_update(updates)

339

```

340

341

### Tree Structure Validation

342

343

Validate tree integrity after modifications.

344

345

**Usage Examples:**

346

347

```python

348

def validate_tree_integrity():

349

"""Validate tree structure after modifications."""

350

issues = []

351

352

# Check for orphaned nodes

353

for node_id, node in tree.nodes.items():

354

if node_id != tree.root:

355

parent_id = tree.parent(node_id)

356

if not parent_id or parent_id.identifier not in tree.nodes:

357

issues.append(f"Orphaned node: {node_id}")

358

359

# Check for circular references

360

visited = set()

361

def check_cycles(node_id, path):

362

if node_id in path:

363

issues.append(f"Circular reference: {path + [node_id]}")

364

return

365

if node_id in visited:

366

return

367

visited.add(node_id)

368

for child in tree.children(node_id):

369

check_cycles(child.identifier, path + [node_id])

370

371

if tree.root:

372

check_cycles(tree.root, [])

373

374

return issues

375

376

# Validate after major changes

377

issues = validate_tree_integrity()

378

if issues:

379

print("Tree integrity issues found:")

380

for issue in issues:

381

print(f" - {issue}")

382

```

383

384

## Exception Handling

385

386

```python { .api }

387

class LoopError(Exception):

388

"""Raised when operation would create circular reference"""

389

390

class LinkPastRootNodeError(Exception):

391

"""Raised when attempting to link past root node"""

392

393

class NodeIDAbsentError(Exception):

394

"""Raised when referencing non-existent node"""

395

```

396

397

**Usage Examples:**

398

399

```python

400

from treelib import LoopError, LinkPastRootNodeError, NodeIDAbsentError

401

402

# Safe node movement

403

def safe_move_node(source, destination):

404

try:

405

tree.move_node(source, destination)

406

return True

407

except LoopError:

408

print(f"Cannot move {source} to {destination}: would create loop")

409

return False

410

except NodeIDAbsentError as e:

411

print(f"Node not found: {e}")

412

return False

413

414

# Safe link past operation

415

def safe_link_past(node_id):

416

try:

417

tree.link_past_node(node_id)

418

return True

419

except LinkPastRootNodeError:

420

print("Cannot link past root node")

421

return False

422

except NodeIDAbsentError:

423

print(f"Node {node_id} not found")

424

return False

425

```