def test_when_params_is_omitted_in_interactive_mode(tmp_dir, scm, dvc): (tmp_dir / "params.yaml").dump({"foo": 1}) inp = io.StringIO("python script.py\nscript.py\ndata\nmodels\nn") init( dvc, interactive=True, stream=inp, defaults=CmdExperimentsInit.DEFAULTS ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "default": { "cmd": "python script.py", "deps": ["data", "script.py"], "metrics": [{"metrics.json": {"cache": False}}], "outs": ["models"], "plots": [{"plots": {"cache": False}}], } } } assert not (tmp_dir / "dvc.lock").exists() scm._reset() assert scm.is_tracked("dvc.yaml") assert not scm.is_tracked("params.yaml") assert scm.is_tracked(".gitignore") assert scm.is_ignored("models")
def test_init_with_type_live_and_models_plots_provided( tmp_dir, dvc, interactive, inp ): (tmp_dir / "params.yaml").dump({"foo": 1}) init( dvc, type="live", interactive=interactive, stream=inp, defaults=CmdExperimentsInit.DEFAULTS, overrides={"cmd": "cmd", "metrics": "m", "plots": "p"}, ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "live": { "cmd": "cmd", "deps": ["data", "src"], "live": {"dvclive": {"html": True, "summary": True}}, "metrics": [{"m": {"cache": False}}], "outs": [{"models": {"checkpoint": True}}], "params": ["foo"], "plots": [{"p": {"cache": False}}], } } }
def test_init_with_no_defaults_interactive(tmp_dir, dvc): inp = io.StringIO( "python script.py\n" "script.py\n" "data\n" "model\n" "n\n" "metric\n" "n\n" ) init( dvc, defaults={}, overrides={"cmd": "python script.py"}, interactive=True, stream=inp, ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "default": { "cmd": "python script.py", "deps": ["python script.py", "script.py"], "metrics": [{"metric": {"cache": False}}], "outs": ["data"], } } }
def test_init_interactive_params_validation(tmp_dir, dvc, capsys): tmp_dir.gen({"data": {"foo": "foo"}}) (tmp_dir / "params.yaml").dump({"foo": 1}) inp = io.StringIO( "python script.py\nscript.py\ndata\nmodels\nparams.json\ndata\n" ) init( dvc, stream=inp, interactive=True, defaults=CmdExperimentsInit.DEFAULTS ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "default": { "cmd": "python script.py", "deps": ["data", "script.py"], "metrics": [{"metrics.json": {"cache": False}}], "outs": ["models"], "params": ["foo"], "plots": [{"plots": {"cache": False}}], } } } out, err = capsys.readouterr() assert ( "Path to a parameters file [params.yaml, n to omit]: " "'params.json' does not exist. " "Please retry with an existing parameters file.\n" "Path to a parameters file [params.yaml, n to omit]: " "'data' is a directory. " "Please retry with an existing parameters file.\n" "Path to a parameters file [params.yaml, n to omit]:" ) in err assert not out
def test_init_interactive_when_no_path_prompts_need_to_be_asked( tmp_dir, dvc, extra_overrides, inp ): """When we pass everything that's required of, it should not prompt us.""" (tmp_dir / "params.yaml").dump({"foo": 1}) init( dvc, interactive=True, defaults=CmdExperimentsInit.DEFAULTS, overrides={**CmdExperimentsInit.DEFAULTS, **extra_overrides}, stream=inp, # we still need to confirm ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "default": { "cmd": "cmd", "deps": ["data", "src"], "live": {"dvclive": {"html": True, "summary": True}}, "metrics": [{"metrics.json": {"cache": False}}], # we specify `live` through `overrides`, # so it creates checkpoint-based output. "outs": [{"models": {"checkpoint": True}}], "params": ["foo"], "plots": [{"plots": {"cache": False}}], } } }
def test_init_with_no_defaults_non_interactive(tmp_dir, scm, dvc): init(dvc, defaults={}, overrides={"cmd": "python script.py"}) assert (tmp_dir / "dvc.yaml").parse() == { "stages": {"train": {"cmd": "python script.py"}} } scm._reset() assert not (tmp_dir / "dvc.lock").exists() assert scm.is_tracked("dvc.yaml")
def test_with_a_custom_name(tmp_dir, dvc): init(dvc, name="custom", overrides={"cmd": "cmd"}) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "custom": { "cmd": "cmd" } } }
def test_init_with_live_and_metrics_plots_provided(tmp_dir, dvc, interactive, inp): (tmp_dir / "params.yaml").dump({"foo": 1}) init( dvc, interactive=interactive, stream=inp, defaults=CmdExperimentsInit.DEFAULTS, overrides={ "cmd": "cmd", "live": "live", "metrics": "metrics.json", "plots": "plots", }, ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "train": { "cmd": "cmd", "deps": ["data", "src"], "metrics": [ { "live.json": { "cache": False } }, { "metrics.json": { "cache": False } }, ], "outs": ["models"], "params": [{ "params.yaml": None }], "plots": [ { os.path.join("live", "scalars"): { "cache": False } }, { "plots": { "cache": False } }, ], } } } assert (tmp_dir / "src").is_dir() assert (tmp_dir / "data").is_dir()
def test_creates_params_file_by_default(tmp_dir, dvc, interactive): init( dvc, interactive=interactive, defaults=CmdExperimentsInit.DEFAULTS, overrides={"cmd": "cmd"}, stream=io.StringIO(""), ) assert (tmp_dir / "params.yaml").is_file() assert (tmp_dir / "params.yaml").parse() == {}
def test_when_stage_already_exists_with_same_name(tmp_dir, dvc, interactive): (tmp_dir / "dvc.yaml").dump({"stages": {"train": {"cmd": "test"}}}) with pytest.raises(DuplicateStageName) as exc: init( dvc, interactive=interactive, overrides={"cmd": "true"}, defaults=CmdExperimentsInit.DEFAULTS, ) assert (str(exc.value) == "Stage 'train' already exists in 'dvc.yaml'. " "Use '--force' to overwrite.")
def test_when_stage_force_if_already_exists(tmp_dir, dvc): (tmp_dir / "params.yaml").dump({"foo": 1}) (tmp_dir / "dvc.yaml").dump({"stages": {"train": {"cmd": "test"}}}) init( dvc, force=True, overrides={"cmd": "true"}, defaults=CmdExperimentsInit.DEFAULTS, ) d = (tmp_dir / "dvc.yaml").parse() assert d["stages"]["train"]["cmd"] == "true"
def test_abort_confirmation(tmp_dir, dvc): (tmp_dir / "param").dump({"foo": 1}) inp = io.StringIO("./script\nscript\ndata\nmodel\nparam\nmetric\nplt\nn") with pytest.raises(DvcException) as exc: init( dvc, interactive=True, defaults=CmdExperimentsInit.DEFAULTS, stream=inp, ) assert str(exc.value) == "Aborting ..." assert not (tmp_dir / "dvc.yaml").exists() assert not (tmp_dir / "dvc.lock").exists()
def test_init_interactive_live(tmp_dir, scm, dvc, interactive, overrides, inp, capsys): overrides["live"] = "dvclive" (tmp_dir / "params.yaml").dump({"foo": {"bar": 1}}) init( dvc, interactive=interactive, defaults=CmdExperimentsInit.DEFAULTS, overrides=overrides, stream=inp, ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "train": { "cmd": "python script.py", "deps": ["data", "script.py"], "metrics": [{ "dvclive.json": { "cache": False } }], "outs": ["models"], "params": [{ "params.yaml": None }], "plots": [{ os.path.join("dvclive", "scalars"): { "cache": False } }], } } } assert not (tmp_dir / "dvc.lock").exists() assert (tmp_dir / "script.py").read_text() == "" assert (tmp_dir / "data").is_dir() scm._reset() assert scm.is_tracked("dvc.yaml") assert scm.is_tracked("params.yaml") assert scm.is_tracked(".gitignore") assert scm.is_ignored("models") out, err = capsys.readouterr() assert not out if interactive: assert "'script.py' does not exist, the file will be created." in err assert "'data' does not exist, the directory will be created." in err
def run(self): from dvc.command.stage import parse_cmd cmd = parse_cmd(self.args.command) if not self.args.interactive and not cmd: raise InvalidArgumentError("command is not specified") from dvc.repo.experiments.init import init defaults = {} if not self.args.explicit: config = self.repo.config["exp"] defaults.update({**self.DEFAULTS, **config}) cli_args = compact({ "cmd": cmd, "code": self.args.code, "data": self.args.data, "models": self.args.models, "metrics": self.args.metrics, "params": self.args.params, "plots": self.args.plots, "live": self.args.live, }) initialized_stage = init( self.repo, name=self.args.name, type=self.args.type, defaults=defaults, overrides=cli_args, interactive=self.args.interactive, force=self.args.force, ) text = ui.rich_text.assemble( "\n" if self.args.interactive else "", "Created ", (self.args.name, "bright_blue"), " stage in ", ("dvc.yaml", "green"), ".", ) if not self.args.run: text.append_text( ui.rich_text.assemble( " To run, use ", ('"dvc exp run"', "green"), ".\nSee ", (self.EXP_LINK, "repr.url"), ".", )) ui.write(text, styled=True) if self.args.run: return self.repo.experiments.run( targets=[initialized_stage.addressing]) return 0
def test_gen_output_dirs(tmp_dir, dvc): init( dvc, defaults=CmdExperimentsInit.DEFAULTS, overrides={ "cmd": "cmd", "models": "models/predict.h5", "metrics": "eval/scores.json", "plots": "eval/plots", "live": "eval/live", }, ) assert (tmp_dir / "models").is_dir() assert (tmp_dir / "eval").is_dir() assert (tmp_dir / "eval/plots").is_dir() assert (tmp_dir / "eval/live").is_dir() assert not (tmp_dir / "models/predict.h5").exists() assert not (tmp_dir / "eval/scores.json").exists()
def test_init_interactive_when_no_path_prompts_need_to_be_asked( tmp_dir, dvc, extra_overrides, inp): """When we pass everything that's required of, it should not prompt us.""" (tmp_dir / "params.yaml").dump({"foo": 1}) init( dvc, interactive=True, defaults=CmdExperimentsInit.DEFAULTS, overrides={ **CmdExperimentsInit.DEFAULTS, **extra_overrides }, stream=inp, ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "train": { "cmd": "cmd", "deps": ["data", "src"], "metrics": [ { "metrics.json": { "cache": False } }, ], "outs": ["models"], "params": [{ "params.yaml": None }], "plots": [ { "plots": { "cache": False } }, ], } } } assert (tmp_dir / "src").is_dir() assert (tmp_dir / "data").is_dir()
def test_init_interactive_default( tmp_dir, scm, dvc, interactive, overrides, inp, capsys ): (tmp_dir / "params.yaml").dump({"foo": {"bar": 1}}) init( dvc, interactive=interactive, defaults=CmdExperimentsInit.DEFAULTS, overrides=overrides, stream=inp, ) assert (tmp_dir / "dvc.yaml").parse() == { "stages": { "train": { "cmd": "python script.py", "deps": ["data", "script.py"], "metrics": [{"metrics.json": {"cache": False}}], "outs": ["models"], "params": ["foo"], "plots": [{"plots": {"cache": False}}], } } } assert not (tmp_dir / "dvc.lock").exists() scm._reset() assert scm.is_tracked("dvc.yaml") assert scm.is_tracked("params.yaml") assert scm.is_tracked(".gitignore") assert scm.is_ignored("models") out, err = capsys.readouterr() if interactive: assert "'script.py' does not exist in the workspace." in err assert "'data' does not exist in the workspace." in err assert not out
def run(self): from dvc.command.stage import parse_cmd cmd = parse_cmd(self.args.cmd) if not self.args.interactive and not cmd: raise InvalidArgumentError("command is not specified") from dvc.repo.experiments.init import init global_defaults = { "code": self.CODE, "data": self.DATA, "models": self.MODELS, "metrics": self.DEFAULT_METRICS, "params": self.DEFAULT_PARAMS, "plots": self.PLOTS, "live": self.DVCLIVE, } defaults = {} if not self.args.explicit: config = {} # TODO defaults.update({**global_defaults, **config}) cli_args = compact({ "cmd": cmd, "code": self.args.code, "data": self.args.data, "models": self.args.models, "metrics": self.args.metrics, "params": self.args.params, "plots": self.args.plots, "live": self.args.live, }) initialized_stage = init( self.repo, name=self.args.name, type=self.args.type, defaults=defaults, overrides=cli_args, interactive=self.args.interactive, force=self.args.force, ) if self.args.run: return self.repo.experiments.run( targets=[initialized_stage.addressing]) return 0
def run(self): from dvc.commands.stage import parse_cmd cmd = parse_cmd(self.args.command) if not self.args.interactive and not cmd: raise InvalidArgumentError("command is not specified") from dvc.repo.experiments.init import init defaults = {} if not self.args.explicit: config = self.repo.config["exp"] defaults.update({**self.DEFAULTS, **config}) cli_args = compact({ "cmd": cmd, "code": self.args.code, "data": self.args.data, "models": self.args.models, "metrics": self.args.metrics, "params": self.args.params, "plots": self.args.plots, "live": self.args.live, }) initialized_stage, initialized_deps, initialized_out_dirs = init( self.repo, name=self.args.name, type=self.args.type, defaults=defaults, overrides=cli_args, interactive=self.args.interactive, force=self.args.force, ) self._post_init_display(initialized_stage, initialized_deps, initialized_out_dirs) if self.args.run: self.repo.experiments.run(targets=[initialized_stage.addressing]) return 0