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

data-manipulation.mddocs/

0

# Data Manipulation

1

2

Operations for modifying dictionary structures including selective deletion and sophisticated deep merging with configurable behavior for different data integration scenarios.

3

4

## Capabilities

5

6

### Deletion Operations

7

8

Remove elements from nested dictionaries using glob patterns with support for filtering and preservation of data structure integrity.

9

10

```python { .api }

11

def delete(obj, glob, separator="/", afilter=None):

12

"""

13

Delete all elements matching glob pattern.

14

15

Parameters:

16

- obj (MutableMapping): Target dictionary to modify

17

- glob (Glob): Path pattern as string or sequence

18

- separator (str): Path separator character (default "/")

19

- afilter (Filter): Optional function to filter which elements to delete

20

21

Returns:

22

int: Number of elements deleted

23

24

Raises:

25

- PathNotFound: If no matching paths found to delete

26

"""

27

```

28

29

#### Usage Examples

30

31

```python

32

import dpath

33

from dpath.exceptions import PathNotFound

34

35

data = {

36

"users": {

37

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

38

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

39

"bob": {"age": 35, "active": True}

40

},

41

"temp_settings": {"cache": True},

42

"permanent_settings": {"theme": "dark"}

43

}

44

45

# Delete exact path

46

count = dpath.delete(data, "users/john/temp_data") # Returns: 1

47

# Removes temp_data from john's record

48

49

# Delete with wildcards - removes matching fields from all users

50

count = dpath.delete(data, "users/*/temp_data") # Returns: 2 (john and jane)

51

52

# Delete entire user records

53

count = dpath.delete(data, "users/jane") # Returns: 1

54

# Removes jane's entire record

55

56

# Delete with filter - only delete inactive users

57

def inactive_filter(user):

58

return isinstance(user, dict) and not user.get("active", True)

59

60

count = dpath.delete(data, "users/*", afilter=inactive_filter)

61

# Only deletes users where active=False

62

63

# Delete all temporary data across entire structure

64

count = dpath.delete(data, "**/temp_*") # Matches any key starting with "temp_"

65

66

# Handle deletion errors

67

try:

68

dpath.delete(data, "nonexistent/path")

69

except PathNotFound as e:

70

print(f"Nothing to delete: {e}")

71

72

# Delete list elements

73

list_data = {"items": ["a", "b", "c", "d"]}

74

count = dpath.delete(list_data, "items/1") # Removes "b"

75

# Note: List behavior depends on position - middle elements become None

76

```

77

78

### Merge Operations

79

80

Deeply merge dictionaries with sophisticated control over how conflicts are resolved and data is combined.

81

82

```python { .api }

83

def merge(dst, src, separator="/", afilter=None, flags=MergeType.ADDITIVE):

84

"""

85

Deep merge source into destination dictionary.

86

87

Parameters:

88

- dst (MutableMapping): Destination dictionary (modified in place)

89

- src (MutableMapping): Source dictionary to merge from

90

- separator (str): Path separator for filtered merging (default "/")

91

- afilter (Filter): Optional function to filter which parts of src to merge

92

- flags (MergeType): Merge behavior flags (default MergeType.ADDITIVE)

93

94

Returns:

95

MutableMapping: The modified destination dictionary

96

97

Note:

98

Creates references, not deep copies. Source objects may be modified

99

by subsequent operations on the destination.

100

"""

101

```

102

103

#### Merge Behavior Flags

104

105

```python { .api }

106

from dpath.types import MergeType

107

108

class MergeType(IntFlag):

109

ADDITIVE = auto() # Combine lists by concatenation (default)

110

REPLACE = auto() # Replace destination lists with source lists

111

TYPESAFE = auto() # Raise TypeError when merging incompatible types

112

```

113

114

#### Usage Examples

115

116

```python

117

import dpath

118

from dpath.types import MergeType

119

120

# Basic merge - combines dictionaries recursively

121

dst = {

122

"users": {"john": {"age": 30}},

123

"settings": {"theme": "light"}

124

}

125

126

src = {

127

"users": {"jane": {"age": 25}, "john": {"city": "NYC"}},

128

"settings": {"lang": "en"}

129

}

130

131

dpath.merge(dst, src)

132

# Result: {

133

# "users": {"john": {"age": 30, "city": "NYC"}, "jane": {"age": 25}},

134

# "settings": {"theme": "light", "lang": "en"}

135

# }

136

137

# List merging with ADDITIVE (default)

138

dst = {"tags": ["python", "data"]}

139

src = {"tags": ["analysis", "ml"]}

140

dpath.merge(dst, src) # tags becomes ["python", "data", "analysis", "ml"]

141

142

# List merging with REPLACE

143

dst = {"tags": ["python", "data"]}

144

src = {"tags": ["analysis", "ml"]}

145

dpath.merge(dst, src, flags=MergeType.REPLACE) # tags becomes ["analysis", "ml"]

146

147

# Type-safe merging

148

dst = {"count": 10}

149

src = {"count": "ten"} # String instead of int

150

151

try:

152

dpath.merge(dst, src, flags=MergeType.TYPESAFE)

153

except TypeError as e:

154

print(f"Type mismatch: {e}")

155

156

# Filtered merging - only merge specific parts

157

def settings_filter(value):

158

# Only merge settings, not user data

159

return True # Apply filter logic here

160

161

filtered_src = dpath.search(src, "settings/**")

162

dpath.merge(dst, filtered_src)

163

164

# Combined flags

165

dpath.merge(dst, src, flags=MergeType.REPLACE | MergeType.TYPESAFE)

166

```

167

168

### Advanced Deletion Patterns

169

170

#### Smart List Deletion

171

172

```python

173

# List deletion preserves order for end elements

174

data = {"items": ["a", "b", "c", "d", "e"]}

175

176

# Deleting last element truly removes it

177

dpath.delete(data, "items/-1") # or "items/4"

178

# Result: ["a", "b", "c", "d"]

179

180

# Deleting middle elements sets to None to preserve indices

181

dpath.delete(data, "items/1")

182

# Result: ["a", None, "c", "d", "e"]

183

184

# Delete multiple list elements

185

for i in reversed(range(1, 4)): # Delete backwards to maintain indices

186

dpath.delete(data, f"items/{i}")

187

```

188

189

#### Conditional Deletion

190

191

```python

192

# Delete based on value properties

193

data = {

194

"products": {

195

"item1": {"price": 10, "discontinued": True},

196

"item2": {"price": 25, "discontinued": False},

197

"item3": {"price": 15, "discontinued": True}

198

}

199

}

200

201

# Delete discontinued products

202

def discontinued_filter(product):

203

return isinstance(product, dict) and product.get("discontinued", False)

204

205

count = dpath.delete(data, "products/*", afilter=discontinued_filter)

206

# Removes item1 and item3

207

208

# Delete based on value ranges

209

def expensive_filter(product):

210

return isinstance(product, dict) and product.get("price", 0) > 20

211

212

count = dpath.delete(data, "products/*", afilter=expensive_filter)

213

```

214

215

### Advanced Merge Scenarios

216

217

#### Merging with Deep Copy Prevention

218

219

```python

220

import copy

221

222

# Problem: Merge creates references

223

dst = {"data": {"list": [1, 2]}}

224

src = {"data": {"list": [3, 4]}}

225

226

dpath.merge(dst, src) # dst["data"]["list"] now references src's list

227

src["data"]["list"].append(5) # This also affects dst!

228

229

# Solution: Deep copy source before merging

230

src_copy = copy.deepcopy(src)

231

dpath.merge(dst, src_copy) # Now changes to src won't affect dst

232

```

233

234

#### Complex Merge Workflows

235

236

```python

237

# Multi-source merging with different behaviors

238

base_config = {"database": {"host": "localhost"}}

239

240

# Merge environment-specific overrides

241

env_config = {"database": {"port": 5432}}

242

dpath.merge(base_config, env_config)

243

244

# Merge user preferences with replacement for UI settings

245

user_config = {"ui": {"theme": "dark", "panels": ["editor", "terminal"]}}

246

dpath.merge(base_config, user_config, flags=MergeType.REPLACE)

247

248

# Merge runtime settings type-safely

249

runtime_config = {"database": {"timeout": 30}}

250

dpath.merge(base_config, runtime_config, flags=MergeType.TYPESAFE)

251

```

252

253

#### Selective Merging

254

255

```python

256

# Merge only specific branches

257

def merge_branch(dst, src, branch_pattern):

258

"""Merge only specific branches of source into destination"""

259

branch_data = dpath.search(src, branch_pattern)

260

dpath.merge(dst, branch_data)

261

262

# Usage

263

merge_branch(dst, src, "settings/**") # Only merge settings branch

264

merge_branch(dst, src, "users/*/profile") # Only merge user profiles

265

```

266

267

## Error Handling and Edge Cases

268

269

```python

270

from dpath.exceptions import PathNotFound, InvalidKeyName

271

272

# Handle empty string keys (requires option)

273

import dpath.options

274

dpath.options.ALLOW_EMPTY_STRING_KEYS = True

275

276

data = {"": "empty key value"} # Now allowed

277

278

# Handle deletion of non-existent paths

279

try:

280

dpath.delete(data, "path/that/does/not/exist")

281

except PathNotFound:

282

print("Nothing to delete")

283

284

# Handle invalid key names

285

try:

286

dpath.new(data, "path/with//empty/segment", "value")

287

except InvalidKeyName as e:

288

print(f"Invalid key: {e}")

289

290

# Merge type conflicts

291

dst = {"value": [1, 2, 3]}

292

src = {"value": {"nested": "dict"}}

293

294

# This will replace the list with dict (default behavior)

295

dpath.merge(dst, src) # dst["value"] becomes {"nested": "dict"}

296

```