Source code for ascetic_ddd.seedwork.domain.utils.data
__all__ = ("hashable", "freeze", "is_subset", "deepmerge",)
[docs]
def hashable(o):
if isinstance(o, dict):
return tuple(sorted((k, hashable(v)) for k, v in o.items()))
if isinstance(o, list):
return tuple([hashable(v) for v in sorted(o)])
return o
[docs]
def freeze(o):
if isinstance(o, dict):
return frozenset(sorted((k, freeze(v)) for k, v in o.items()))
if isinstance(o, list):
return frozenset([freeze(v) for v in sorted(o)])
return o
[docs]
def is_subset(sub, master):
"""
Recursively checks if 'sub' is a subset of 'master'.
Works with nested dicts and lists of dicts.
"""
# 1. Handle Dictionaries
if isinstance(sub, dict):
if not isinstance(master, dict):
return False
# Every key in the subset must exist in the master and match the subset's criteria
return all(k in master and is_subset(sub[k], master[k]) for k in sub)
# 2. Handle Lists (Subset logic: every item in 'sub' must exist in 'master')
elif isinstance(sub, list):
if not isinstance(master, list):
return False
# Each item in the subset list must have at least one match in the master list
return all(any(is_subset(sub_item, master_item) for master_item in master) for sub_item in sub)
# 3. Handle Primitive Values (Strings, Ints, etc.)
else:
return sub == master
[docs]
def deepmerge(destination, source):
"""
>>> a = { 'first' : { 'all_rows' : { 'pass' : 'dog', 'number' : '1' } } }
>>> b = { 'first' : { 'all_rows' : { 'fail' : 'cat', 'number' : '5' } } }
>>> deepmerge(b, a) == { 'first' : { 'all_rows' : { 'pass' : 'dog', 'fail' : 'cat', 'number' : '5' } } }
True
"""
if isinstance(source, dict):
assert isinstance(destination, dict)
for key, value in source.items():
if key in destination:
deepmerge(destination[key], value)
else:
destination[key] = value
elif isinstance(source, list):
assert isinstance(destination, list)
for index, value in enumerate(source):
if isinstance(value, dict) and index < len(destination):
deepmerge(destination[index], value)
elif value not in destination:
destination.append(value)
return destination