Files
dvc/tests/func/metrics/test_diff.py
T
Ruslan Kuprieiev 52fe76cefc metrics: diff: make table more intuitive (#4655)
* metrics: diff: make table more intuitive

Currently we have a "diff not supported" marker in the table, that is
used whenever dvc is not able to diff the values (e.g. no old one, no
new one or format error). It is quite ugly and it is much more intuitive
to just show both old and new values and now show that marker at all, as
if there is no old/new value it is intuitive that we can't calculate the
change. Next step is to add old/new "bad format"/etc markers for
unsupported types or malformed/missing metric files.

E.g., before:

```
Path          Metric    Value    Change
metrics.json  foo       1.2      diff not supported
```

after this PR:

```
Path          Metric    Old    New    Change
metrics.json  foo       None   1.2
```

* metrics/params: use em dash in diff table
2020-10-05 19:37:34 +03:00

212 lines
5.7 KiB
Python

import json
import logging
from dvc.main import main
from dvc.utils.serialize import dump_yaml
def test_metrics_diff_simple(tmp_dir, scm, dvc, run_copy_metrics):
def _gen(val):
tmp_dir.gen({"m_temp.yaml": str(val)})
run_copy_metrics("m_temp.yaml", "m.yaml", metrics=["m.yaml"])
dvc.scm.commit(str(val))
_gen(1)
_gen(2)
_gen(3)
expected = {"m.yaml": {"": {"old": 1, "new": 3, "diff": 2}}}
assert dvc.metrics.diff(a_rev="HEAD~2") == expected
def test_metrics_diff_yaml(tmp_dir, scm, dvc, run_copy_metrics):
def _gen(val):
metrics = {"a": {"b": {"c": val, "d": 1, "e": str(val)}}}
dump_yaml("m_temp.yaml", metrics)
run_copy_metrics(
"m_temp.yaml", "m.yaml", metrics=["m.yaml"], commit=str(val)
)
_gen(1)
_gen(2)
_gen(3)
expected = {"m.yaml": {"a.b.c": {"old": 1, "new": 3, "diff": 2}}}
assert dvc.metrics.diff(a_rev="HEAD~2") == expected
def test_metrics_diff_json(tmp_dir, scm, dvc, run_copy_metrics):
def _gen(val):
metrics = {"a": {"b": {"c": val, "d": 1, "e": str(val)}}}
tmp_dir.gen({"m_temp.json": json.dumps(metrics)})
run_copy_metrics(
"m_temp.json", "m.json", metrics=["m.json"], commit=str(val)
)
_gen(1)
_gen(2)
_gen(3)
expected = {"m.json": {"a.b.c": {"old": 1, "new": 3, "diff": 2}}}
assert dvc.metrics.diff(a_rev="HEAD~2") == expected
def test_metrics_diff_json_unchanged(tmp_dir, scm, dvc, run_copy_metrics):
def _gen(val):
metrics = {"a": {"b": {"c": val, "d": 1, "e": str(val)}}}
tmp_dir.gen({"m_temp.json": json.dumps(metrics)})
run_copy_metrics(
"m_temp.json", "m.json", metrics=["m.json"], commit=str(val)
)
_gen(1)
_gen(2)
_gen(1)
assert dvc.metrics.diff(a_rev="HEAD~2") == {}
def test_metrics_diff_broken_json(tmp_dir, scm, dvc, run_copy_metrics):
metrics = {"a": {"b": {"c": 1, "d": 1, "e": "3"}}}
tmp_dir.gen({"m_temp.json": json.dumps(metrics)})
run_copy_metrics(
"m_temp.json",
"m.json",
metrics_no_cache=["m.json"],
commit="add metrics",
)
(tmp_dir / "m.json").write_text(json.dumps(metrics) + "ma\nlformed\n")
assert dvc.metrics.diff() == {
"m.json": {
"a.b.c": {"old": 1, "new": None},
"a.b.d": {"old": 1, "new": None},
}
}
def test_metrics_diff_no_metrics(tmp_dir, scm, dvc):
tmp_dir.scm_gen({"foo": "foo"}, commit="add foo")
assert dvc.metrics.diff(a_rev="HEAD~1") == {}
def test_metrics_diff_new_metric(tmp_dir, scm, dvc, run_copy_metrics):
metrics = {"a": {"b": {"c": 1, "d": 1, "e": "3"}}}
tmp_dir.gen({"m_temp.json": json.dumps(metrics)})
run_copy_metrics("m_temp.json", "m.json", metrics_no_cache=["m.json"])
assert dvc.metrics.diff() == {
"m.json": {
"a.b.c": {"old": None, "new": 1},
"a.b.d": {"old": None, "new": 1},
}
}
def test_metrics_diff_deleted_metric(tmp_dir, scm, dvc, run_copy_metrics):
metrics = {"a": {"b": {"c": 1, "d": 1, "e": "3"}}}
tmp_dir.gen({"m_temp.json": json.dumps(metrics)})
run_copy_metrics(
"m_temp.json",
"m.json",
metrics_no_cache=["m.json"],
commit="add metrics",
)
(tmp_dir / "m.json").unlink()
assert dvc.metrics.diff() == {
"m.json": {
"a.b.c": {"old": 1, "new": None},
"a.b.d": {"old": 1, "new": None},
}
}
def test_metrics_diff_with_unchanged(tmp_dir, scm, dvc, run_copy_metrics):
tmp_dir.gen("metrics_temp.yaml", "foo: 1\nxyz: 10")
run_copy_metrics(
"metrics_temp.yaml",
"metrics.yaml",
metrics_no_cache=["metrics.yaml"],
commit="1",
)
tmp_dir.scm_gen("metrics.yaml", "foo: 2\nxyz: 10", commit="2")
tmp_dir.scm_gen("metrics.yaml", "foo: 3\nxyz: 10", commit="3")
assert dvc.metrics.diff(a_rev="HEAD~2", all=True) == {
"metrics.yaml": {
"foo": {"old": 1, "new": 3, "diff": 2},
"xyz": {"old": 10, "new": 10, "diff": 0},
}
}
def test_no_commits(tmp_dir):
from dvc.repo import Repo
from dvc.scm.git import Git
from tests.dir_helpers import git_init
git_init(".")
assert Git().no_commits
assert Repo.init().metrics.diff() == {}
def test_metrics_diff_dirty(tmp_dir, scm, dvc, run_copy_metrics):
def _gen(val):
tmp_dir.gen({"m_temp.yaml": str(val)})
run_copy_metrics("m_temp.yaml", "m.yaml", metrics=["m.yaml"])
dvc.scm.commit(str(val))
_gen(1)
_gen(2)
_gen(3)
tmp_dir.gen({"m.yaml": "4"})
expected = {"m.yaml": {"": {"old": 3, "new": 4, "diff": 1}}}
assert dvc.metrics.diff() == expected
def test_metrics_diff_cli(tmp_dir, scm, dvc, run_copy_metrics, caplog, capsys):
def _gen(val):
tmp_dir.gen({"m_temp.yaml": f"foo: {val}"})
run_copy_metrics("m_temp.yaml", "m.yaml", metrics=["m.yaml"])
dvc.scm.commit(str(val))
_gen(1.23456789)
_gen(2.34567891011)
_gen(3.45678910111213)
caplog.clear()
assert main(["metrics", "diff", "HEAD~2"]) == 0
(info,) = [
msg
for name, level, msg in caplog.record_tuples
if name.startswith("dvc") and level == logging.INFO
]
assert info == (
"Path Metric Old New Change\n"
"m.yaml foo 1.23457 3.45679 2.22222"
)
def test_metrics_diff_non_metrics(tmp_dir, scm, dvc):
def _gen(val):
tmp_dir.scm_gen({"some_file.yaml": f"foo: {val}"}, commit=str(val))
_gen(1)
_gen(2)
_gen(3)
result = dvc.metrics.diff(targets=["some_file.yaml"], a_rev="HEAD~2")
assert result == {
"some_file.yaml": {"foo": {"old": 1, "new": 3, "diff": 2}}
}