or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

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

index.mddocs/

mergedeep

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.

Package Information

  • Package Name: mergedeep
  • Language: Python
  • Installation: pip install mergedeep
  • Minimum Python Version: 3.6+

Core Imports

from mergedeep import merge, Strategy

Package-level import:

import mergedeep
# Access via mergedeep.merge, mergedeep.Strategy

Basic Usage

from mergedeep import merge, Strategy

# Basic non-mutating merge
a = {"keyA": 1}
b = {"keyB": {"sub1": 10}}
c = {"keyB": {"sub2": 20}}

merged = merge({}, a, b, c)
print(merged)
# {"keyA": 1, "keyB": {"sub1": 10, "sub2": 20}}

# Mutating merge into existing dict
result = {"initial": "data"}
merge(result, a, b, c)
print(result)
# {"initial": "data", "keyA": 1, "keyB": {"sub1": 10, "sub2": 20}}

# Using different merge strategies
dst = {"key": [1, 2]}
src = {"key": [3, 4]}

# Replace strategy (default)
merge(dst, src, strategy=Strategy.REPLACE)
print(dst)  # {"key": [3, 4]}

# Additive strategy
dst = {"key": [1, 2]}
merge(dst, src, strategy=Strategy.ADDITIVE)
print(dst)  # {"key": [1, 2, 3, 4]}

Architecture

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

Core Components

  • Strategy Enumeration: Defines merge behavior policies (REPLACE, ADDITIVE, TYPESAFE variants)
  • Handler Dispatch System: Maps each strategy to specialized handler functions that implement the merge logic
  • Recursive Merge Engine: The _deepmerge function that traverses nested mapping structures
  • Type-Aware Processing: Specialized handling for different Python collection types (list, set, tuple, Counter)

Merge Process Flow

  1. Strategy Selection: User specifies merge strategy (defaults to REPLACE)
  2. Source Iteration: Multiple source mappings are processed sequentially using functools.reduce
  3. Key-by-Key Processing: For each key in source mappings:
    • If key exists in destination: Apply strategy-specific merge logic
    • If key is new: Deep copy value from source to destination
  4. Recursive Descent: When both destination and source values are mappings (but not Counter objects), recurse with _deepmerge
  5. Collection Handling: Strategy handlers apply type-specific merge operations for lists, sets, tuples, and Counter objects

Design Patterns

  • Strategy Pattern: Encapsulates merge algorithms in the Strategy enum and handler functions
  • Immutability Support: Uses copy.deepcopy to prevent unintended mutations between source and destination
  • Type Safety: Optional type checking prevents accidental type mismatches during merge operations
  • Functional Composition: Uses functools.reduce and functools.partial for clean handler composition

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

Capabilities

Deep Merge Function

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

def merge(destination: MutableMapping, *sources: Mapping, strategy: Strategy = Strategy.REPLACE) -> MutableMapping:
    """
    A deep merge function for Python dictionaries and mapping objects.

    Parameters:
    - destination (MutableMapping): The target mapping to merge into
    - *sources (Mapping): Variable number of source mappings to merge from
    - strategy (Strategy, optional): The merge strategy to use (defaults to Strategy.REPLACE)

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

Usage Examples

from mergedeep import merge, Strategy
from collections import Counter

# Merging nested dictionaries
config = {"database": {"host": "localhost", "port": 5432}}
overrides = {"database": {"port": 3306, "ssl": True}}
merge(config, overrides)
# {"database": {"host": "localhost", "port": 3306, "ssl": True}}

# Working with different collection types
data = {
    "lists": [1, 2],
    "sets": {1, 2},
    "tuples": (1, 2),
    "counters": Counter({"a": 1, "b": 1})
}
updates = {
    "lists": [3, 4],
    "sets": {3, 4},
    "tuples": (3, 4),
    "counters": Counter({"a": 1, "c": 1})
}

# Additive merge combines collections
merge(data, updates, strategy=Strategy.ADDITIVE)
# {
#   "lists": [1, 2, 3, 4],
#   "sets": {1, 2, 3, 4},
#   "tuples": (1, 2, 3, 4),
#   "counters": Counter({"a": 2, "b": 1, "c": 1})
# }

# Type-safe merge with error checking
try:
    dst = {"key": [1, 2]}
    src = {"key": {3, 4}}  # Different type (set vs list)
    merge(dst, src, strategy=Strategy.TYPESAFE_REPLACE)
except TypeError as e:
    print(e)  # destination type: <class 'list'> differs from source type: <class 'set'> for key: "key"

Merge Strategies

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

class Strategy(Enum):
    """
    Enumeration of merge strategies for handling conflicts.
    
    Values:
    - REPLACE (0): Replace destination value with source value (default)
    - ADDITIVE (1): Combine collections by extending/updating
    - TYPESAFE (2): Alias for TYPESAFE_REPLACE
    - TYPESAFE_REPLACE (3): Raise TypeError if types differ, otherwise REPLACE
    - TYPESAFE_ADDITIVE (4): Raise TypeError if types differ, otherwise ADDITIVE
    """
    REPLACE = 0
    ADDITIVE = 1
    TYPESAFE = 2
    TYPESAFE_REPLACE = 3
    TYPESAFE_ADDITIVE = 4

Strategy Behaviors

REPLACE (default)

  • When keys exist in both destination and source, replace destination value with source value
  • With multiple sources, the rightmost (last) source value appears in the merged result
  • Nested dictionaries are recursively merged

ADDITIVE

  • Combines collections of the same type:
    • list: extends destination with source items
    • set: updates destination with source items
    • tuple: concatenates tuples
    • Counter: updates counter values
  • Falls back to REPLACE behavior for non-collection types or type mismatches

TYPESAFE_REPLACE (TYPESAFE)

  • Raises TypeError when destination and source types differ
  • Otherwise performs REPLACE merge
  • Ensures type consistency during merge operations

TYPESAFE_ADDITIVE

  • Raises TypeError when destination and source types differ
  • Otherwise performs ADDITIVE merge
  • Provides type-safe collection merging

Strategy Usage Examples

from mergedeep import merge, Strategy
from collections import Counter

# Replace strategy examples
dst = {"key": [1, 2], "nested": {"a": 1}}
src = {"key": [3, 4], "nested": {"b": 2}}
merge(dst, src, strategy=Strategy.REPLACE)
# {"key": [3, 4], "nested": {"a": 1, "b": 2}}  # Lists replaced, dicts merged

# Additive strategy examples
dst = {"numbers": [1, 2], "count": Counter({"x": 1})}
src = {"numbers": [3, 4], "count": Counter({"x": 1, "y": 1})}
merge(dst, src, strategy=Strategy.ADDITIVE)
# {"numbers": [1, 2, 3, 4], "count": Counter({"x": 2, "y": 1})}

# Type-safe examples
dst = {"data": [1, 2]}
src = {"data": "string"}  # Different type
try:
    merge(dst, src, strategy=Strategy.TYPESAFE)
except TypeError as e:
    print(f"Type safety error: {e}")

Error Handling

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

try:
    dst = {"key": [1, 2]}
    src = {"key": {3, 4}}  # set instead of list
    merge(dst, src, strategy=Strategy.TYPESAFE_REPLACE)
except TypeError as e:
    # Error format: 'destination type: <class 'list'> differs from source type: <class 'set'> for key: "key"'
    print(f"Merge failed: {e}")

Supported Collection Types

The merge function supports these Python collection types:

  • dict and other Mapping types: Recursive deep merge
  • list: Extend destination with source items (ADDITIVE mode)
  • tuple: Concatenate tuples (ADDITIVE mode)
  • set: Update destination with source items (ADDITIVE mode)
  • Counter: Update counter values, with special handling for nested Counter objects

Package Constants

Version Information

__version__: str
# Package version string, currently "1.3.4"
# Usage: from mergedeep import __version__

Types

from typing import MutableMapping, Mapping
from enum import Enum
from collections import Counter

# Core function signature uses these types
MutableMapping  # For destination parameter
Mapping         # For source parameters
Enum           # Base class for Strategy
Counter        # Supported collection type

Advanced Usage Patterns

Configuration Management

from mergedeep import merge

# Base configuration
base_config = {
    "database": {"host": "localhost", "port": 5432, "ssl": False},
    "cache": {"ttl": 300, "size": 1000},
    "features": ["logging", "monitoring"]
}

# Environment-specific overrides
production_config = {
    "database": {"host": "prod.db.com", "ssl": True},
    "cache": {"size": 10000},
    "features": ["logging", "monitoring", "analytics"]
}

# Merge configurations
final_config = merge({}, base_config, production_config)

Data Processing Pipelines

from mergedeep import merge, Strategy
from collections import Counter

# Aggregating results from multiple sources
results = [
    {"metrics": Counter({"success": 10, "error": 2}), "data": [1, 2, 3]},
    {"metrics": Counter({"success": 15, "error": 1}), "data": [4, 5, 6]},
    {"metrics": Counter({"success": 8, "error": 3}), "data": [7, 8, 9]}
]

# Combine all results
aggregated = {}
for result in results:
    merge(aggregated, result, strategy=Strategy.ADDITIVE)

# aggregated = {
#   "metrics": Counter({"success": 33, "error": 6}),
#   "data": [1, 2, 3, 4, 5, 6, 7, 8, 9]
# }

API Response Merging

from mergedeep import merge

# Merging paginated API responses
page1 = {"users": [{"id": 1, "name": "Alice"}], "pagination": {"page": 1, "total": 100}}
page2 = {"users": [{"id": 2, "name": "Bob"}], "pagination": {"page": 2, "total": 100}}

# Combine user data while preserving pagination info
combined = merge({}, page1)
merge(combined["users"], {"users": page2["users"]}, strategy=Strategy.ADDITIVE)
merge(combined, {"pagination": page2["pagination"]})