From e1b34442aa5eae8785ed5691ee0152b0bb4d9334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Redzy=C5=84ski?= Date: Wed, 23 Sep 2020 16:02:12 +0200 Subject: [PATCH] plot: accept any viable target in dvc repo (#4602) --- dvc/repo/plots/__init__.py | 45 ++++++++++++++++++---------- tests/func/plots/test_plots.py | 55 +++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/dvc/repo/plots/__init__.py b/dvc/repo/plots/__init__.py index 1d9165ea7..82702230a 100644 --- a/dvc/repo/plots/__init__.py +++ b/dvc/repo/plots/__init__.py @@ -1,8 +1,10 @@ import logging +import os from funcy import first, project -from dvc.exceptions import DvcException, NoPlotsError, OutputNotFoundError +from dvc.exceptions import DvcException, NoPlotsError +from dvc.path_info import PathInfo from dvc.schema import PLOT_PROPS from dvc.tree.repo import RepoTree from dvc.utils import relpath @@ -142,23 +144,34 @@ class Plots: def _collect_plots(repo, targets=None, rev=None): - def _targets_to_outs(targets): - for t in targets: - try: - (out,) = repo.find_outs_by_path(t) - yield out - except OutputNotFoundError: - logger.warning( - "File '{}' was not found at: '{}'. It will not be " - "plotted.".format(t, rev) - ) + plots = {out for stage in repo.stages for out in stage.outs if out.plot} - if targets: - outs = _targets_to_outs(targets) - else: - outs = (out for stage in repo.stages for out in stage.outs if out.plot) + def to_result(plots): + return {plot.path_info: _plot_props(plot) for plot in plots} - return {out.path_info: _plot_props(out) for out in outs} + if not targets: + return to_result(plots) + + target_infos = {PathInfo(os.path.abspath(target)) for target in targets} + + target_plots = set() + for p in plots: + if p.path_info in target_infos: + target_plots.add(p) + target_infos.remove(p.path_info) + + tree = RepoTree(repo) + result = to_result(target_plots) + + for t in target_infos: + if tree.isfile(t): + result[t] = {} + else: + logger.warning( + "'%s' was not found at: '%s'. It will not be plotted.", t, rev, + ) + + return result def _plot_props(out): diff --git a/tests/func/plots/test_plots.py b/tests/func/plots/test_plots.py index 75f5f3ae1..27c5d07d3 100644 --- a/tests/func/plots/test_plots.py +++ b/tests/func/plots/test_plots.py @@ -330,7 +330,7 @@ def test_plot_even_if_metric_missing( with caplog.at_level(logging.WARNING, "dvc"): plots = dvc.plots.show(revs=["v1", "v2"], targets=["metric.json"]) assert ( - "File 'metric.json' was not found at: 'v1'. " + "'metric.json' was not found at: 'v1'. " "It will not be plotted." in caplog.text ) @@ -602,3 +602,56 @@ def test_multiple_plots(tmp_dir, scm, dvc, run_copy_metrics): ) assert len(dvc.plots.show().keys()) == 2 + + +def test_show_non_plot(tmp_dir, scm, dvc): + metric = [ + {"first_val": 100, "val": 2}, + {"first_val": 200, "val": 3}, + ] + _write_json(tmp_dir, metric, "metric.json") + plot_string = dvc.plots.show(targets=["metric.json"])["metric.json"] + + plot_content = json.loads(plot_string) + assert plot_content["data"]["values"] == [ + { + "val": 2, + PlotData.INDEX_FIELD: 0, + "first_val": 100, + "rev": "workspace", + }, + { + "val": 3, + PlotData.INDEX_FIELD: 1, + "first_val": 200, + "rev": "workspace", + }, + ] + assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD + assert plot_content["encoding"]["y"]["field"] == "val" + + +def test_show_non_plot_and_plot_with_params( + tmp_dir, scm, dvc, run_copy_metrics +): + metric = [ + {"first_val": 100, "val": 2}, + {"first_val": 200, "val": 3}, + ] + _write_json(tmp_dir, metric, "metric.json") + run_copy_metrics( + "metric.json", "metric2.json", plots_no_cache=["metric2.json"] + ) + + dvc.plots.modify("metric2.json", props={"title": "TITLE"}) + result = dvc.plots.show(targets=["metric.json", "metric2.json"]) + + plot_content = json.loads(result["metric.json"]) + plot2_content = json.loads(result["metric2.json"]) + + assert plot2_content["title"] == "TITLE" + + assert plot_content != plot2_content + plot_content.pop("title") + plot2_content.pop("title") + assert plot_content == plot2_content