Created
November 1, 2018 17:15
-
-
Save LexVocoder/05522ae9098cbb9118bcbe53539b4622 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is experimental! | |
def type_as_str(v): | |
return type(v).__name__ | |
def deep_merge_mappings(a, b, *rest, sequence_behavior='append'): | |
""" | |
merges b into a and return merged result | |
sequence_behavior - specifies what happens if a & b are (or contain) non-string sequences. It must be one of the following: | |
'append': modifies a, appending b to it | |
'clobber': overwrites a with b | |
'error': raises TypeError in this situation | |
NOTE: tuples and arbitrary objects are not handled as it is totally ambiguous what should happen | |
""" | |
def helper(path, parameter_number, a, b, *rest): | |
def raise_type_error(): | |
raise TypeError('cannot merge {type_as_str(b)} into {type_as_str(a)} in parameter {parameter_number}, path {path}'.format({ | |
path=path, parameter_number=parameter_number, a=a, b=b | |
})) | |
key = None | |
# ## debug output | |
# sys.stderr.write("DEBUG: %s to %s\n" %(b,a)) | |
try: | |
if a is None or isinstance(a, str) or isinstance(a, unicode) or isinstance(a, int) or isinstance(a, long) or isinstance(a, float): | |
# border case for first run or if a is a primitive | |
a = b | |
elif isinstance(a, list): | |
if sequence_behavior == 'append': | |
# lists can be only appended | |
if isinstance(b, list): | |
# merge lists | |
a.extend(b) | |
else: | |
# append to list | |
a.append(b) | |
elif sequence_behavior == 'clobber': | |
a = b | |
else: | |
raise_type_error() | |
elif isinstance(a, dict): | |
# mappings must be merged | |
if isinstance(b, dict): | |
for key in b: | |
if key in a: | |
a[key] = helper(path + '.' + key, parameter_number, a[key], b[key]) | |
else: | |
a[key] = b[key] | |
else: | |
raise_type_error() | |
else: | |
raise_type_error() | |
except TypeError, e: | |
six.raise_from(TypeError('in parameter {parameter_number}, path {path}: {e}'.format(path=path, parameter_number=parameter_number, e=e)), e) | |
if len(rest) >= 1: | |
return helper(path, parameter_number + 1, a, rest[0], *rest[1:]) | |
else: | |
return a | |
return helper('', 1, a, b, *rest) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment