mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-08 15:28:26 +01:00
exp show: handle renaming of metrics/params.
_extend_row did not considered partially empty `items`, which can occur when metris or params are renamed between commits. Fixes #7070
This commit is contained in:
@@ -65,6 +65,9 @@ experiment_types = {
|
||||
def _collect_rows(
|
||||
base_rev,
|
||||
experiments,
|
||||
all_headers,
|
||||
metric_headers,
|
||||
param_headers,
|
||||
metric_names,
|
||||
param_names,
|
||||
deps_names,
|
||||
@@ -87,14 +90,18 @@ def _collect_rows(
|
||||
|
||||
new_checkpoint = True
|
||||
for i, (rev, results) in enumerate(experiments.items()):
|
||||
fill_value = FILL_VALUE_ERRORED if results.get("error") else fill_value
|
||||
row_dict = {k: fill_value for k in all_headers}
|
||||
|
||||
exp = results.get("data", {})
|
||||
|
||||
if exp.get("running"):
|
||||
state = "Running"
|
||||
elif exp.get("queued"):
|
||||
state = "Queued"
|
||||
else:
|
||||
state = fill_value
|
||||
executor = exp.get("executor", fill_value)
|
||||
|
||||
is_baseline = rev == "baseline"
|
||||
|
||||
if is_baseline:
|
||||
@@ -102,9 +109,7 @@ def _collect_rows(
|
||||
else:
|
||||
name_rev = rev[:7]
|
||||
|
||||
exp_name = exp.get("name", "")
|
||||
tip = exp.get("checkpoint_tip")
|
||||
|
||||
parent_rev = exp.get("checkpoint_parent", "")
|
||||
parent_exp = experiments.get(parent_rev, {}).get("data", {})
|
||||
parent_tip = parent_exp.get("checkpoint_tip")
|
||||
@@ -130,26 +135,28 @@ def _collect_rows(
|
||||
if not is_baseline:
|
||||
new_checkpoint = not (tip and tip == parent_tip)
|
||||
|
||||
row = [
|
||||
exp_name,
|
||||
name_rev,
|
||||
typ,
|
||||
_format_time(exp.get("timestamp"), fill_value, iso),
|
||||
parent,
|
||||
state,
|
||||
executor,
|
||||
]
|
||||
fill_value = FILL_VALUE_ERRORED if results.get("error") else fill_value
|
||||
row_dict["Experiment"] = exp.get("name", "")
|
||||
row_dict["rev"] = name_rev
|
||||
row_dict["typ"] = typ
|
||||
row_dict["Created"] = _format_time(
|
||||
exp.get("timestamp"), fill_value, iso
|
||||
)
|
||||
row_dict["parent"] = parent
|
||||
row_dict["State"] = state
|
||||
row_dict["Executor"] = exp.get("executor", fill_value)
|
||||
|
||||
_extend_row(
|
||||
row,
|
||||
row_dict,
|
||||
metric_names,
|
||||
metric_headers,
|
||||
exp.get("metrics", {}).items(),
|
||||
precision,
|
||||
fill_value=fill_value,
|
||||
)
|
||||
_extend_row(
|
||||
row,
|
||||
row_dict,
|
||||
param_names,
|
||||
param_headers,
|
||||
exp.get("params", {}).items(),
|
||||
precision,
|
||||
fill_value=fill_value,
|
||||
@@ -158,8 +165,8 @@ def _collect_rows(
|
||||
hash_info = exp.get("deps", {}).get(dep, {}).get("hash")
|
||||
if hash_info is not None:
|
||||
hash_info = hash_info[:7]
|
||||
row.append(hash_info or fill_value)
|
||||
yield row
|
||||
row_dict[dep] = hash_info
|
||||
yield list(row_dict.values())
|
||||
|
||||
|
||||
def _sort_column(sort_by, metric_names, param_names):
|
||||
@@ -225,13 +232,9 @@ def _format_time(datetime_obj, fill_value=FILL_VALUE, iso=False):
|
||||
return datetime_obj.strftime(fmt)
|
||||
|
||||
|
||||
def _extend_row(row, names, items, precision, fill_value=FILL_VALUE):
|
||||
def _extend_row(row, names, headers, items, precision, fill_value=FILL_VALUE):
|
||||
from dvc.compare import _format_field, with_value
|
||||
|
||||
if not items:
|
||||
row.extend(fill_value for keys in names.values() for _ in keys)
|
||||
return
|
||||
|
||||
for fname, data in items:
|
||||
item = data.get("data", {})
|
||||
item = flatten(item) if isinstance(item, dict) else {fname: item}
|
||||
@@ -243,7 +246,11 @@ def _extend_row(row, names, items, precision, fill_value=FILL_VALUE):
|
||||
# wrap field data in ui.rich_text, otherwise rich may
|
||||
# interpret unescaped braces from list/dict types as rich
|
||||
# markup tags
|
||||
row.append(ui.rich_text(str(_format_field(value, precision))))
|
||||
value = ui.rich_text(str(_format_field(value, precision)))
|
||||
if name in headers:
|
||||
row[name] = value
|
||||
else:
|
||||
row[f"{fname}:{name}"] = value
|
||||
|
||||
|
||||
def experiments_table(
|
||||
@@ -264,14 +271,15 @@ def experiments_table(
|
||||
|
||||
from dvc.compare import TabularData
|
||||
|
||||
td = TabularData(
|
||||
lconcat(headers, metric_headers, param_headers, deps_names),
|
||||
fill_value=fill_value,
|
||||
)
|
||||
all_headers = lconcat(headers, metric_headers, param_headers, deps_names)
|
||||
td = TabularData(all_headers, fill_value=fill_value)
|
||||
for base_rev, experiments in all_experiments.items():
|
||||
rows = _collect_rows(
|
||||
base_rev,
|
||||
experiments,
|
||||
all_headers,
|
||||
metric_headers,
|
||||
param_headers,
|
||||
metric_names,
|
||||
param_names,
|
||||
deps_names,
|
||||
|
||||
@@ -640,16 +640,7 @@ def test_show_outs(tmp_dir, dvc, scm):
|
||||
deps=["copy.py"],
|
||||
outs=["out"],
|
||||
)
|
||||
scm.add(
|
||||
[
|
||||
"dvc.yaml",
|
||||
"dvc.lock",
|
||||
"copy.py",
|
||||
"params.yaml",
|
||||
"metrics.yaml",
|
||||
".gitignore",
|
||||
]
|
||||
)
|
||||
|
||||
scm.commit("init")
|
||||
|
||||
outs = dvc.experiments.show()["workspace"]["baseline"]["data"]["outs"]
|
||||
@@ -662,6 +653,76 @@ def test_show_outs(tmp_dir, dvc, scm):
|
||||
}
|
||||
|
||||
|
||||
def test_metrics_renaming(tmp_dir, dvc, scm, capsys):
|
||||
tmp_dir.gen("copy.py", COPY_SCRIPT)
|
||||
params_file = tmp_dir / "params.yaml"
|
||||
params_data = {
|
||||
"foo": 1,
|
||||
}
|
||||
(tmp_dir / params_file).dump(params_data)
|
||||
|
||||
dvc.run(
|
||||
cmd="python copy.py params.yaml metrics.yaml",
|
||||
metrics_no_cache=["metrics.yaml"],
|
||||
params=["foo"],
|
||||
name="copy-file",
|
||||
deps=["copy.py"],
|
||||
)
|
||||
scm.add(
|
||||
[
|
||||
"dvc.yaml",
|
||||
"dvc.lock",
|
||||
"copy.py",
|
||||
"params.yaml",
|
||||
"metrics.yaml",
|
||||
".gitignore",
|
||||
]
|
||||
)
|
||||
|
||||
scm.commit("metrics.yaml")
|
||||
metrics_rev = scm.get_rev()
|
||||
|
||||
dvc.run(
|
||||
cmd="python copy.py params.yaml scores.yaml",
|
||||
metrics_no_cache=["scores.yaml"],
|
||||
params=["foo"],
|
||||
name="copy-file",
|
||||
deps=["copy.py"],
|
||||
)
|
||||
scm.add(
|
||||
[
|
||||
"dvc.yaml",
|
||||
"dvc.lock",
|
||||
"params.yaml",
|
||||
"scores.yaml",
|
||||
]
|
||||
)
|
||||
scm.commit("scores.yaml")
|
||||
scores_rev = scm.get_rev()
|
||||
|
||||
capsys.readouterr()
|
||||
assert main(["exp", "show", "--csv", "-A"]) == 0
|
||||
cap = capsys.readouterr()
|
||||
|
||||
def _get_rev_isotimestamp(rev):
|
||||
return datetime.fromtimestamp(
|
||||
scm.gitpython.repo.rev_parse(rev).committed_date
|
||||
).isoformat()
|
||||
|
||||
assert (
|
||||
"master,{},baseline,{},,1,,1".format(
|
||||
scores_rev[:7], _get_rev_isotimestamp(scores_rev)
|
||||
)
|
||||
in cap.out
|
||||
)
|
||||
assert (
|
||||
",{},baseline,{},,,1,1".format(
|
||||
metrics_rev[:7], _get_rev_isotimestamp(metrics_rev)
|
||||
)
|
||||
in cap.out
|
||||
)
|
||||
|
||||
|
||||
def test_show_sorted_deps(tmp_dir, dvc, scm, capsys):
|
||||
tmp_dir.gen("a", "a")
|
||||
tmp_dir.gen("b", "b")
|
||||
|
||||
Reference in New Issue
Block a user