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
This commit is contained in:
David de la Iglesia Castro
2022-08-05 17:53:24 +02:00
parent 45ac64ddde
commit 31635b8312
12 changed files with 339 additions and 210 deletions
+7 -59
View File
@@ -7,7 +7,7 @@ import pytest
from funcy import first
from dvc.dvcfile import PIPELINE_FILE
from dvc.exceptions import DvcException, ReproductionError
from dvc.exceptions import ReproductionError
from dvc.repo.experiments.queue.base import BaseStashQueue
from dvc.repo.experiments.utils import exp_refs_by_rev
from dvc.scm import resolve_rev
@@ -107,69 +107,17 @@ def test_failed_exp_workspace(
@pytest.mark.parametrize(
"changes, expected",
[
[["foo=baz"], "{foo: baz, goo: {bag: 3}, lorem: false}"],
[["foo=baz", "goo=bar"], "{foo: baz, goo: bar, lorem: false}"],
[
["goo.bag=4"],
"{foo: [bar: 1, baz: 2], goo: {bag: 4}, lorem: false}",
],
[["foo[0]=bar"], "{foo: [bar, baz: 2], goo: {bag: 3}, lorem: false}"],
[
["foo[1].baz=3"],
"{foo: [bar: 1, baz: 3], goo: {bag: 3}, lorem: false}",
],
[
["foo[1]=[baz, goo]"],
"{foo: [bar: 1, [baz, goo]], goo: {bag: 3}, lorem: false}",
],
[["foo=baz"], "foo: baz\ngoo:\n bag: 3.0\nlorem: false"],
[["params.yaml:foo=baz"], "foo: baz\ngoo:\n bag: 3.0\nlorem: false"],
],
)
def test_modify_params(tmp_dir, scm, dvc, mocker, changes, expected):
tmp_dir.gen("copy.py", COPY_SCRIPT)
tmp_dir.gen(
"params.yaml", "{foo: [bar: 1, baz: 2], goo: {bag: 3}, lorem: false}"
)
stage = dvc.run(
cmd="python copy.py params.yaml metrics.yaml",
metrics_no_cache=["metrics.yaml"],
params=["foo", "goo", "lorem"],
name="copy-file",
)
scm.add(["dvc.yaml", "dvc.lock", "copy.py", "params.yaml", "metrics.yaml"])
scm.commit("init")
new_mock = mocker.spy(dvc.experiments, "new")
results = dvc.experiments.run(stage.addressing, params=changes)
exp = first(results)
new_mock.assert_called_once()
fs = scm.get_fs(exp)
with fs.open("metrics.yaml", mode="r") as fobj:
def test_modify_params(params_repo, dvc, changes, expected):
dvc.experiments.run(params=changes)
# pylint: disable=unspecified-encoding
with open("params.yaml", mode="r") as fobj:
assert fobj.read().strip() == expected
@pytest.mark.parametrize(
"changes",
[["lorem.ipsum=3"], ["foo[0].bazar=3"]],
)
def test_add_params(tmp_dir, scm, dvc, changes):
tmp_dir.gen("copy.py", COPY_SCRIPT)
tmp_dir.gen(
"params.yaml", "{foo: [bar: 1, baz: 2], goo: {bag: 3}, lorem: false}"
)
stage = dvc.run(
cmd="python copy.py params.yaml metrics.yaml",
metrics_no_cache=["metrics.yaml"],
params=["foo", "goo", "lorem"],
name="copy-file",
)
scm.add(["dvc.yaml", "dvc.lock", "copy.py", "params.yaml", "metrics.yaml"])
scm.commit("init")
with pytest.raises(DvcException):
dvc.experiments.run(stage.addressing, params=changes)
def test_apply(tmp_dir, scm, dvc, exp_stage):
from dvc.exceptions import InvalidArgumentError
from dvc.repo.experiments.exceptions import ApplyConflictError