Jon Herron 7c219fd731 Squashed 'SpiffWorkflow/' content from commit 63db3e4
git-subtree-dir: SpiffWorkflow
git-subtree-split: 63db3e45947ec66b8d0efc2c74064004f8ff482c
2022-10-12 10:19:53 -04:00

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):]