Files
dvc/tests/func/utils/test_hydra.py
T
David de la Iglesia Castro 31635b8312 exp run: Use hydra for parsing --set-param.
- Overriding a config value : foo.bar=value
- Appending a config value : +foo.bar=value
- Appending or overriding a config value : ++foo.bar=value
- Removing a config value : ~foo.bar, ~foo.bar=value

See https://hydra.cc/docs/advanced/override_grammar/basic/#modifying-the-config-object

---

Breaking changes:

To modify a list, `foo[0]=bar` must now be passed as `foo.0=bar`.

Modifying a nested list inside a dictionary is not supported by omegaconf.

---

Closes #4883
Closes #5868
Closes #6129
2022-08-05 17:53:24 +02:00

123 lines
3.3 KiB
Python

import pytest
from dvc.exceptions import InvalidArgumentError
from dvc.utils.hydra import apply_overrides
@pytest.mark.parametrize("suffix", ["yaml", "toml", "json"])
@pytest.mark.parametrize(
"overrides, expected",
[
# Overriding
(["foo=baz"], {"foo": "baz", "goo": {"bag": 3.0}, "lorem": False}),
(["foo=baz", "goo=bar"], {"foo": "baz", "goo": "bar", "lorem": False}),
(
["foo.0=bar"],
{"foo": ["bar", {"baz": 2}], "goo": {"bag": 3.0}, "lorem": False},
),
(
["foo.1.baz=3"],
{
"foo": [{"bar": 1}, {"baz": 3}],
"goo": {"bag": 3.0},
"lorem": False,
},
),
(
["goo.bag=4.0"],
{
"foo": [{"bar": 1}, {"baz": 2}],
"goo": {"bag": 4.0},
"lorem": False,
},
),
(
["++goo={bag: 1, b: 2}"],
{
"foo": [{"bar": 1}, {"baz": 2}],
"goo": {"bag": 1, "b": 2},
"lorem": False,
},
),
# 6129
(
["lorem="],
{
"foo": [{"bar": 1}, {"baz": 2}],
"goo": {"bag": 3.0},
"lorem": "",
},
),
# 6129
(
["lorem=null"],
{
"foo": [{"bar": 1}, {"baz": 2}],
"goo": {"bag": 3.0},
"lorem": None,
},
),
# 5868
(
["lorem=1992-11-20"],
{
"foo": [{"bar": 1}, {"baz": 2}],
"goo": {"bag": 3.0},
"lorem": "1992-11-20",
},
),
# 5868
(
["lorem='1992-11-20'"],
{
"foo": [{"bar": 1}, {"baz": 2}],
"goo": {"bag": 3.0},
"lorem": "1992-11-20",
},
),
# Appending
(
["+a=1"],
{
"foo": [{"bar": 1}, {"baz": 2}],
"goo": {"bag": 3.0},
"lorem": False,
"a": 1,
},
),
# Removing
(["~foo"], {"goo": {"bag": 3.0}, "lorem": False}),
],
)
def test_apply_overrides(tmp_dir, suffix, overrides, expected):
if suffix == "toml":
if overrides in [
["foo=baz"],
["foo.0=bar"],
["foo=baz", "goo=bar"],
["lorem=null"],
]:
# TOML dumper breaks when overriding a list/dict with other type
# or when handling `null` values.
pytest.xfail()
params_file = tmp_dir / f"params.{suffix}"
params_file.dump(
{"foo": [{"bar": 1}, {"baz": 2}], "goo": {"bag": 3.0}, "lorem": False}
)
apply_overrides(path=params_file.name, overrides=overrides)
assert params_file.parse() == expected
@pytest.mark.parametrize(
"overrides",
[["foobar=2"], ["lorem=3,2"], ["+lorem=3"], ["foo[0]=bar"]],
)
def test_invalid_overrides(tmp_dir, overrides):
params_file = tmp_dir / "params.yaml"
params_file.dump(
{"foo": [{"bar": 1}, {"baz": 2}], "goo": {"bag": 3.0}, "lorem": False}
)
with pytest.raises(InvalidArgumentError):
apply_overrides(path=params_file.name, overrides=overrides)