diff --git a/dvc/command/metrics.py b/dvc/command/metrics.py index a6c38c030..c2db5dd28 100644 --- a/dvc/command/metrics.py +++ b/dvc/command/metrics.py @@ -7,6 +7,9 @@ from dvc.exceptions import BadMetricError, DvcException logger = logging.getLogger(__name__) +DEFAULT_PRECISION = 5 + + def show_metrics( metrics, all_branches=False, all_tags=False, all_commits=False ): @@ -63,11 +66,20 @@ class CmdMetricsShow(CmdBase): return 0 -def _show_diff(diff, markdown=False, no_path=False, old=False): +def _show_diff(diff, markdown=False, no_path=False, old=False, precision=None): from collections import OrderedDict from dvc.utils.diff import table + if precision is None: + precision = DEFAULT_PRECISION + + def _round(val): + if isinstance(val, float): + return round(val, precision) + + return val + rows = [] for fname, mdiff in diff.items(): sorted_mdiff = OrderedDict(sorted(mdiff.items())) @@ -75,9 +87,9 @@ def _show_diff(diff, markdown=False, no_path=False, old=False): row = [] if no_path else [fname] row.append(metric) if old: - row.append(change.get("old")) - row.append(change["new"]) - row.append(change.get("diff", "diff not supported")) + row.append(_round(change.get("old"))) + row.append(_round(change["new"])) + row.append(_round(change.get("diff", "diff not supported"))) rows.append(row) header = [] if no_path else ["Path"] @@ -108,7 +120,11 @@ class CmdMetricsDiff(CmdBase): logger.info(json.dumps(diff)) else: table = _show_diff( - diff, self.args.show_md, self.args.no_path, self.args.old + diff, + self.args.show_md, + self.args.no_path, + self.args.old, + precision=self.args.precision, ) if table: logger.info(table) @@ -189,8 +205,10 @@ def add_parser(subparsers, parent_parser): ) metrics_show_parser.set_defaults(func=CmdMetricsShow) - METRICS_DIFF_HELP = "Show changes in metrics between commits" - " in the DVC repository, or between a commit and the workspace." + METRICS_DIFF_HELP = ( + "Show changes in metrics between commits in the DVC repository, or " + "between a commit and the workspace." + ) metrics_diff_parser = metrics_subparsers.add_parser( "diff", parents=[parent_parser], @@ -255,4 +273,13 @@ def add_parser(subparsers, parent_parser): default=False, help="Show old metric value.", ) + metrics_diff_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="", + ) metrics_diff_parser.set_defaults(func=CmdMetricsDiff) diff --git a/tests/func/metrics/test_diff.py b/tests/func/metrics/test_diff.py index ce62b7b57..752094df8 100644 --- a/tests/func/metrics/test_diff.py +++ b/tests/func/metrics/test_diff.py @@ -1,7 +1,10 @@ import json +import logging import yaml +from dvc.main import main + def test_metrics_diff_simple(tmp_dir, scm, dvc, run_copy_metrics): def _gen(val): @@ -170,3 +173,26 @@ def test_metrics_diff_dirty(tmp_dir, scm, dvc, run_copy_metrics): 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", "--old"]) == 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" + ) diff --git a/tests/unit/command/test_metrics.py b/tests/unit/command/test_metrics.py index d0eb89e1b..45392ad91 100644 --- a/tests/unit/command/test_metrics.py +++ b/tests/unit/command/test_metrics.py @@ -20,6 +20,8 @@ def test_metrics_diff(dvc, mocker): "--show-md", "--no-path", "--old", + "--precision", + "10", ] ) assert cli_args.func == CmdMetricsDiff @@ -123,13 +125,27 @@ def test_metrics_show(dvc, mocker): ) -def test_metrics_diff_prec(): - assert _show_diff( - {"other.json": {"a.b": {"old": 0.0042, "new": 0.0043, "diff": 0.0001}}} - ) == textwrap.dedent( +def test_metrics_diff_precision(): + diff = { + "other.json": { + "a.b": { + "old": 0.1234567, + "new": 0.765432101234567, + "diff": 0.641975401234567, + } + } + } + + assert _show_diff(diff) == textwrap.dedent( """\ Path Metric Value Change - other.json a.b 0.0043 0.0001""" + other.json a.b 0.76543 0.64198""" + ) + + assert _show_diff(diff, precision=10) == textwrap.dedent( + """\ + Path Metric Value Change + other.json a.b 0.7654321012 0.6419754012""" )