mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-12-25 17:27:01 +00:00
Add generic dictionary merge routine.
- Poached from YamlUtils. - YamlUtils should be updated to use this as the base merge routine.
This commit is contained in:
@@ -18,3 +18,74 @@ class OnlServiceMixin(object):
|
||||
self.logger.critical(msg)
|
||||
raise klass(msg)
|
||||
|
||||
|
||||
def dmerge(d1, d2):
|
||||
"""
|
||||
dictionary merge.
|
||||
|
||||
d1 is the default source. Leaf values from d2 will override.
|
||||
|
||||
d1 is the 'default' source; leaf values from d2 will override.
|
||||
Returns the merged tree.
|
||||
|
||||
Set a leaf in d2 to None to create a tombstone (discard any key
|
||||
from d1).
|
||||
|
||||
if a (sub) key in d1, d2 differ in type (dict vs. non-dict) then
|
||||
the merge will proceed with the non-dict promoted to a dict using
|
||||
the default-key schema ('='). Consumers of this function should be
|
||||
prepared to handle such keys.
|
||||
"""
|
||||
merged = {}
|
||||
q = [(d1, d2, merged)]
|
||||
while True:
|
||||
if not q: break
|
||||
c1, c2, c3 = q.pop(0)
|
||||
# add in non-overlapping keys
|
||||
# 'None' keys from p2 are tombstones
|
||||
s1 = set(c1.keys())
|
||||
s2 = set(c2.keys())
|
||||
|
||||
for k in s1.difference(s2):
|
||||
v = c1[k]
|
||||
if type(v) == dict:
|
||||
c3.setdefault(k, {})
|
||||
q.append((v, {}, c3[k],))
|
||||
else:
|
||||
c3.setdefault(k, v)
|
||||
|
||||
for k in s2.difference(s1):
|
||||
v = c2[k]
|
||||
if v is None: continue
|
||||
if type(v) == dict:
|
||||
c3.setdefault(k, {})
|
||||
q.append(({}, v, c3[k],))
|
||||
else:
|
||||
c3.setdefault(k, v)
|
||||
|
||||
# handle overlapping keys
|
||||
for k in s1.intersection(s2):
|
||||
v1 = c1[k]
|
||||
v2 = c2[k]
|
||||
|
||||
if v2 is None: continue
|
||||
|
||||
# two dicts, key-by-key reconciliation required
|
||||
if type(v1) == dict and type(v2) == dict:
|
||||
c3.setdefault(k, {})
|
||||
q.append((v1, v2, c3[k],))
|
||||
continue
|
||||
|
||||
# two non-dicts, p2 wins
|
||||
if type(v1) != dict and type(v2) != dict:
|
||||
c3[k] = v2
|
||||
continue
|
||||
|
||||
if type(v1) != dict:
|
||||
v1 = { '=' : v1, }
|
||||
if type(v2) != dict:
|
||||
v2 = { '=' : v2, }
|
||||
c3.setdefault(k, {})
|
||||
q.append((v1, v2, c3[k],))
|
||||
|
||||
return merged
|
||||
|
||||
Reference in New Issue
Block a user