52 lines
2.0 KiB
Python
52 lines
2.0 KiB
Python
from copy import deepcopy
|
|
|
|
|
|
def apply_layer(base: dict, layer: dict):
|
|
"""
|
|
Recursively applies key-value pairs from `layer` onto `base`.
|
|
|
|
For each key in `layer`:
|
|
- If both `base[key]` and `layer[key]` are dictionaries, recursively merge them.
|
|
- Otherwise, `base[key]` is overwritten (or newly inserted) with `layer[key]`.
|
|
|
|
Note: This function mutates the `base` dictionary in-place.
|
|
|
|
:param base: The target dictionary to be updated. Will be modified directly.
|
|
:param layer: The source dictionary whose values will be applied to `base`.
|
|
"""
|
|
for key, value in layer.items():
|
|
# if base and layer value are dicts, apply recursively
|
|
if type(value) is dict and key in base and type(base[key]) is dict:
|
|
apply_layer(base[key], value)
|
|
# else replace the base value with the layer value
|
|
# or insert the base value
|
|
else:
|
|
base[key] = value
|
|
|
|
|
|
def merge(*pillar_data, deep_copy=True) -> dict:
|
|
"""
|
|
Merges multiple pillar data dictionaries into one.
|
|
|
|
The merging is done left-to-right: keys from later dictionaries override
|
|
those in earlier ones. Nested dictionaries are merged recursively using
|
|
`apply_layer`.
|
|
|
|
:param pillar_data: Two or more dictionaries to merge. Must contain at least one item.
|
|
:param deep_copy: If True (default), the first dictionary is deep-copied before merging,
|
|
preserving the original input data. If False, the first dictionary
|
|
is modified in-place.
|
|
:return: A new merged dictionary (if `deep_copy=True`) or the mutated first dictionary (if `deep_copy=False`).
|
|
|
|
Example:
|
|
merge({'a': 1}, {'b': 2}) → {'a': 1, 'b': 2}
|
|
merge({'a': {'x': 1}}, {'a': {'y': 2}}) → {'a': {'x': 1, 'y': 2}}
|
|
"""
|
|
assert len(pillar_data) > 0, "At least one pillar data is required"
|
|
merged_pillar = deepcopy(pillar_data[0]) if deep_copy else pillar_data[0]
|
|
|
|
for pillar in pillar_data[1:]:
|
|
apply_layer(merged_pillar, pillar)
|
|
|
|
|
|
return merged_pillar |