metrics: diff: handle deleted/new metric (#3529)

Partial fix for https://github.com/iterative/dvc/issues/3469
This commit is contained in:
Ruslan Kuprieiev
2020-03-25 05:23:21 +02:00
committed by GitHub
parent 9b38aa4680
commit 0bf6fdae14
3 changed files with 67 additions and 19 deletions
+17 -19
View File
@@ -7,7 +7,7 @@ from dvc.exceptions import NoMetricsError
def _parse(raw):
if isinstance(raw, (dict, list, int, float)):
if raw is None or isinstance(raw, (dict, list, int, float)):
return raw
assert isinstance(raw, str)
@@ -34,29 +34,27 @@ def _diff_vals(old, new):
return res
def _flatten(d):
if not d:
return defaultdict(lambda: None)
if isinstance(d, dict):
return defaultdict(lambda: None, flatten(d, "."))
return defaultdict(lambda: "unable to parse")
def _diff_dicts(old_dict, new_dict):
old_default = None
new_default = None
if isinstance(new_dict, dict):
new = flatten(new_dict, ".")
else:
new = defaultdict(lambda: "not a dict")
new_default = "unable to parse"
if isinstance(old_dict, dict):
old = flatten(old_dict, ".")
else:
old = defaultdict(lambda: "not a dict")
old_default = "unable to parse"
new = _flatten(new_dict)
old = _flatten(old_dict)
res = defaultdict(dict)
xpaths = set(old.keys())
xpaths.update(set(new.keys()))
for xpath in xpaths:
old_val = old.get(xpath, old_default)
new_val = new.get(xpath, new_default)
old_val = old[xpath]
new_val = new[xpath]
val_diff = _diff_vals(old_val, new_val)
if val_diff:
res[xpath] = val_diff
@@ -78,7 +76,7 @@ def _get_metrics(repo, *args, rev=None, **kwargs):
metrics = repo.metrics.show(
*args, **kwargs, revs=[rev] if rev else None
)
return metrics[rev or ""]
return metrics.get(rev or "", {})
except NoMetricsError:
return {}
@@ -92,7 +90,7 @@ def diff(repo, *args, a_rev=None, b_rev=None, **kwargs):
res = defaultdict(dict)
for path in paths:
path_diff = _diff(old[path], new[path])
path_diff = _diff(old.get(path), new.get(path))
if path_diff:
res[path] = path_diff
return dict(res)
+32
View File
@@ -940,3 +940,35 @@ def test_metrics_diff_broken_json(tmp_dir, scm, dvc):
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):
metrics = {"a": {"b": {"c": 1, "d": 1, "e": "3"}}}
tmp_dir.gen({"m.json": json.dumps(metrics)})
dvc.run(cmd="", 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},
"a.b.e": {"old": None, "new": "3"},
}
}
def test_metrics_diff_deleted_metric(tmp_dir, scm, dvc):
metrics = {"a": {"b": {"c": 1, "d": 1, "e": "3"}}}
tmp_dir.gen({"m.json": json.dumps(metrics)})
dvc.run(cmd="", metrics_no_cache=["m.json"])
dvc.scm.add(["m.json.dvc", "m.json"])
dvc.scm.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},
"a.b.e": {"old": "3", "new": None},
}
}
+18
View File
@@ -65,3 +65,21 @@ def test_metrics_diff_no_diff():
def test_metrics_diff_no_changes():
assert _show_diff({}) == "No changes."
def test_metrics_diff_new_metric():
assert _show_diff(
{"other.json": {"a.b.d": {"old": None, "new": "new"}}}
) == (
" Path Metric Value Change \n"
"other.json a.b.d new diff not supported"
)
def test_metrics_diff_deleted_metric():
assert _show_diff(
{"other.json": {"a.b.d": {"old": "old", "new": None}}}
) == (
" Path Metric Value Change \n"
"other.json a.b.d None diff not supported"
)