diff --git a/dvc/command/run.py b/dvc/command/run.py index 3499cf41c..f1ee4d479 100644 --- a/dvc/command/run.py +++ b/dvc/command/run.py @@ -44,6 +44,7 @@ class CmdRun(CmdBase): plots_no_cache=self.args.plots_no_cache, live=self.args.live, live_summary=not self.args.live_no_summary, + live_report=not self.args.live_no_report, deps=self.args.deps, params=self.args.params, fname=self.args.file, @@ -165,13 +166,19 @@ def add_parser(subparsers, parent_parser): metavar="", ) run_parser.add_argument( - "--live", help=argparse.SUPPRESS, metavar="", + "--live", help="Declare output as dvclive.", metavar="", ) run_parser.add_argument( "--live-no-summary", action="store_true", default=False, - help=argparse.SUPPRESS, + help="Signal dvclive logger to not dump latest metrics file.", + ) + run_parser.add_argument( + "--live-no-report", + action="store_true", + default=False, + help="Signal dvclive logger to not produce training report.", ) run_parser.add_argument( "--file", metavar="", help=argparse.SUPPRESS, diff --git a/dvc/env.py b/dvc/env.py index 5ddcfbc98..ad611f80c 100644 --- a/dvc/env.py +++ b/dvc/env.py @@ -4,3 +4,4 @@ DVC_PAGER = "DVC_PAGER" DVC_ROOT = "DVC_ROOT" DVCLIVE_PATH = "DVCLIVE_PATH" DVCLIVE_SUMMARY = "DVCLIVE_SUMMARY" +DVCLIVE_REPORT = "DVCLIVE_REPORT" diff --git a/dvc/output/base.py b/dvc/output/base.py index 75f88797f..8303a6606 100644 --- a/dvc/output/base.py +++ b/dvc/output/base.py @@ -9,7 +9,7 @@ from voluptuous import Any import dvc.prompt as prompt from dvc.cache import NamedCache -from dvc.env import DVCLIVE_PATH, DVCLIVE_SUMMARY +from dvc.env import DVCLIVE_PATH, DVCLIVE_REPORT, DVCLIVE_SUMMARY from dvc.exceptions import ( CheckoutError, CollectCacheError, @@ -81,6 +81,7 @@ class BaseOutput: PARAM_ISEXEC = "isexec" PARAM_LIVE = "live" PARAM_LIVE_SUMMARY = "summary" + PARAM_LIVE_REPORT = "report" METRIC_SCHEMA = Any( None, @@ -620,5 +621,8 @@ class BaseOutput: env[DVCLIVE_SUMMARY] = str( int(config.get(BaseOutput.PARAM_LIVE_SUMMARY, True)) ) + env[DVCLIVE_REPORT] = str( + int(config.get(BaseOutput.PARAM_LIVE_REPORT, True)) + ) return env return {} diff --git a/dvc/schema.py b/dvc/schema.py index 41fb905a7..451399b26 100644 --- a/dvc/schema.py +++ b/dvc/schema.py @@ -69,6 +69,7 @@ PLOT_PSTAGE_SCHEMA = {str: Any(PLOT_PROPS_SCHEMA, [PLOT_PROPS_SCHEMA])} LIVE_PROPS = { BaseOutput.PARAM_LIVE_SUMMARY: bool, + BaseOutput.PARAM_LIVE_REPORT: bool, } LIVE_PROPS_SCHEMA = {**PLOT_PROPS_SCHEMA, **LIVE_PROPS} LIVE_PSTAGE_SCHEMA = {str: LIVE_PROPS_SCHEMA} diff --git a/dvc/stage/utils.py b/dvc/stage/utils.py index a621589b6..9b8f98df7 100644 --- a/dvc/stage/utils.py +++ b/dvc/stage/utils.py @@ -55,9 +55,7 @@ def fill_stage_outputs(stage, **kwargs): stage.outs = [] - stage.outs += _load_live_outputs( - stage, kwargs.get("live", None), kwargs.get("live_summary", False) - ) + stage.outs += _load_live_output(stage, **kwargs) for key in keys: stage.outs += loads_from( @@ -71,17 +69,21 @@ def fill_stage_outputs(stage, **kwargs): ) -def _load_live_outputs(stage, live_l=None, live_summary=False): +def _load_live_output( + stage, live=None, live_summary=False, live_report=False, **kwargs +): from dvc.output import BaseOutput, loads_from outs = [] - if live_l: - + if live: outs += loads_from( stage, - [live_l], + [live], use_cache=False, - live={BaseOutput.PARAM_LIVE_SUMMARY: live_summary}, + live={ + BaseOutput.PARAM_LIVE_SUMMARY: live_summary, + BaseOutput.PARAM_LIVE_REPORT: live_report, + }, ) return outs diff --git a/tests/func/test_live.py b/tests/func/test_live.py index 54790d621..f0bf11acf 100644 --- a/tests/func/test_live.py +++ b/tests/func/test_live.py @@ -7,7 +7,7 @@ from dvc.exceptions import MetricsError LIVE_SCRITP = dedent( """ - from dvclive import dvclive + import dvclive import sys r = 2 for i in range(r): @@ -22,7 +22,7 @@ def live_stage(tmp_dir, scm, dvc): pytest.skip("dvclive does not exist yet") - def make(summary=True): + def make(summary=True, report=True): tmp_dir.gen("train.py", LIVE_SCRITP) tmp_dir.gen("params.yaml", "foo: 1") stage = dvc.run( @@ -32,6 +32,7 @@ def live_stage(tmp_dir, scm, dvc): name="live_stage", live="logs", live_summary=summary, + live_report=report, ) scm.add(["dvc.yaml", "dvc.lock", "train.py", "params.yaml"]) @@ -41,8 +42,9 @@ def live_stage(tmp_dir, scm, dvc): yield make +@pytest.mark.parametrize("report", (True, False)) @pytest.mark.parametrize("summary", (True, False)) -def test_export_config_tmp(tmp_dir, dvc, mocker, summary): +def test_export_config_tmp(tmp_dir, dvc, mocker, summary, report): run_spy = mocker.spy(stage_module.run, "_run") tmp_dir.gen("src", "dependency") dvc.run( @@ -51,6 +53,7 @@ def test_export_config_tmp(tmp_dir, dvc, mocker, summary): name="run_logger", live="logs", live_summary=summary, + live_report=report, ) assert run_spy.call_count == 1 @@ -62,6 +65,9 @@ def test_export_config_tmp(tmp_dir, dvc, mocker, summary): assert "DVCLIVE_SUMMARY" in kwargs["env"] assert kwargs["env"]["DVCLIVE_SUMMARY"] == str(int(summary)) + assert "DVCLIVE_REPORT" in kwargs["env"] + assert kwargs["env"]["DVCLIVE_REPORT"] == str(int(report)) + @pytest.mark.parametrize("summary", (True, False)) def test_export_config(tmp_dir, dvc, mocker, summary, live_stage): @@ -115,3 +121,10 @@ def test_experiments_track_summary(tmp_dir, scm, dvc, live_stage): res = dvc.experiments.show() assert "logs.json" in res[baseline_rev][exp_rev]["metrics"].keys() + + +@pytest.mark.parametrize("report", [True, False]) +def test_live_report(tmp_dir, dvc, live_stage, report): + live_stage(report=report) + + assert (tmp_dir / "logs.html").is_file() == report diff --git a/tests/unit/command/test_run.py b/tests/unit/command/test_run.py index 8ab68d4a6..dabb3d20e 100644 --- a/tests/unit/command/test_run.py +++ b/tests/unit/command/test_run.py @@ -25,6 +25,7 @@ def test_run(mocker, dvc): "--live", "live", "--live-no-summary", + "--live-no-report", "--file", "file", "--wdir", @@ -71,6 +72,7 @@ def test_run(mocker, dvc): params=["file:param1,param2", "param3"], live="live", live_summary=False, + live_report=False, fname="file", wdir="wdir", no_exec=True, @@ -101,6 +103,7 @@ def test_run_args_from_cli(mocker, dvc): plots_no_cache=[], live=None, live_summary=True, + live_report=True, outs_persist=[], outs_persist_no_cache=[], checkpoints=[], @@ -135,6 +138,7 @@ def test_run_args_with_spaces(mocker, dvc): plots_no_cache=[], live=None, live_summary=True, + live_report=True, outs_persist=[], outs_persist_no_cache=[], checkpoints=[],