or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/pypi-mergedeep

A deep merge function for Python dictionaries and other mapping objects with configurable merge strategies.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/mergedeep@1.3.x

To install, run

npx @tessl/cli install tessl/pypi-mergedeep@1.3.0

0

# mergedeep

1

2

A deep merge function for Python dictionaries and other mapping objects with configurable merge strategies. This package provides comprehensive deep merging functionality with fine-grained control over how conflicts are resolved, supporting various Python collection types and type safety options.

3

4

## Package Information

5

6

- **Package Name**: mergedeep

7

- **Language**: Python

8

- **Installation**: `pip install mergedeep`

9

- **Minimum Python Version**: 3.6+

10

11

## Core Imports

12

13

```python

14

from mergedeep import merge, Strategy

15

```

16

17

Package-level import:

18

19

```python

20

import mergedeep

21

# Access via mergedeep.merge, mergedeep.Strategy

22

```

23

24

## Basic Usage

25

26

```python

27

from mergedeep import merge, Strategy

28

29

# Basic non-mutating merge

30

a = {"keyA": 1}

31

b = {"keyB": {"sub1": 10}}

32

c = {"keyB": {"sub2": 20}}

33

34

merged = merge({}, a, b, c)

35

print(merged)

36

# {"keyA": 1, "keyB": {"sub1": 10, "sub2": 20}}

37

38

# Mutating merge into existing dict

39

result = {"initial": "data"}

40

merge(result, a, b, c)

41

print(result)

42

# {"initial": "data", "keyA": 1, "keyB": {"sub1": 10, "sub2": 20}}

43

44

# Using different merge strategies

45

dst = {"key": [1, 2]}

46

src = {"key": [3, 4]}

47

48

# Replace strategy (default)

49

merge(dst, src, strategy=Strategy.REPLACE)

50

print(dst) # {"key": [3, 4]}

51

52

# Additive strategy

53

dst = {"key": [1, 2]}

54

merge(dst, src, strategy=Strategy.ADDITIVE)

55

print(dst) # {"key": [1, 2, 3, 4]}

56

```

57

58

## Architecture

59

60

The mergedeep package implements a flexible merge system built around the Strategy pattern and recursive processing:

61

62

### Core Components

63

64

- **Strategy Enumeration**: Defines merge behavior policies (REPLACE, ADDITIVE, TYPESAFE variants)

65

- **Handler Dispatch System**: Maps each strategy to specialized handler functions that implement the merge logic

66

- **Recursive Merge Engine**: The `_deepmerge` function that traverses nested mapping structures

67

- **Type-Aware Processing**: Specialized handling for different Python collection types (list, set, tuple, Counter)

68

69

### Merge Process Flow

70

71

1. **Strategy Selection**: User specifies merge strategy (defaults to REPLACE)

72

2. **Source Iteration**: Multiple source mappings are processed sequentially using `functools.reduce`

73

3. **Key-by-Key Processing**: For each key in source mappings:

74

- If key exists in destination: Apply strategy-specific merge logic

75

- If key is new: Deep copy value from source to destination

76

4. **Recursive Descent**: When both destination and source values are mappings (but not Counter objects), recurse with `_deepmerge`

77

5. **Collection Handling**: Strategy handlers apply type-specific merge operations for lists, sets, tuples, and Counter objects

78

79

### Design Patterns

80

81

- **Strategy Pattern**: Encapsulates merge algorithms in the Strategy enum and handler functions

82

- **Immutability Support**: Uses `copy.deepcopy` to prevent unintended mutations between source and destination

83

- **Type Safety**: Optional type checking prevents accidental type mismatches during merge operations

84

- **Functional Composition**: Uses `functools.reduce` and `functools.partial` for clean handler composition

85

86

This architecture enables mergedeep to handle complex nested data structures while providing fine-grained control over merge behavior through configurable strategies.

87

88

## Capabilities

89

90

### Deep Merge Function

91

92

The core merge function that performs deep merging of multiple source mappings into a destination mapping with configurable strategies.

93

94

```python { .api }

95

def merge(destination: MutableMapping, *sources: Mapping, strategy: Strategy = Strategy.REPLACE) -> MutableMapping:

96

"""

97

A deep merge function for Python dictionaries and mapping objects.

98

99

Parameters:

100

- destination (MutableMapping): The target mapping to merge into

101

- *sources (Mapping): Variable number of source mappings to merge from

102

- strategy (Strategy, optional): The merge strategy to use (defaults to Strategy.REPLACE)

103

104

Returns:

105

MutableMapping: The merged destination mapping (same object as input destination)

106

"""

107

```

108

109

#### Usage Examples

110

111

```python

112

from mergedeep import merge, Strategy

113

from collections import Counter

114

115

# Merging nested dictionaries

116

config = {"database": {"host": "localhost", "port": 5432}}

117

overrides = {"database": {"port": 3306, "ssl": True}}

118

merge(config, overrides)

119

# {"database": {"host": "localhost", "port": 3306, "ssl": True}}

120

121

# Working with different collection types

122

data = {

123

"lists": [1, 2],

124

"sets": {1, 2},

125

"tuples": (1, 2),

126

"counters": Counter({"a": 1, "b": 1})

127

}

128

updates = {

129

"lists": [3, 4],

130

"sets": {3, 4},

131

"tuples": (3, 4),

132

"counters": Counter({"a": 1, "c": 1})

133

}

134

135

# Additive merge combines collections

136

merge(data, updates, strategy=Strategy.ADDITIVE)

137

# {

138

# "lists": [1, 2, 3, 4],

139

# "sets": {1, 2, 3, 4},

140

# "tuples": (1, 2, 3, 4),

141

# "counters": Counter({"a": 2, "b": 1, "c": 1})

142

# }

143

144

# Type-safe merge with error checking

145

try:

146

dst = {"key": [1, 2]}

147

src = {"key": {3, 4}} # Different type (set vs list)

148

merge(dst, src, strategy=Strategy.TYPESAFE_REPLACE)

149

except TypeError as e:

150

print(e) # destination type: <class 'list'> differs from source type: <class 'set'> for key: "key"

151

```

152

153

### Merge Strategies

154

155

Enumeration defining different strategies for handling conflicting keys during merge operations.

156

157

```python { .api }

158

class Strategy(Enum):

159

"""

160

Enumeration of merge strategies for handling conflicts.

161

162

Values:

163

- REPLACE (0): Replace destination value with source value (default)

164

- ADDITIVE (1): Combine collections by extending/updating

165

- TYPESAFE (2): Alias for TYPESAFE_REPLACE

166

- TYPESAFE_REPLACE (3): Raise TypeError if types differ, otherwise REPLACE

167

- TYPESAFE_ADDITIVE (4): Raise TypeError if types differ, otherwise ADDITIVE

168

"""

169

REPLACE = 0

170

ADDITIVE = 1

171

TYPESAFE = 2

172

TYPESAFE_REPLACE = 3

173

TYPESAFE_ADDITIVE = 4

174

```

175

176

#### Strategy Behaviors

177

178

**REPLACE (default)**

179

- When keys exist in both destination and source, replace destination value with source value

180

- With multiple sources, the rightmost (last) source value appears in the merged result

181

- Nested dictionaries are recursively merged

182

183

**ADDITIVE**

184

- Combines collections of the same type:

185

- `list`: extends destination with source items

186

- `set`: updates destination with source items

187

- `tuple`: concatenates tuples

188

- `Counter`: updates counter values

189

- Falls back to REPLACE behavior for non-collection types or type mismatches

190

191

**TYPESAFE_REPLACE (TYPESAFE)**

192

- Raises `TypeError` when destination and source types differ

193

- Otherwise performs REPLACE merge

194

- Ensures type consistency during merge operations

195

196

**TYPESAFE_ADDITIVE**

197

- Raises `TypeError` when destination and source types differ

198

- Otherwise performs ADDITIVE merge

199

- Provides type-safe collection merging

200

201

#### Strategy Usage Examples

202

203

```python

204

from mergedeep import merge, Strategy

205

from collections import Counter

206

207

# Replace strategy examples

208

dst = {"key": [1, 2], "nested": {"a": 1}}

209

src = {"key": [3, 4], "nested": {"b": 2}}

210

merge(dst, src, strategy=Strategy.REPLACE)

211

# {"key": [3, 4], "nested": {"a": 1, "b": 2}} # Lists replaced, dicts merged

212

213

# Additive strategy examples

214

dst = {"numbers": [1, 2], "count": Counter({"x": 1})}

215

src = {"numbers": [3, 4], "count": Counter({"x": 1, "y": 1})}

216

merge(dst, src, strategy=Strategy.ADDITIVE)

217

# {"numbers": [1, 2, 3, 4], "count": Counter({"x": 2, "y": 1})}

218

219

# Type-safe examples

220

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

221

src = {"data": "string"} # Different type

222

try:

223

merge(dst, src, strategy=Strategy.TYPESAFE)

224

except TypeError as e:

225

print(f"Type safety error: {e}")

226

```

227

228

## Error Handling

229

230

The package raises `TypeError` when using type-safe strategies and type mismatches occur:

231

232

```python

233

try:

234

dst = {"key": [1, 2]}

235

src = {"key": {3, 4}} # set instead of list

236

merge(dst, src, strategy=Strategy.TYPESAFE_REPLACE)

237

except TypeError as e:

238

# Error format: 'destination type: <class 'list'> differs from source type: <class 'set'> for key: "key"'

239

print(f"Merge failed: {e}")

240

```

241

242

## Supported Collection Types

243

244

The merge function supports these Python collection types:

245

246

- **dict** and other `Mapping` types: Recursive deep merge

247

- **list**: Extend destination with source items (ADDITIVE mode)

248

- **tuple**: Concatenate tuples (ADDITIVE mode)

249

- **set**: Update destination with source items (ADDITIVE mode)

250

- **Counter**: Update counter values, with special handling for nested Counter objects

251

252

## Package Constants

253

254

### Version Information

255

256

```python { .api }

257

__version__: str

258

# Package version string, currently "1.3.4"

259

# Usage: from mergedeep import __version__

260

```

261

262

## Types

263

264

```python { .api }

265

from typing import MutableMapping, Mapping

266

from enum import Enum

267

from collections import Counter

268

269

# Core function signature uses these types

270

MutableMapping # For destination parameter

271

Mapping # For source parameters

272

Enum # Base class for Strategy

273

Counter # Supported collection type

274

```

275

276

## Advanced Usage Patterns

277

278

### Configuration Management

279

280

```python

281

from mergedeep import merge

282

283

# Base configuration

284

base_config = {

285

"database": {"host": "localhost", "port": 5432, "ssl": False},

286

"cache": {"ttl": 300, "size": 1000},

287

"features": ["logging", "monitoring"]

288

}

289

290

# Environment-specific overrides

291

production_config = {

292

"database": {"host": "prod.db.com", "ssl": True},

293

"cache": {"size": 10000},

294

"features": ["logging", "monitoring", "analytics"]

295

}

296

297

# Merge configurations

298

final_config = merge({}, base_config, production_config)

299

```

300

301

### Data Processing Pipelines

302

303

```python

304

from mergedeep import merge, Strategy

305

from collections import Counter

306

307

# Aggregating results from multiple sources

308

results = [

309

{"metrics": Counter({"success": 10, "error": 2}), "data": [1, 2, 3]},

310

{"metrics": Counter({"success": 15, "error": 1}), "data": [4, 5, 6]},

311

{"metrics": Counter({"success": 8, "error": 3}), "data": [7, 8, 9]}

312

]

313

314

# Combine all results

315

aggregated = {}

316

for result in results:

317

merge(aggregated, result, strategy=Strategy.ADDITIVE)

318

319

# aggregated = {

320

# "metrics": Counter({"success": 33, "error": 6}),

321

# "data": [1, 2, 3, 4, 5, 6, 7, 8, 9]

322

# }

323

```

324

325

### API Response Merging

326

327

```python

328

from mergedeep import merge

329

330

# Merging paginated API responses

331

page1 = {"users": [{"id": 1, "name": "Alice"}], "pagination": {"page": 1, "total": 100}}

332

page2 = {"users": [{"id": 2, "name": "Bob"}], "pagination": {"page": 2, "total": 100}}

333

334

# Combine user data while preserving pagination info

335

combined = merge({}, page1)

336

merge(combined["users"], {"users": page2["users"]}, strategy=Strategy.ADDITIVE)

337

merge(combined, {"pagination": page2["pagination"]})

338

```