89 lines
1.9 KiB
Python
89 lines
1.9 KiB
Python
|
# vim:fileencoding=utf-8:noet
|
||
|
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||
|
|
||
|
|
||
|
REMOVE_THIS_KEY = object()
|
||
|
|
||
|
|
||
|
def mergeargs(argvalue, remove=False):
|
||
|
if not argvalue:
|
||
|
return None
|
||
|
r = {}
|
||
|
for subval in argvalue:
|
||
|
mergedicts(r, dict([subval]), remove=remove)
|
||
|
return r
|
||
|
|
||
|
|
||
|
def _clear_special_values(d):
|
||
|
'''Remove REMOVE_THIS_KEY values from dictionary
|
||
|
'''
|
||
|
l = [d]
|
||
|
while l:
|
||
|
i = l.pop()
|
||
|
pops = []
|
||
|
for k, v in i.items():
|
||
|
if v is REMOVE_THIS_KEY:
|
||
|
pops.append(k)
|
||
|
elif isinstance(v, dict):
|
||
|
l.append(v)
|
||
|
for k in pops:
|
||
|
i.pop(k)
|
||
|
|
||
|
|
||
|
def mergedicts(d1, d2, remove=True):
|
||
|
'''Recursively merge two dictionaries
|
||
|
|
||
|
First dictionary is modified in-place.
|
||
|
'''
|
||
|
_setmerged(d1, d2)
|
||
|
for k in d2:
|
||
|
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
|
||
|
mergedicts(d1[k], d2[k], remove)
|
||
|
elif remove and d2[k] is REMOVE_THIS_KEY:
|
||
|
d1.pop(k, None)
|
||
|
else:
|
||
|
if remove and isinstance(d2[k], dict):
|
||
|
_clear_special_values(d2[k])
|
||
|
d1[k] = d2[k]
|
||
|
|
||
|
|
||
|
def mergedefaults(d1, d2):
|
||
|
'''Recursively merge two dictionaries, keeping existing values
|
||
|
|
||
|
First dictionary is modified in-place.
|
||
|
'''
|
||
|
for k in d2:
|
||
|
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
|
||
|
mergedefaults(d1[k], d2[k])
|
||
|
else:
|
||
|
d1.setdefault(k, d2[k])
|
||
|
|
||
|
|
||
|
def _setmerged(d1, d2):
|
||
|
if hasattr(d1, 'setmerged'):
|
||
|
d1.setmerged(d2)
|
||
|
|
||
|
|
||
|
def mergedicts_copy(d1, d2):
|
||
|
'''Recursively merge two dictionaries.
|
||
|
|
||
|
Dictionaries are not modified. Copying happens only if necessary. Assumes
|
||
|
that first dictionary supports .copy() method.
|
||
|
'''
|
||
|
ret = d1.copy()
|
||
|
_setmerged(ret, d2)
|
||
|
for k in d2:
|
||
|
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
|
||
|
ret[k] = mergedicts_copy(d1[k], d2[k])
|
||
|
else:
|
||
|
ret[k] = d2[k]
|
||
|
return ret
|
||
|
|
||
|
|
||
|
def updated(d, *args, **kwargs):
|
||
|
'''Copy dictionary and update it with provided arguments
|
||
|
'''
|
||
|
d = d.copy()
|
||
|
d.update(*args, **kwargs)
|
||
|
return d
|