Skip to content

Commit

Permalink
fix: make predefined merge strategies work with primitive collections…
Browse files Browse the repository at this point in the history
… subtypes (#25)

Currently the predefined merge strategies for dicts, lists and sets are not being applied when the objects to be merged are different subtypes of those base types.

For instance, two dicts can be merged. Even a dict with an OrderedDict, or viceversa. But an OrderedDict and a defaultdict are treated as two completely different types and the conflict strategy is applied, although they could perfectly be merged as dicts, as they are both subtypes of dict and behave as such.
  • Loading branch information
pabloge committed Dec 18, 2023
1 parent 48cc8cb commit 98ec8c1
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 3 deletions.
6 changes: 3 additions & 3 deletions deepmerge/merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ def type_conflict_strategy(self, *args):
return self._type_conflict_strategy(self, *args)

def value_strategy(self, path, base, nxt):
if not (isinstance(base, type(nxt)) or isinstance(nxt, type(base))):
return self.type_conflict_strategy(path, base, nxt)
for typ, strategy in self._type_strategies:
if isinstance(nxt, typ):
if isinstance(base, typ) and isinstance(nxt, typ):
return strategy(self, path, base, nxt)
if not (isinstance(base, type(nxt)) or isinstance(nxt, type(base))):
return self.type_conflict_strategy(path, base, nxt)
return self._fallback_strategy(self, path, base, nxt)
10 changes: 10 additions & 0 deletions deepmerge/tests/test_full.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from deepmerge.exception import *
from collections import OrderedDict, defaultdict
import pytest


Expand Down Expand Up @@ -48,3 +49,12 @@ def test_example():
always_merger.merge(base, next)

assert base == {"foo": "value", "bar": "value2", "baz": ["a", "b"]}


def test_subtypes():
base = OrderedDict({"foo": "value", "baz": ["a"]})
next = defaultdict(str, {"bar": "value2", "baz": ["b"]})

result = always_merger.merge(base, next)

assert dict(result) == {"foo": "value", "bar": "value2", "baz": ["a", "b"]}

0 comments on commit 98ec8c1

Please sign in to comment.