Skip to content

Commit

Permalink
run: preserve order when -f/--force overwrite stage (iterative#4035)
Browse files Browse the repository at this point in the history
This commit preserves comments, meta and order inside a dvc.yaml
when `-f/--force` is used. But, it does not maintain comments/meta
for .dvc files.

Related: iterative#4014
  • Loading branch information
skshetry authored Jun 12, 2020
1 parent a1d3440 commit 24a1456
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 5 deletions.
11 changes: 6 additions & 5 deletions dvc/repo/run.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from contextlib import suppress

from funcy import concat, first, lfilter

Expand Down Expand Up @@ -109,12 +110,12 @@ def run(self, fname=None, no_exec=False, single_stage=False, **kwargs):
return None

dvcfile = Dvcfile(self, stage.path)
if kwargs.get("force", True):
dvcfile.remove_stage(stage)
else:
_check_stage_exists(dvcfile, stage)

try:
if kwargs.get("force", True):
with suppress(ValueError):
self.stages.remove(stage)
else:
_check_stage_exists(dvcfile, stage)
self.check_modified_graph([stage])
except OutputDuplicationError as exc:
raise OutputDuplicationError(exc.output, set(exc.stages) - {stage})
Expand Down
46 changes: 46 additions & 0 deletions tests/func/test_run_multistage.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import os
import textwrap

import pytest
import yaml

from dvc.exceptions import InvalidArgumentError
from dvc.repo import Repo
from dvc.stage.exceptions import DuplicateStageName, InvalidStageName
from dvc.utils.yaml import parse_yaml_for_update


def test_run_with_name(tmp_dir, dvc, run_copy):
Expand Down Expand Up @@ -315,3 +317,47 @@ def test_run_without_cmd(kwargs):
with pytest.raises(InvalidArgumentError) as exc:
Repo().run(**kwargs)
assert "command is not specified" == str(exc.value)


def test_run_overwrite_order(tmp_dir, dvc, run_copy):
from dvc.dvcfile import PIPELINE_FILE

tmp_dir.gen({"foo": "foo", "foo1": "foo1"})
run_copy("foo", "bar", name="copy-foo-bar")
run_copy("bar", "foobar", name="copy-bar-foobar")

run_copy("foo1", "bar1", name="copy-foo-bar", force=True)

data = parse_yaml_for_update(
(tmp_dir / PIPELINE_FILE).read_text(), PIPELINE_FILE
)
assert list(data["stages"].keys()) == ["copy-foo-bar", "copy-bar-foobar"]


def test_run_overwrite_preserves_meta_and_comment(tmp_dir, dvc, run_copy):
from dvc.dvcfile import PIPELINE_FILE

tmp_dir.gen({"foo": "foo", "foo1": "foo1"})
text = textwrap.dedent(
"""\
stages:
copy-foo-bar:
cmd: python copy.py {src} {dest}
deps:
- copy.py
- {src}
outs:
# comments are preserved
- {dest}
meta:
name: meta is preserved too
"""
)
(tmp_dir / PIPELINE_FILE).write_text(text.format(src="foo", dest="bar"))
assert dvc.reproduce(PIPELINE_FILE)

assert run_copy("foo1", "bar1", name="copy-foo-bar", force=True)

assert (tmp_dir / PIPELINE_FILE).read_text() == text.format(
src="foo1", dest="bar1"
)
30 changes: 30 additions & 0 deletions tests/func/test_run_single_stage.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import filecmp
import logging
import os
import textwrap
import uuid
from pathlib import Path

Expand Down Expand Up @@ -1017,3 +1018,32 @@ def test_metrics_dir_not_cached(self, dvc):
metrics_no_cache=["dir"],
single_stage=True,
)


def test_run_force_doesnot_preserve_comments_and_meta(tmp_dir, dvc, run_copy):
"""Depends on loading of stage on `run` where we don't check the file
for stage already exists, so we don't copy `stage_text` over due to which
`meta` and `comments` don't get preserved."""
tmp_dir.gen({"foo": "foo", "foo1": "foo1"})
text = textwrap.dedent(
"""\
cmd: python copy.py foo bar
deps:
- path: copy.py
- path: foo
outs:
# comment not preserved
- path: bar
meta:
name: copy-foo-bar
"""
)
(tmp_dir / "bar.dvc").write_text(text)
dvc.reproduce("bar.dvc")
assert "comment" in (tmp_dir / "bar.dvc").read_text()
assert "meta" in (tmp_dir / "bar.dvc").read_text()

run_copy("foo1", "bar1", single_stage=True, force=True, fname="bar.dvc")

assert "comment" not in (tmp_dir / "bar.dvc").read_text()
assert "meta" not in (tmp_dir / "bar.dvc").read_text()

0 comments on commit 24a1456

Please sign in to comment.