-
Notifications
You must be signed in to change notification settings - Fork 116
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
OmegaConf.to_object
: Instantiate structured configs
#502
Conversation
Looking at the code, I believe this does not handle nested structured configs right now.
We should probably introduce an alias to to_container(), maybe to_object() which will call to_container but will allow Any return type. |
I am having success with nested structured configs:
It is also working for e.g. structured config as a dict value type.
I see what you mean. I'm surprised that mypy did not catch that.
Ok, sounds good. So |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am having success with nested structured configs:
Please add actual tests.
Can you explain why this works?
I also noticed that you are using get_structured_config_data() which is not designed for this (it's used to convert from an sc to a dictconfig) and is actually a rather weird function.
Can you explain what you are using it for exactly, it's not clear to me looking at the code what value it provides you. (it's returning a dictionary where values can be DictConfigs).
Ok, sounds good. So to_container will keep the old behavior (return python primitives) and to_object will instantiate structured configs?
Seems reasonable.
to_container() can still have the new parameter instantiate_structured_configs. (I think a better name for it is instantiate). Doc string should explain it in more detail.
Rebased onto master |
I've added tests for nested structured config (f02261e).
It works because For example, if you have |
The
When the
to create the object, then it does
I'm using the
Hmm... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No more comment from me at this point, thanks!
omegaconf/basecontainer.py
Outdated
for k, v in instance_data.items(): | ||
if _is_missing_literal(v): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The data passed in is derived from the content of self, which is why I am asking it.
It feels redundant.
You have custom code here that is handling things, it can resolve interpolations and deal with containers.
am I missing anything?
omegaconf/basecontainer.py
Outdated
for k, v in instance_data.items(): | ||
if _is_missing_literal(v): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see a few things there that does not make sense when converting a DictConfig backed by a dataclass to an object:
- Support for not resolving interpolations
- Support for converting enums to string (doesn't make sense if we are creating an object).
What do you think about this high level approach:
# converts THIS dict config to an object if it's backed by a Structured Config (error otherwise):
DictConfig._to_object()
The implementation will use _to_content(scmode=Instantiate)
for any nested containers (ListConfig or DictConfig).
_to_content() can call DictConfig._to_object()
if the container it is called on is a DictConfig backed by a Structured Config (and the sc mode is instantiate)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like what I am seeing. A few nits inline.
@odelalleau, can you take a second look? there have been some significant changes.
Co-authored-by: Omry Yadan <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some small comments.
Overall looks good to me. I'm not entirely sure we should ignore the resolve
flag for structured configs (if someone wants an unresolved dataclass to later convert it back to a DictConfig, why not?), but I don't care much about it so let's go :)
node = self._get_node(k) | ||
assert isinstance(node, Node) | ||
node = node._dereference_node(throw_on_resolution_failure=True) | ||
assert node is not None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@omry calling get_node()
followed by _dereference_node()
is a somewhat common operation and it's a bit annoying right now with the mypy asserts.
Would it make sense to add a get_dereferenced_node()
function that would return a Node
(not optional) to streamline such code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would make sense to me.
I'll do it in another PR :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First step is here: #668
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shipit!
OmegaConf.to_object
: Instantiate structured configs
Closes #472
The idea is to add an
instantiate_structured_configs
keyword argument to theOmegaConf.to_container
method.If
OmegaConf.to_container(cfg, instantiate_structured_configs=True)
is called with this new flag, the returned python object will include instantiateddataclass
orattrs
instances.