diff --git a/dvc/command/plots.py b/dvc/command/plots.py index 47fba416fb..97439b533a 100644 --- a/dvc/command/plots.py +++ b/dvc/command/plots.py @@ -94,8 +94,14 @@ def run(self): ) ui.write(index_path.as_uri()) - - if self.args.open: + auto_open = self.repo.config["plots"].get("auto_open", False) + if self.args.open or auto_open: + if not auto_open: + ui.write( + "To enable auto opening, you can run:\n" + "\n" + "\tdvc config plots.auto_open true" + ) return ui.open_browser(index_path) return 0 diff --git a/dvc/config_schema.py b/dvc/config_schema.py index 24bb165ee3..723fec3dae 100644 --- a/dvc/config_schema.py +++ b/dvc/config_schema.py @@ -256,7 +256,10 @@ class RelPath(str): # enabled by default. It's of no use, kept for backward compatibility. Optional("parametrization", default=True): Bool, }, - "plots": {"html_template": str}, + "plots": { + "html_template": str, + Optional("auto_open", default=False): Bool, + }, "exp": { "code": str, "data": str, diff --git a/dvc/repo/live.py b/dvc/repo/live.py index 265b5c71c6..fdeb3f6baf 100644 --- a/dvc/repo/live.py +++ b/dvc/repo/live.py @@ -20,7 +20,6 @@ def webbrowser_open(url: str) -> int: def create_summary(out): - assert out.live and out.live["html"] metrics, plots = out.repo.live.show(out.fs_path) @@ -31,8 +30,8 @@ def create_summary(out): index_path = render( out.repo, renderers, metrics=metrics, path=html_path, refresh_seconds=5 ) - - webbrowser_open(index_path) + if out.repo.config["plots"].get("auto_open", False): + webbrowser_open(index_path) def summary_fs_path(out: "Output") -> Optional[str]: diff --git a/tests/func/test_live.py b/tests/func/test_live.py index 9f702f5872..049487621a 100644 --- a/tests/func/test_live.py +++ b/tests/func/test_live.py @@ -241,7 +241,14 @@ def test_live_checkpoints_resume( assert checkpoints_metric(results, "logs.json", "metric2") == [8, 6, 4, 2] -def test_dvc_generates_html_during_run(tmp_dir, dvc, mocker, live_stage): +@pytest.mark.parametrize("auto_open", [False, True]) +def test_dvc_generates_html_during_run( + tmp_dir, dvc, mocker, live_stage, auto_open +): + if auto_open: + with dvc.config.edit() as conf: + conf["plots"]["auto_open"] = True + show_spy = mocker.spy(dvc.live, "show") webbrowser_open = mocker.patch("dvc.repo.live.webbrowser_open") @@ -265,7 +272,7 @@ def test_dvc_generates_html_during_run(tmp_dir, dvc, mocker, live_stage): live_stage(summary=True, live="logs", code=script) assert show_spy.call_count == 2 - assert webbrowser_open.call_count == 2 + assert webbrowser_open.call_count == (2 if auto_open else 0) def test_dvclive_stage_with_different_wdir(tmp_dir, scm, dvc): diff --git a/tests/unit/command/test_plots.py b/tests/unit/command/test_plots.py index 8950f36f80..c581af57f1 100644 --- a/tests/unit/command/test_plots.py +++ b/tests/unit/command/test_plots.py @@ -138,11 +138,19 @@ def test_plots_diff_vega(dvc, mocker, capsys, plots_data): render_mock.assert_not_called() -def test_plots_diff_open(tmp_dir, dvc, mocker, capsys, plots_data): +@pytest.mark.parametrize("auto_open", [True, False]) +def test_plots_diff_open(tmp_dir, dvc, mocker, capsys, plots_data, auto_open): mocked_open = mocker.patch("webbrowser.open", return_value=True) - cli_args = parse_args( - ["plots", "diff", "--targets", "plots.csv", "--open"] - ) + + args = ["plots", "diff", "--targets", "plots.csv"] + + if auto_open: + with dvc.config.edit() as conf: + conf["plots"]["auto_open"] = True + else: + args.append("--open") + + cli_args = parse_args(args) cmd = cli_args.func(cli_args) mocker.patch("dvc.repo.plots.diff.diff", return_value=plots_data)