Closed collinmccarthy closed 3 years ago
Thanks for reporting. Can you boil this down to a simple minimal example that does not take a few pages of code? ideally it would have an enum, a dataclass containing it, and an OmegaConf.merge call.
Your current PR includes so much new code that it's too time consuming to understand if you are reporting a bug in OmegaConf or in your own logic.
In addition, please test this on OmegaConf 2.1, you can try one of the dev releases (latest is 2.1.0.dev26).
As a side note: Please be aware that OmegaConf objects are overriding the __eq__
so it's dangerous to rely on it for testing.
Will do. I can't make it "simpler" per say, but I can remove the stuff that works which will cut it down a bit. I'll get to that later today.
just use a bit of hard coded config (did not run this):
cfg1 = OmegaConf.create({"height": "TALL"})
cfg2 = OmegaConf.merge(SimpleTypesEnum, cfg1)
assert cfg2.highet == Height.TALL
I think this is as simple as I can get it. Same thing in 2.1, so maybe this is expected behavior or more of a "feature request". I had thought the types would be preserved in both cases, but maybe there's no way to access the constructor to preserve the type in the second case? Not entirely sure...
from enum import Enum
from dataclasses import dataclass
from omegaconf import OmegaConf
class Height(Enum):
SHORT = 0
TALL = 1
@dataclass
class Simple:
height: Height = Height.SHORT
struct_config = OmegaConf.structured(Simple)
struct_config = OmegaConf.structured(Simple(**{'height': struct_config['height']}))
dict_config = OmegaConf.create({'height': 'TALL'})
merge_config = OmegaConf.merge(struct_config, dict_config)
assert type(merge_config.height) == type(struct_config.height) # Works
struct_config = OmegaConf.structured(Simple)
struct_config = OmegaConf.create({'height': struct_config['height']})
merge_config = OmegaConf.merge(struct_config, dict_config)
assert type(merge_config.height) == type(struct_config.height) # Fails
Thanks!
This is expected. In your second struct_config, there is no type associated with height, which means the node can take any supported type. You are merging a string onto it, and this is what you end up with.
The correct way to do what you are trying to do is:
schema = OmegaConf.structured(Simple)
cfg = OmegaConf.create({"height": Height.SHORT})
# cfg = OmegaConf.create({"height": "SHORT"}) # This will also work.
merged = OmegaConf.merge(schema, cfg)
assert type(merged.height) == Height
Okay, got it. So basically I can't "flatten" a config created with OmegaConf.structured()
into a dictionary, and then merge it, because during the merging process it won't have the typing information of the dataclass to retain the original types.
Thank you for your help in understanding this!
Describe the bug My use case for OmegaConf is to be able to define a default config, and let the user specify a YAML file with overrides. This YAML file can be in standard form, with nested dictionaries, or as a "flattened" dictionary with dot-notation like
simple.num=10
. I use flatten and inflate methods to handle both cases, and when using enums the type information is lost in one specific situation, shown below.The merging works if I inflate the YAML file, then merge with the default config. The merging "fails" (in the sense the type information is lost) if I flatten both configs, then merge, then inflate. The type information is important so I can compare with
config.simple.height == Height.TALL
or something like that. I'm submitting this bug report mainly because this was difficult for me to track down and I don't think this behavior is intentional.To Reproduce
This produces the following output:
Expected behavior As shown in the last few lines of the output, test 4 fails when using enums. The flattened YAML config has a string for
simple.height
and the flattened structured config has an enum, as expected. But when they merge they produce a string, rather than an enum like in test 3. I expected test 3 and test 4 to work for both cases, with and without enums.Additional context
omegaconf 2.0.6 pypi_0 pypi
python 3.8.8 hffdb5ce_0_cpython conda-forge
Thank you for your help! Really loving omegaconf!