mirror of
https://github.com/status-im/spiff-arena.git
synced 2025-01-15 04:34:16 +00:00
46 lines
1.8 KiB
Python
46 lines
1.8 KiB
Python
|
class DeepMerge(object):
|
||
|
# Merges two deeply nested json-like dictionaries,
|
||
|
# useful for updating things like task data.
|
||
|
# I know in my heart, that this isn't completely correct.
|
||
|
# But I don't want to create a dependency, and this is passing
|
||
|
# all the failure points I've found so far. So I'll just
|
||
|
# keep plugging away at it.
|
||
|
# This will merge all updates from b into a, but it does not
|
||
|
# remove items from a that are not in b. Passing a prune of
|
||
|
# true, and it WILL remove items in a that are not in b.
|
||
|
|
||
|
@staticmethod
|
||
|
def merge(a, b, path=None):
|
||
|
"merges b into a"
|
||
|
if path is None: path = []
|
||
|
for key in b:
|
||
|
if key in a:
|
||
|
if a[key] == b[key]:
|
||
|
continue
|
||
|
elif isinstance(a[key], dict) and isinstance(b[key], dict):
|
||
|
DeepMerge.merge(a[key], b[key], path + [str(key)])
|
||
|
elif isinstance(a[key], list) and isinstance(b[key], list):
|
||
|
DeepMerge.merge_array(a[key], b[key], path + [str(key)])
|
||
|
else:
|
||
|
a[key] = b[key] # Just overwrite the value in a.
|
||
|
else:
|
||
|
a[key] = b[key]
|
||
|
return a
|
||
|
|
||
|
@staticmethod
|
||
|
def merge_array(a, b, path=None):
|
||
|
|
||
|
for idx, val in enumerate(b):
|
||
|
if isinstance(b[idx], dict): # Recurse back on dictionaries.
|
||
|
# If lists of dictionaries get out of order, this might
|
||
|
# cause us some pain.
|
||
|
if len(a) > idx:
|
||
|
a[idx] = DeepMerge.merge(a[idx], b[idx], path + [str(idx)])
|
||
|
else:
|
||
|
a.append(b[idx])
|
||
|
else: # Just merge whatever it is back in.
|
||
|
a.extend(x for x in b if x not in a)
|
||
|
|
||
|
# Trim a back to the length of b. In the end, the two arrays should match
|
||
|
del a[len(b):]
|