-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Structured configs do not respect dataclasses.field(init=False)
#789
Comments
Hi @thomkeh , thanks for the feature request!
What is the motivation for ignoring fields that have EDIT: Here is a WORKAROUND:@dataclass
class C:
a: float
b: float
def __post_init__(self):
self.c: float = self.a + self.b
obj = C(1, 2)
assert obj.c == 3
reveal_type(obj.c)
# "c" is not a field of C, but type checkers still reveal obj.c to be of type `float` The >>> from omegaconf import OmegaConf
>>> d = OmegaConf.create(C)
>>> d.a = 3
>>> d.b = 4
>>> o = OmegaConf.to_object(d)
>>> o.c
7.0 |
It does exactly what I am expecting it to do. c is missing, just like a and b. In [8]: @dataclass
...: class C:
...: a: float
...: b: float
...: c: float = field(init=False)
...:
In [9]: OmegaConf.structured(C)
Out[9]: {'a': '???', 'b': '???', 'c': '???'} This issue looks like it's about to_object, not about a the handling of OmegaConf of fields with init=False. |
Good point. |
In general I think |
Makes sense to me.
Not sure what you mean here... |
If you have from dataclasses import dataclass, field
from omegaconf import OmegaConf
@dataclass
class C:
a: float
b: float
c: float = field(init=False)
cfg = OmegaConf.create(C(a=1, b=2))
cfg.c = 3
obj = OmegaConf.to_object(cfg) I am expecting the resulting object to have the values a=1, b=2 and c=3. |
I see. So if the from dataclasses import dataclass, field
from omegaconf import OmegaConf
@dataclass
class C:
a: float
b: float
c: float = field(init=False)
def __post_init__(self) -> None:
self.c = self.a + self.b + 100
cfg = OmegaConf.create(C(a=1, b=2)) # C(a=1, b=2) has c==103
cfg.c = 3
obj = OmegaConf.to_object(cfg) # obj has c==3, not c==103 The exception would be if |
yeah, this is a good point. not sure how to handle it. |
For the record, here is the behavior if we follow the OP's suggestion to exclude from dataclasses import dataclass, field
from omegaconf import OmegaConf
@dataclass
class C:
a: float
b: float
c: float = field(init=False)
def __post_init__(self):
self.c = self.a + self.b
# creating from a dataclass
cfg = OmegaConf.create(C)
assert cfg == {"a"="???", "b"="???"}
cfg.a = 1
cfg.b = 2
obj = OmegaConf.to_object(cfg)
assert obj.c == 3
# creating from an instance
cfg_inst = OmegaConf.create(C(a=1, b=2))
assert cfg_inst == {"a"=1, "b"=2}
cfg_inst.a = 10
cfg_inst.b = 20
obj2 = OmegaConf.to_object(cfg_inst)
assert obj2.c == 30 # this is expected A drawback of this approach is that duck-typing does not work (i.e. treating |
Hi, I am also registering the interest in excluding |
TL;DR:
Supporting
|
FWIW, since opening this issue, I have realized that my use case was better handled by (And I don't understand @rsokl 's requirements well enough to comment on his proposal.) |
@thomkeh I think using By the way @thomkeh, I've discovered a workaround for your original issue: @dataclass
class C:
a: float
b: float
def __post_init__(self):
self.c: float = self.a + self.b
obj = C(1, 2)
assert obj.c == 3
reveal_type(obj.c)
# "c" is not a field of C, but type checkers still reveal obj.c to be of type `float` The
Your suggestion to call I feel that a provision should be made for the case where an @dataclass
class MyDataClass:
foo: int = field(init=False)
obj1 = MyDataClass()
assert not hasattr(obj1, "foo")
cfg = OmegaConf.create(MyDataClass)
assert OmegaConf.is_missing(cfg, "foo")
obj2 = OmegaConf.to_object(cfg)
# It would be strange if in this case `obj2.foo == MISSING`.
# I think `hasattr(obj2, "foo")` should be False here,
# agreeing with the case of `obj1` above. If you are inclinded to submit a PR implementing this, it would be most welcome! The
|
Great, I will take a swing at this; hopefully relatively soon 😄 |
Great! FYR most of the |
I ended up knocking this out myself in #879. |
Ah, thanks for tackling this! |
The documentation of dataclasses has this example for
init=False
:It just means that
c
is not an argument to the__init__
. I find this useful sometimes when I have a configuration value that can be computed from other configuration values.Describe the solution you'd like
OmegaConf should just ignore fields that have
init=False
set.Describe alternatives you've considered
One alternative is to not give a type annotation to the field and just set it to
MISSING
:This works, but it is a bit sad that we have to accept the loss of the type annotation.
Additional context
This is what currently happens when you use
init=False
.The text was updated successfully, but these errors were encountered: