or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-operations.mddata-manipulation.mdindex.mdpath-access.mdsearch-operations.md

advanced-operations.mddocs/

0

# Advanced Operations

1

2

Low-level utilities for custom path manipulation and advanced use cases, providing direct access to the underlying path walking, matching, and transformation algorithms that power dpath's high-level functions.

3

4

## Capabilities

5

6

### Path Walking and Traversal

7

8

Core traversal functions that provide the foundation for all dpath operations, offering fine-grained control over how nested structures are navigated.

9

10

```python { .api }

11

from dpath.segments import walk, make_walkable, leaf, leafy

12

13

def walk(obj, location=()):

14

"""

15

Walk object yielding (segments, value) pairs in breadth-first order.

16

17

Parameters:

18

- obj: Object to walk (dict, list, or other nested structure)

19

- location (tuple): Current location tuple (used internally for recursion)

20

21

Yields:

22

Tuple[Tuple[PathSegment, ...], Any]: (path_segments, value) pairs

23

24

Note:

25

Walks right-to-left for sequences to support safe deletion patterns.

26

"""

27

28

def make_walkable(node):

29

"""

30

Create iterator for (key, value) pairs regardless of node type.

31

32

Parameters:

33

- node: Dict, list, tuple, or other container

34

35

Returns:

36

Iterator[Tuple[PathSegment, Any]]: Iterator of (key, value) pairs

37

"""

38

39

def leaf(thing):

40

"""

41

Check if object is a leaf (primitive type: str, int, float, bool, None, bytes).

42

43

Parameters:

44

- thing: Any object to test

45

46

Returns:

47

bool: True if object is a primitive leaf value

48

"""

49

50

def leafy(thing):

51

"""

52

Check if object is leaf-like (primitive or empty container).

53

54

Parameters:

55

- thing: Any object to test

56

57

Returns:

58

bool: True if object is primitive or empty sequence/mapping

59

"""

60

```

61

62

#### Usage Examples

63

64

```python

65

from dpath.segments import walk, make_walkable, leaf, leafy

66

67

data = {

68

"users": {

69

"john": {"age": 30, "hobbies": ["reading", "gaming"]},

70

"jane": {"age": 25, "hobbies": []}

71

}

72

}

73

74

# Walk entire structure

75

for path_segments, value in walk(data):

76

path_str = "/".join(str(seg) for seg in path_segments)

77

print(f"{path_str}: {value} (leaf: {leaf(value)})")

78

79

# Output includes:

80

# users: {'john': {...}, 'jane': {...}} (leaf: False)

81

# users/john: {'age': 30, 'hobbies': [...]} (leaf: False)

82

# users/john/age: 30 (leaf: True)

83

# users/john/hobbies: ['reading', 'gaming'] (leaf: False)

84

# users/john/hobbies/0: reading (leaf: True)

85

# etc.

86

87

# Make any container walkable

88

mixed_data = [{"key": "value"}, "string", 42]

89

for key, value in make_walkable(mixed_data):

90

print(f"Index {key}: {value}")

91

92

# Test leaf conditions

93

print(leaf("string")) # True

94

print(leaf(42)) # True

95

print(leaf([])) # False

96

print(leafy([])) # True (empty containers are leafy)

97

print(leafy({"a": 1})) # False (non-empty containers)

98

```

99

100

### Pattern Matching and Filtering

101

102

Advanced pattern matching utilities for implementing custom search and filter logic.

103

104

```python { .api }

105

from dpath.segments import match, view, has, get

106

107

def match(segments, glob):

108

"""

109

Check if path segments match glob pattern.

110

111

Parameters:

112

- segments (Path): Path segments as tuple or list

113

- glob (Glob): Glob pattern as tuple or list

114

115

Returns:

116

bool: True if segments match the glob pattern

117

118

Note:

119

Supports *, **, character classes, and complex patterns.

120

Converts integers to strings for comparison.

121

"""

122

123

def view(obj, glob):

124

"""

125

Create filtered deep copy view of object matching glob.

126

127

Parameters:

128

- obj (MutableMapping): Object to create view from

129

- glob (Glob): Glob pattern to match

130

131

Returns:

132

MutableMapping: New object containing only matching paths (deep copied)

133

"""

134

135

def has(obj, segments):

136

"""

137

Check if path exists in object.

138

139

Parameters:

140

- obj: Object to check

141

- segments: Path segments as sequence

142

143

Returns:

144

bool: True if path exists

145

"""

146

147

def get(obj, segments):

148

"""

149

Get value at path segments (lower-level than dpath.get).

150

151

Parameters:

152

- obj: Object to navigate

153

- segments: Path segments as sequence

154

155

Returns:

156

Any: Value at path

157

158

Raises:

159

- PathNotFound: If path doesn't exist

160

"""

161

```

162

163

#### Usage Examples

164

165

```python

166

from dpath.segments import match, view, has, get

167

168

data = {

169

"api": {

170

"v1": {"users": ["john", "jane"]},

171

"v2": {"users": ["bob"], "admin": ["alice"]}

172

}

173

}

174

175

# Test pattern matching directly

176

segments = ("api", "v1", "users")

177

pattern = ("api", "*", "users")

178

print(match(segments, pattern)) # True

179

180

pattern2 = ("api", "v2", "admin")

181

print(match(segments, pattern2)) # False

182

183

# Create views with deep copying

184

api_v1_view = view(data, ("api", "v1", "**"))

185

# Returns: {"api": {"v1": {"users": ["john", "jane"]}}}

186

187

users_view = view(data, ("**", "users"))

188

# Returns: {"api": {"v1": {"users": ["john", "jane"]}, "v2": {"users": ["bob"]}}}

189

190

# Path existence checking

191

print(has(data, ("api", "v1", "users"))) # True

192

print(has(data, ("api", "v3", "users"))) # False

193

print(has(data, ("api", "v1", "users", 0))) # True (first user exists)

194

195

# Direct path access

196

users = get(data, ("api", "v1", "users")) # Returns: ["john", "jane"]

197

first_user = get(data, ("api", "v1", "users", 0)) # Returns: "john"

198

```

199

200

### Advanced Path Manipulation

201

202

Low-level path construction and manipulation utilities for implementing custom creators and transformers.

203

204

```python { .api }

205

from dpath.segments import set, extend, types, expand, int_str, _default_creator

206

207

def set(obj, segments, value, creator=_default_creator, hints=()):

208

"""

209

Set value at path, optionally creating missing components.

210

211

Parameters:

212

- obj (MutableMapping): Object to modify

213

- segments: Path segments sequence

214

- value: Value to set

215

- creator (Creator): Function to create missing path components (default _default_creator)

216

- hints (Hints): Type hints for creator function

217

218

Returns:

219

MutableMapping: Modified object

220

"""

221

222

def _default_creator(current, segments, i, hints=()):

223

"""

224

Default creator function that creates dicts or lists based on next segment type.

225

226

Parameters:

227

- current: Current container being modified

228

- segments: Full path segments

229

- i (int): Current segment index

230

- hints (Hints): Type hints for creation

231

232

Creates:

233

- List if next segment is numeric

234

- Dict otherwise

235

"""

236

237

def extend(thing, index, value=None):

238

"""

239

Extend sequence to contain at least index+1 elements.

240

241

Parameters:

242

- thing (MutableSequence): Sequence to extend

243

- index (int): Required minimum index

244

- value: Fill value for new elements (default None)

245

246

Returns:

247

MutableSequence: Extended sequence

248

"""

249

250

def types(obj, segments):

251

"""

252

Get type information for each level of path.

253

254

Parameters:

255

- obj: Object to analyze

256

- segments: Path segments

257

258

Returns:

259

Tuple[Tuple[PathSegment, type], ...]: (segment, type) pairs for each level

260

"""

261

262

def expand(segments):

263

"""

264

Generate progressively longer path prefixes.

265

266

Parameters:

267

- segments: Full path segments

268

269

Yields:

270

Tuple: Path prefixes from shortest to full length

271

"""

272

273

def int_str(segment):

274

"""

275

Convert integer segments to strings.

276

277

Parameters:

278

- segment (PathSegment): Path segment to convert

279

280

Returns:

281

PathSegment: String if input was int, otherwise unchanged

282

"""

283

```

284

285

#### Usage Examples

286

287

```python

288

from dpath.segments import set, extend, types, expand, int_str, _default_creator

289

290

# Use default creator (automatic dict/list selection)

291

data = {}

292

set(data, ("users", 0, "name"), "john") # Uses _default_creator

293

# Creates: {"users": [{"name": "john"}]} - list because next segment is 0

294

295

# Custom creator functions

296

def always_list_creator(current, segments, i, hints=()):

297

"""Creator that always makes lists instead of dicts"""

298

segment = segments[i]

299

if isinstance(current, list):

300

extend(current, segment)

301

current[segment] = []

302

303

# Use custom creator

304

data2 = {}

305

set(data2, ("items", 0, "name"), "first", creator=always_list_creator)

306

# Creates: {"items": [{"name": "first"}]} but with all list structure

307

308

# Extend sequences manually

309

my_list = ["a", "b"]

310

extend(my_list, 5, "empty") # Extends to ["a", "b", "empty", "empty", "empty", "empty"]

311

312

# Analyze path types

313

data = {"users": [{"name": "john", "age": 30}]}

314

path_types = types(data, ("users", 0, "name"))

315

# Returns: (("users", <class 'dict'>), (0, <class 'list'>), ("name", <class 'dict'>))

316

317

# Generate path prefixes

318

for prefix in expand(("a", "b", "c", "d")):

319

print(prefix)

320

# Output:

321

# ("a",)

322

# ("a", "b")

323

# ("a", "b", "c")

324

# ("a", "b", "c", "d")

325

326

# Convert path segments for display

327

mixed_path = ("users", 0, "profile", 1, "email")

328

display_path = "/".join(int_str(seg) for seg in mixed_path)

329

# Returns: "users/0/profile/1/email"

330

```

331

332

### Functional Operations

333

334

Higher-order functions for implementing custom operations over nested structures.

335

336

```python { .api }

337

from dpath.segments import fold, foldm, leaves

338

339

def fold(obj, f, acc):

340

"""

341

Fold (reduce) over all paths in object with read-only access.

342

343

Parameters:

344

- obj: Object to fold over

345

- f: Function(obj, (path_segments, value), accumulator) -> bool|Any

346

- acc: Initial accumulator value

347

348

Returns:

349

Any: Final accumulator value

350

351

Note:

352

If f returns False (exactly), folding stops early.

353

"""

354

355

def foldm(obj, f, acc):

356

"""

357

Fold with mutation support - allows modifying obj during iteration.

358

359

Parameters:

360

- obj: Object to fold over (may be modified)

361

- f: Function(obj, (path_segments, value), accumulator) -> bool|Any

362

- acc: Initial accumulator value

363

364

Returns:

365

Any: Final accumulator value

366

367

Note:

368

Loads all paths into memory first to support safe mutations.

369

"""

370

371

def leaves(obj):

372

"""

373

Generate only leaf (path, value) pairs.

374

375

Parameters:

376

- obj: Object to traverse

377

378

Yields:

379

Tuple[Tuple[PathSegment, ...], Any]: (path_segments, leaf_value) pairs

380

"""

381

```

382

383

#### Usage Examples

384

385

```python

386

from dpath.segments import fold, foldm, leaves

387

388

data = {

389

"users": {

390

"john": {"age": 30, "active": True},

391

"jane": {"age": 25, "active": False}

392

},

393

"settings": {"theme": "dark"}

394

}

395

396

# Count all paths

397

def counter(obj, pair, count):

398

count[0] += 1

399

return True

400

401

total_paths = fold(data, counter, [0])

402

print(f"Total paths: {total_paths[0]}")

403

404

# Find first match with early termination

405

def find_age_30(obj, pair, result):

406

path_segments, value = pair

407

if value == 30:

408

result.append(path_segments)

409

return False # Stop folding

410

return True

411

412

result = fold(data, find_age_30, [])

413

if result:

414

print(f"Found age 30 at: {result[0]}")

415

416

# Mutating fold - deactivate all users

417

def deactivate_users(obj, pair, count):

418

path_segments, value = pair

419

if (isinstance(value, dict) and

420

"active" in value and

421

len(path_segments) >= 2 and

422

path_segments[0] == "users"):

423

value["active"] = False

424

count[0] += 1

425

return True

426

427

changes = foldm(data, deactivate_users, [0])

428

print(f"Deactivated {changes[0]} users")

429

430

# Process only leaf values

431

for path_segments, value in leaves(data):

432

path_str = "/".join(str(seg) for seg in path_segments)

433

print(f"Leaf {path_str}: {value}")

434

435

# Custom aggregations

436

def sum_numeric_leaves(obj, pair, acc):

437

path_segments, value = pair

438

if isinstance(value, (int, float)):

439

acc["sum"] += value

440

acc["count"] += 1

441

return True

442

443

result = fold(data, sum_numeric_leaves, {"sum": 0, "count": 0})

444

if result["count"] > 0:

445

average = result["sum"] / result["count"]

446

print(f"Average numeric value: {average}")

447

```

448

449

## Advanced Integration Patterns

450

451

### Custom Path Operations

452

453

```python

454

# Implement custom search with transformation

455

def transform_search(obj, pattern, transformer):

456

"""Search and transform matching values"""

457

results = {}

458

459

def transform_match(obj, pair, results):

460

path_segments, value = pair

461

if match(path_segments, pattern):

462

transformed = transformer(value)

463

set(results, path_segments, transformed)

464

return True

465

466

fold(obj, transform_match, results)

467

return results

468

469

# Usage

470

def uppercase_strings(value):

471

return value.upper() if isinstance(value, str) else value

472

473

transformed = transform_search(data, ("**",), uppercase_strings)

474

```

475

476

### Performance Optimization

477

478

```python

479

# Early termination patterns

480

def find_first_matching_path(obj, condition):

481

"""Find first path matching condition"""

482

def finder(obj, pair, result):

483

path_segments, value = pair

484

if condition(value):

485

result.append(path_segments)

486

return False # Stop immediately

487

return True

488

489

result = fold(obj, finder, [])

490

return result[0] if result else None

491

492

# Memory-efficient processing

493

def process_large_structure(obj, processor):

494

"""Process structure without loading all paths"""

495

for path_segments, value in walk(obj):

496

if leaf(value):

497

processor(path_segments, value)

498

```