Skip to content
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

Fix bug where interpolations were unnecessarily resolved during merge. #432

Merged
merged 6 commits into from
Nov 11, 2020

Conversation

pereman2
Copy link
Contributor

@pereman2 pereman2 commented Nov 6, 2020

Closes #431 .

DictConfig and ListConfig which were interpolations had to be "expanded" in order to fulfil the merge. If it wasn't, it detaches the node to find the interpolation value which in the example given in #431 doesn't exist and then fails. is_interpolation has to be checked before is_missing since is_missing detaches the node(which will resolve the interpolation) to find if that is missing.

Copy link
Owner

@omry omry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!
Got a few requests.


@dataclass
class InterpolationList:
list: List[float] = "${optimization.lr}" # type: ignore
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the docs for interpolation with Structured Configs.
you can do something like:

list: List[float] = II("optimization.lr")

And this would not need the type: ignore.

Comment on lines 391 to 393
self.__dict__["_content"] = []
else:
self.__dict__["_content"].clear()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bit puzzles me. the two branches are pretty similar.
Can you try to see if you can just use one of the branches always?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block can be reduced to self.__dict__["_content"] = [] without the if-else and works the same

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, please do it.

),
],
)
def test_merge_with_interpolation(dst: Any, other: Any, expected: Any) -> None:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test for merging with itself.

Should be something like:

            OmegaConf.structured(InterpolationDict),
            OmegaConf.structured(InterpolationDict),
            {"dict": {"a": "${optimization.lr}"}},

I want to see that the interpolation is not resolved in the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails, in this case in validate_merge

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, this needs to pass too. no reason for it to fail.

@omry
Copy link
Owner

omry commented Nov 6, 2020

Also, can you tell me what is missing from this PR? :)

@pereman2
Copy link
Contributor Author

pereman2 commented Nov 6, 2020

Also, can you tell me what is missing from this PR? :)

news fragment?

@omry
Copy link
Owner

omry commented Nov 6, 2020

Also, can you tell me what is missing from this PR? :)

news fragment?

Yup :)

@pereman2 pereman2 changed the title Fix bug where interpolations were unnecessary resolved during merge. Fix bug where interpolations were unnecessarily resolved during merge. Nov 6, 2020
Copy link
Owner

@omry omry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. a few questions inline.

omegaconf/basecontainer.py Show resolved Hide resolved
@@ -575,9 +577,12 @@ def _item_eq(
def _is_none(self) -> bool:
return self.__dict__["_content"] is None

def _is_missing(self) -> bool:
def _is_missing(self, throw_on_resolution_failure: bool = True) -> bool:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you change this function to not throw on resolution failure (without a parameter), does this cause any issues?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't cause any issue, It could be changed to that.

Comment on lines 508 to 521
(
OmegaConf.structured(InterpolationDict),
OmegaConf.structured(InterpolationDict),
None,
"dict",
True,
),
(
OmegaConf.structured(InterpolationList),
OmegaConf.structured(InterpolationList),
None,
"list",
True,
),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you name tests?
pytest.param(..., id="test_name")

omegaconf/basecontainer.py Show resolved Hide resolved
Comment on lines +284 to +286
if src._is_interpolation():
dest._set_value(src._value())
return
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merging an interpolation to a container is basically keeping the interpolation in dest therefore, dest's value should be src's value.
If I don't do this check here it will fail in for key, src_value in src.items_ex(resolve=False):(line 307).
To sum up, it's the same as line 289 where if src._is_missing(): dest._set_value("???")

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. See that there is a comment explaining it in 288.
Add a similar comment.

@@ -445,7 +445,7 @@ def pop(self, key: Union[str, Enum], default: Any = DEFAULT_VALUE_MARKER) -> Any
self._format_and_raise(key=key, value=None, cause=e)

def keys(self) -> Any:
if self._is_missing() or self._is_interpolation() or self._is_none():
if self._is_interpolation() or self._is_missing() or self._is_none():
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not that _is_missing dies not throw, you can undo this change.

Comment on lines 566 to 567
elif c._is_interpolation():
return None
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that is_missing doesn't throw on resolution failure it doesn't matter this line. I'll remove it.

Comment on lines 528 to 535
def test_merge_with_interpolation(
dst: Any, other: Any, expected: Any, node: Any, check_missing: bool
) -> None:
res = OmegaConf.merge(dst, other)
if check_missing:
OmegaConf.is_missing(res, node)
else:
assert res == expected
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do one thing in each test.
you can add another test to test the behavior of _is_missing with interpolation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm changing it to is_interpolation

Copy link
Owner

@omry omry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great.
Merging, can you add another PR cherry-picking this into the 2.0_branch?

@omry omry merged commit 0d6b602 into omry:master Nov 11, 2020
@pereman2
Copy link
Contributor Author

Great.
Merging, can you add another PR cherry-picking this into the 2.0_branch?

Sure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] omegaconf is doing interpolation during merges when it shouldnt
2 participants