Skip to content

Commit

Permalink
Consistent exceptions when resolving interpolations
Browse files Browse the repository at this point in the history
Now all exceptions are InterpolationValidationError (or a subclass), and
`throw_on_resolution_failure=False` silences them all.
  • Loading branch information
odelalleau committed Mar 9, 2021
1 parent 1a77110 commit 92757d6
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 16 deletions.
35 changes: 26 additions & 9 deletions omegaconf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
InterpolationKeyError,
InterpolationResolutionError,
InterpolationToMissingValueError,
InterpolationValidationError,
KeyValidationError,
MissingMandatoryValue,
OmegaConfBaseException,
UnsupportedInterpolationType,
Expand Down Expand Up @@ -425,7 +427,12 @@ def _resolve_interpolation_from_parse_tree(
conv_value = value.validate_and_convert(res_value)
except ValidationError as e:
if throw_on_resolution_failure:
self._format_and_raise(key=key, value=res_value, cause=e)
self._format_and_raise(
key=key,
value=res_value,
cause=e,
type_override=InterpolationValidationError,
)
return None

# If the converted value is of the same type, it means that no conversion
Expand All @@ -437,14 +444,24 @@ def _resolve_interpolation_from_parse_tree(

if must_wrap:
assert parent is None or isinstance(parent, BaseContainer)
return _node_wrap(
type_=value._metadata.ref_type,
parent=parent,
is_optional=value._metadata.optional,
value=resolved,
key=key,
ref_type=value._metadata.ref_type,
)
try:
return _node_wrap(
type_=value._metadata.ref_type,
parent=parent,
is_optional=value._metadata.optional,
value=resolved,
key=key,
ref_type=value._metadata.ref_type,
)
except (KeyValidationError, ValidationError) as e:
if throw_on_resolution_failure:
self._format_and_raise(
key=key,
value=resolved,
cause=e,
type_override=InterpolationValidationError,
)
return None
else:
assert isinstance(resolved, Node)
return resolved
Expand Down
6 changes: 6 additions & 0 deletions omegaconf/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ class InterpolationToMissingValueError(InterpolationResolutionError):
"""


class InterpolationValidationError(InterpolationResolutionError):
"""
Thrown when the result of an interpolation fails the validation step.
"""


class ConfigKeyError(OmegaConfBaseException, KeyError):
"""
Thrown from DictConfig when a regular dict access would have caused a KeyError.
Expand Down
16 changes: 9 additions & 7 deletions tests/test_interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
GrammarParseError,
InterpolationKeyError,
InterpolationResolutionError,
KeyValidationError,
InterpolationValidationError,
OmegaConfBaseException,
UnsupportedInterpolationType,
)
Expand Down Expand Up @@ -843,7 +843,7 @@ def drop_last(s: str) -> str:
User(name="Bond", age=SI("${cast:str,seven}")),
"age",
pytest.raises(
ValidationError,
InterpolationValidationError,
match=re.escape(
dedent(
"""\
Expand All @@ -859,7 +859,7 @@ def drop_last(s: str) -> str:
User(name="Bond", age=SI("${name}")),
"age",
pytest.raises(
ValidationError,
InterpolationValidationError,
match=re.escape(
dedent(
"""\
Expand All @@ -875,7 +875,7 @@ def drop_last(s: str) -> str:
StructuredWithMissing(opt_num=None, num=II("opt_num")),
"num",
pytest.raises(
ValidationError,
InterpolationValidationError,
match=re.escape("Non optional field cannot be assigned None"),
),
id="non_optional_node_interpolation",
Expand All @@ -884,7 +884,7 @@ def drop_last(s: str) -> str:
SubscriptedList(list=SI("${identity:[a, b]}")),
"list",
pytest.raises(
ValidationError,
InterpolationValidationError,
match=re.escape("Value 'a' could not be converted to Integer"),
),
id="list_type_mismatch",
Expand All @@ -893,7 +893,7 @@ def drop_last(s: str) -> str:
MissingDict(dict=SI("${identity:{0: b, 1: d}}")),
"dict",
pytest.raises(
KeyValidationError,
InterpolationValidationError,
match=re.escape("Key 0 (int) is incompatible with (str)"),
),
id="dict_key_type_mismatch",
Expand All @@ -905,7 +905,7 @@ def test_interpolation_type_validated_error(
key: str,
expected_error: Any,
restore_resolvers: Any,
) -> Any:
) -> None:
def cast(t: Any, v: Any) -> Any:
return {"str": str, "int": int}[t](v) # cast `v` to type `t`

Expand All @@ -917,6 +917,8 @@ def cast(t: Any, v: Any) -> Any:
with expected_error:
cfg[key]

assert OmegaConf.select(cfg, key, throw_on_resolution_failure=False) is None


def test_type_validation_error_no_throw() -> None:
cfg = OmegaConf.structured(User(name="Bond", age=SI("${name}")))
Expand Down

0 comments on commit 92757d6

Please sign in to comment.