Organize metrics as table (#4706)

* WIP fixes #4621

* changes to all_branch if condition

* flatten_dict changes

* fix one test

* minor changes

* minor changes

* add precision

* tests and added precision to arguments

Co-authored-by: indh8717 <[email protected]>
This commit is contained in:
Indhu Kumar
2020-12-02 19:46:48 +02:00
committed by GitHub
co-authored by indh8717
parent 2d70bc5ec4
commit 2e9fac5fb3
3 changed files with 153 additions and 19 deletions
+49 -13
View File
@@ -12,33 +12,60 @@ DEFAULT_PRECISION = 5
def _show_metrics(
metrics, all_branches=False, all_tags=False, all_commits=False
metrics,
all_branches=False,
all_tags=False,
all_commits=False,
precision=None,
):
from dvc.utils.diff import format_dict
from dvc.utils.diff import format_dict, table
from dvc.utils.flatten import flatten
# When `metrics` contains a `None` key, it means that some files
# specified as `targets` in `repo.metrics.show` didn't contain any metrics.
missing = metrics.pop(None, None)
with_rev = any([all_branches, all_tags, all_commits])
header_set = set()
rows = []
lines = []
for branch, val in metrics.items():
if all_branches or all_tags or all_commits:
lines.append(f"{branch}:")
if precision is None:
precision = DEFAULT_PRECISION
for fname, metric in val.items():
def _round(val):
if isinstance(val, float):
return round(val, precision)
return val
for _branch, val in metrics.items():
for _fname, metric in val.items():
if not isinstance(metric, dict):
lines.append("\t{}: {}".format(fname, str(metric)))
header_set.add("")
continue
for key, _val in flatten(format_dict(metric)).items():
header_set.add(key)
header = sorted(header_set)
for branch, val in metrics.items():
for fname, metric in val.items():
row = []
if with_rev:
row.append(branch)
row.append(fname)
if not isinstance(metric, dict):
row.append(str(metric))
rows.append(row)
continue
flattened_val = flatten(format_dict(metric))
lines.append(f"\t{fname}:")
for key, value in flatten(format_dict(metric)).items():
lines.append(f"\t\t{key}: {value}")
for i in header:
row.append(_round(flattened_val.get(i)))
rows.append(row)
header.insert(0, "Path")
if with_rev:
header.insert(0, "Revision")
if missing:
raise BadMetricError(missing)
return "\n".join(lines)
return table(header, rows, markdown=False)
class CmdMetricsBase(CmdBase):
@@ -211,6 +238,15 @@ def add_parser(subparsers, parent_parser):
"metrics files."
),
)
metrics_show_parser.add_argument(
"--precision",
type=int,
help=(
"Round metrics to `n` digits precision after the decimal point. "
f"Rounds to {DEFAULT_PRECISION} digits by default."
),
metavar="<n>",
)
metrics_show_parser.set_defaults(func=CmdMetricsShow)
METRICS_DIFF_HELP = (
+1 -1
View File
@@ -982,7 +982,7 @@ class TestShouldDisplayMetricsOnReproWithMetricsOption(TestDvc):
)
self.assertEqual(0, ret)
expected_metrics_display = f"{metrics_file}: {metrics_value}"
expected_metrics_display = f"Path\n{metrics_file} {metrics_value}\n"
self.assertIn(expected_metrics_display, self._caplog.text)
+103 -5
View File
@@ -226,9 +226,107 @@ def test_metrics_show_with_valid_falsey_values():
all_branches=True,
) == textwrap.dedent(
"""\
branch_1:
\tmetrics.json:
\t\ta: 0
\t\tb.ad: 0.0
\t\tb.bc: 0.0"""
Revision Path a b.ad b.bc
branch_1 metrics.json 0 0.0 0.0"""
)
def test_metrics_show_with_no_revision():
assert _show_metrics(
{"branch_1": {"metrics.json": {"a": 0, "b": {"ad": 0.0, "bc": 0.0}}}},
all_branches=False,
) == textwrap.dedent(
"""\
Path a b.ad b.bc
metrics.json 0 0.0 0.0"""
)
def test_metrics_show_with_non_dict_values():
assert _show_metrics(
{"branch_1": {"metrics.json": 1}}, all_branches=True,
) == textwrap.dedent(
"""\
Revision Path
branch_1 metrics.json 1"""
)
def test_metrics_show_with_multiple_revision():
assert _show_metrics(
{
"branch_1": {"metrics.json": {"a": 1, "b": {"ad": 1, "bc": 2}}},
"branch_2": {"metrics.json": {"a": 1, "b": {"ad": 3, "bc": 4}}},
},
all_branches=True,
) == textwrap.dedent(
"""\
Revision Path a b.ad b.bc
branch_1 metrics.json 1 1 2
branch_2 metrics.json 1 3 4"""
)
def test_metrics_show_with_one_revision_multiple_paths():
assert _show_metrics(
{
"branch_1": {
"metrics.json": {"a": 1, "b": {"ad": 0.1, "bc": 1.03}},
"metrics_1.json": {"a": 2.3, "b": {"ad": 6.5, "bc": 7.9}},
}
},
all_branches=True,
) == textwrap.dedent(
"""\
Revision Path a b.ad b.bc
branch_1 metrics.json 1 0.1 1.03
branch_1 metrics_1.json 2.3 6.5 7.9"""
)
def test_metrics_show_with_different_metrics_header():
assert _show_metrics(
{
"branch_1": {"metrics.json": {"b": {"ad": 1, "bc": 2}, "c": 4}},
"branch_2": {"metrics.json": {"a": 1, "b": {"ad": 3, "bc": 4}}},
},
all_branches=True,
) == textwrap.dedent(
"""\
Revision Path a b.ad b.bc c
branch_1 metrics.json — 1 2 4
branch_2 metrics.json 1 3 4 —"""
)
def test_metrics_show_precision():
metrics = {
"branch_1": {
"metrics.json": {
"a": 1.098765366365355,
"b": {"ad": 1.5342673, "bc": 2.987725527},
}
}
}
assert _show_metrics(metrics, all_branches=True,) == textwrap.dedent(
"""\
Revision Path a b.ad b.bc
branch_1 metrics.json 1.09877 1.53427 2.98773"""
)
assert _show_metrics(
metrics, all_branches=True, precision=4
) == textwrap.dedent(
"""\
Revision Path a b.ad b.bc
branch_1 metrics.json 1.0988 1.5343 2.9877"""
)
assert _show_metrics(
metrics, all_branches=True, precision=7
) == textwrap.dedent(
"""\
Revision Path a b.ad b.bc
branch_1 metrics.json 1.0987654 1.5342673 2.9877255"""
)