-
Hi, I noticed that when using inheritance, nested configs are not recursively merged but simply overriden by the child. base = make_config(a=dict(b=0, c=0))
cfg = make_config(a=dict(c=1, d=1), bases=(base,))
I would expect
but it is
Can this be changed? I am unfamiliar with the return type of from collections.abc import MutableMapping, Iterable
def index_with_keys(cfg: MutableMapping, keys: Iterable[str]) -> MutableMapping:
list_of_tuples = [(k, cfg[k]) for k in keys]
return dict(list_of_tuples)
def merge_mappings(cfg: MutableMapping, base: MutableMapping) -> MutableMapping:
if len(cfg) == 0 or len(base) == 0:
return {**cfg, **base}
cfg_keys = set(cfg.keys())
base_keys = set(base.keys())
only_cfg_keys = cfg_keys - base_keys
only_base_keys = base_keys - cfg_keys
intersection_keys = cfg_keys & base_keys
merged_intersection = {k: merge(cfg[k], base[k]) for k in intersection_keys}
return {
**index_with_keys(cfg, only_cfg_keys),
**index_with_keys(base, only_base_keys),
**merged_intersection
}
def merge(cfg: MutableMapping, base: MutableMapping) -> MutableMapping:
cfg_primitive = {k: v for k, v in cfg.items() if not isinstance(v, MutableMapping)}
base_primitive = {k: v for k, v in base.items() if not isinstance(v, MutableMapping)}
merged_primitives = {**base_primitive, **cfg_primitive}
cfg_mappings = {k: v for k, v in cfg.items() if isinstance(v, MutableMapping)}
base_mappings = {k: v for k, v in base.items() if isinstance(v, MutableMapping)}
merged_mappings = merge_mappings(cfg_mappings, base_mappings)
return {**merged_primitives, **merged_mappings}
if __name__ == '__main__':
base = dict(a=dict(b=0, c=0), b=0, c=0)
cfg = dict(a=dict(c=1, d=1), c=1, d=1)
print(cfg)
print(base)
print(merge(cfg, base)) It prints
though the order changes. What do you guys think? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
I also noticed that the defaults list simply gets replaced the the child, i.e. base = make_config(hydra_defaults=[{'a': 'a0'}, {'b': 'b0'}, '_self_'])
cfg = make_config(hydra_defaults=[{'b': 'b1'}, {'c': 'c1'}, '_self_'], bases=(base,)) results in
I think this makes sense, as |
Beta Was this translation helpful? Give feedback.
-
All of hydra-zen's config-creation functions - You can get the behavior you are looking for by using from hydra_zen import make_config
from omegaconf import OmegaConf
base = make_config(a=dict(b=0, c=0))
cfg = make_config(a=dict(c=1, d=1), bases=(base,))
OmegaConf.merge(base, cfg) produces
|
Beta Was this translation helpful? Give feedback.
-
I wanted to follow-up on this answer because I spent a long-time trying to do something similar, trying many complicated variants, until I realized the answer is simple. Please correct me if I'm wrong but from my testing, if you are storing the configs from E.g.,
I suppose you could then retrieve the config by doing something like Hope this helps someone looking for something similar in the future! |
Beta Was this translation helpful? Give feedback.
All of hydra-zen's config-creation functions -
builds
,make_config
- return dynamically-generated dataclass types, so the inheritance behavior you are seeing is just straightforward class inheritance.You can get the behavior you are looking for by using
OmegaConf.merge
:produces