def test_remove_stage_preserves_comment(tmp_dir, dvc, run_copy): tmp_dir.gen( "dvc.yaml", textwrap.dedent("""\ stages: generate-foo: cmd: "echo foo > foo" # This copies 'foo' text to 'foo' file. outs: - foo copy-foo-bar: cmd: "python copy.py foo bar" deps: - foo outs: - bar"""), ) dvc.reproduce(PIPELINE_FILE) dvc_file = Dvcfile(dvc, PIPELINE_FILE) assert dvc_file.exists() assert (tmp_dir / PIPELINE_LOCK).exists() assert (tmp_dir / "foo").exists() assert (tmp_dir / "bar").exists() dvc_file.remove_stage(dvc_file.stages["copy-foo-bar"]) assert ("# This copies 'foo' text to 'foo' file." in (tmp_dir / PIPELINE_FILE).read_text())
def run(self, fname=None, no_exec=False, single_stage=False, **kwargs): from dvc.stage import PipelineStage, Stage, create_stage from dvc.dvcfile import Dvcfile, PIPELINE_FILE if not kwargs.get("cmd"): raise InvalidArgumentError("command is not specified") stage_cls = PipelineStage path = PIPELINE_FILE stage_name = kwargs.get("name") if stage_name and single_stage: raise InvalidArgumentError( "`-n|--name` is incompatible with `--single-stage`") if not stage_name and not single_stage: raise InvalidArgumentError("`-n|--name` is required") if single_stage: kwargs.pop("name", None) stage_cls = Stage path = fname or _get_file_path(kwargs) else: if not is_valid_name(stage_name): raise InvalidStageName params = parse_params(kwargs.pop("params", [])) stage = create_stage(stage_cls, repo=self, path=path, params=params, **kwargs) if stage is None: return None dvcfile = Dvcfile(self, stage.path) if dvcfile.exists(): if kwargs.get("overwrite", True): dvcfile.remove_stage(stage) elif stage_cls != PipelineStage: raise StageFileAlreadyExistsError(dvcfile.relpath) elif stage_name and stage_name in dvcfile.stages: raise DuplicateStageName(stage_name, dvcfile) try: self.check_modified_graph([stage]) except OutputDuplicationError as exc: raise OutputDuplicationError(exc.output, set(exc.stages) - {stage}) if no_exec: stage.ignore_outs() else: stage.run( no_commit=kwargs.get("no_commit", False), run_cache=kwargs.get("run_cache", True), ) dvcfile.dump(stage, update_pipeline=True, no_lock=no_exec) return stage
def test_remove_stage_removes_dvcfiles_if_no_stages_left( tmp_dir, dvc, run_copy): tmp_dir.gen("foo", "foo") run_copy("foo", "bar", name="run_copy") dvc_file = Dvcfile(dvc, PIPELINE_FILE) assert dvc_file.exists() assert (tmp_dir / PIPELINE_LOCK).exists() assert (tmp_dir / "foo").exists() dvc_file.remove_stage(dvc_file.stages["run_copy"]) assert not dvc_file.exists() assert not (tmp_dir / PIPELINE_LOCK).exists()
def test_remove_stage_on_lockfile_format_error(tmp_dir, dvc, run_copy): tmp_dir.gen("foo", "foo") stage = run_copy("foo", "bar", name="copy-foo-bar") dvc_file = Dvcfile(dvc, stage.path) lock_file = dvc_file._lockfile data = dvc_file._load()[0] lock_data = lock_file.load() lock_data["gibberish"] = True data["gibberish"] = True dump_yaml(lock_file.relpath, lock_data) with pytest.raises(StageFileFormatError): dvc_file.remove_stage(stage) lock_file.remove() dvc_file.dump(stage, update_pipeline=False) dump_yaml(dvc_file.relpath, data) with pytest.raises(StageFileFormatError): dvc_file.remove_stage(stage)
def test_remove_stage_dvcfiles(tmp_dir, dvc, run_copy): tmp_dir.gen("foo", "foo") stage = run_copy("foo", "bar", single_stage=True) dvc_file = Dvcfile(dvc, stage.path) assert dvc_file.exists() dvc_file.remove_stage(stage) assert not dvc_file.exists() # re-check to see if it fails if there's no stage entry dvc_file.remove_stage(stage) dvc_file.remove(force=True) # should not fail when there's no file at all. dvc_file.remove_stage(stage)
def test_remove_stage(tmp_dir, dvc, run_copy): tmp_dir.gen("foo", "foo") stage = run_copy("foo", "bar", name="copy-foo-bar") stage2 = run_copy("bar", "foobar", name="copy-bar-foobar") dvc_file = Dvcfile(dvc, PIPELINE_FILE) assert dvc_file.exists() assert {"copy-bar-foobar", "copy-foo-bar"} == set(dvc_file._load()[0]["stages"].keys()) dvc_file.remove_stage(stage) assert ["copy-bar-foobar"] == list(dvc_file._load()[0]["stages"].keys()) # sanity check stage2.reload() # re-check to see if it fails if there's no stage entry dvc_file.remove_stage(stage) dvc_file.remove(force=True) # should not fail when there's no file at all. dvc_file.remove_stage(stage)