@@ -28,16 +28,8 @@ def deep_merge(*dcts: Mapping[str, Any]) -> dict[str, Any]:
2828 if not dcts :
2929 return {}
3030
31- # Initial deep copy of the base dictionary
3231 result = deepcopy (dict (dcts [0 ]))
3332
34- # Handlers for specific types (excluding Mapping which needs special handling)
35- funcmap = {
36- (list , list ): lambda e , v : e + deepcopy (v ),
37- (tuple , tuple ): lambda e , v : e + deepcopy (v ),
38- (set , set ): lambda e , v : e | deepcopy (v ),
39- }
40-
4133 for src in dcts [1 :]:
4234 stack : list [tuple [dict [str , Any ], Mapping [str , Any ]]] = [(result , src )]
4335
@@ -51,19 +43,26 @@ def deep_merge(*dcts: Mapping[str, Any]) -> dict[str, Any]:
5143
5244 existing = dest [key ]
5345
54- # Special handling for Mappings (recursive merge)
46+ # Mapping → merge deeper
5547 if isinstance (existing , Mapping ) and isinstance (value , Mapping ):
48+ # Ensure we are working with a dict for the merge target
49+ # This avoids nested specialized types if they support item assignment
5650 if type (existing ) is not dict :
5751 existing = dict (existing )
5852 dest [key ] = existing
5953 stack .append ((existing , value ))
60- continue
6154
62- # Use funcmap for other types
63- # Using get() on dict with tuple key avoids the loop
64- handler = funcmap .get ((type (existing ), type (value )))
65- if handler :
66- dest [key ] = handler (existing , value )
55+ # Lists / tuples → concatenate
56+ elif (isinstance (existing , list ) and isinstance (value , list )) or (
57+ isinstance (existing , tuple ) and isinstance (value , tuple )
58+ ):
59+ dest [key ] = existing + deepcopy (value ) # type: ignore[operator]
60+
61+ # Sets → union
62+ elif isinstance (existing , set ) and isinstance (value , set ):
63+ dest [key ] = existing | deepcopy (value )
64+
65+ # Fallback → overwrite
6766 else :
6867 dest [key ] = deepcopy (value )
6968
0 commit comments