mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-13 07:18:25 +01:00
cli: remove dvc run (#9508)
Note that `Repo.run()` API still exists, which will be removed in successive PRs. A lot of tests depend on it that it'll take time before removing it.
This commit is contained in:
@@ -41,7 +41,6 @@ from dvc.commands import (
|
||||
remove,
|
||||
repro,
|
||||
root,
|
||||
run,
|
||||
stage,
|
||||
unprotect,
|
||||
update,
|
||||
@@ -62,7 +61,6 @@ COMMANDS = [
|
||||
remove,
|
||||
move,
|
||||
unprotect,
|
||||
run,
|
||||
repro,
|
||||
data_sync,
|
||||
gc,
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
from dvc.cli.command import CmdBase
|
||||
from dvc.cli.utils import append_doc_link
|
||||
from dvc.commands.stage import parse_cmd
|
||||
from dvc.exceptions import DvcException
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CmdRun(CmdBase):
|
||||
def run(self):
|
||||
if not any(
|
||||
[
|
||||
self.args.deps,
|
||||
self.args.outs,
|
||||
self.args.outs_no_cache,
|
||||
self.args.metrics,
|
||||
self.args.metrics_no_cache,
|
||||
self.args.plots,
|
||||
self.args.plots_no_cache,
|
||||
self.args.outs_persist,
|
||||
self.args.outs_persist_no_cache,
|
||||
self.args.params,
|
||||
self.args.command,
|
||||
]
|
||||
): # pragma: no cover
|
||||
logger.error(
|
||||
"too few arguments. Specify at least one: `-d`, `-o`, `-O`, "
|
||||
"`-m`, `-M`, `-p`, `--plots`, `--plots-no-cache`, "
|
||||
"`--outs-persist`, `--outs-persist-no-cache`, `command`."
|
||||
)
|
||||
return 1
|
||||
|
||||
kwargs = vars(self.args)
|
||||
kwargs.update(
|
||||
{
|
||||
"cmd": parse_cmd(self.args.command),
|
||||
"fname": kwargs.pop("file"),
|
||||
"no_exec": self.args.no_exec,
|
||||
"run_cache": not kwargs.pop("no_run_cache"),
|
||||
}
|
||||
)
|
||||
try:
|
||||
self.repo.run(**kwargs)
|
||||
except DvcException:
|
||||
logger.exception("")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def add_parser(subparsers, parent_parser):
|
||||
from dvc.commands.stage import _add_common_args
|
||||
|
||||
RUN_HELP = "Generate a dvc.yaml file from a command and execute the command."
|
||||
run_parser = subparsers.add_parser(
|
||||
"run",
|
||||
parents=[parent_parser],
|
||||
description=append_doc_link(RUN_HELP, "run"),
|
||||
help=RUN_HELP,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
run_parser.add_argument("-n", "--name", help="Stage name.")
|
||||
run_parser.add_argument("--file", metavar="<filename>", help=argparse.SUPPRESS)
|
||||
run_parser.add_argument(
|
||||
"--single-stage",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
_add_common_args(run_parser)
|
||||
run_parser.add_argument(
|
||||
"--no-exec",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Only create dvc.yaml without actually running it.",
|
||||
)
|
||||
run_parser.add_argument(
|
||||
"--no-commit",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Don't put files/directories into cache.",
|
||||
)
|
||||
run_parser.add_argument(
|
||||
"--no-run-cache",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=(
|
||||
"Execute the command even if this stage has already been run "
|
||||
"with the same command/dependencies/outputs/etc before."
|
||||
),
|
||||
)
|
||||
run_parser.set_defaults(func=CmdRun)
|
||||
+2
-11
@@ -362,10 +362,6 @@ def test_should_update_state_entry_for_file_after_add(mocker, dvc, tmp_dir):
|
||||
assert ret == 0
|
||||
assert file_md5_counter.mock.call_count == 1
|
||||
|
||||
ret = main(["run", "--single-stage", "-d", "foo", "echo foo"])
|
||||
assert ret == 0
|
||||
assert file_md5_counter.mock.call_count == 1
|
||||
|
||||
os.rename("foo", "foo.back")
|
||||
ret = main(["checkout"])
|
||||
assert ret == 0
|
||||
@@ -392,19 +388,14 @@ def test_should_update_state_entry_for_directory_after_add(mocker, dvc, tmp_dir)
|
||||
assert ret == 0
|
||||
assert file_md5_counter.mock.call_count == 5
|
||||
|
||||
ls = "dir" if os.name == "nt" else "ls"
|
||||
ret = main(["run", "--single-stage", "-d", "data", "{} {}".format(ls, "data")])
|
||||
assert ret == 0
|
||||
assert file_md5_counter.mock.call_count == 7
|
||||
|
||||
os.rename("data", "data.back")
|
||||
ret = main(["checkout"])
|
||||
assert ret == 0
|
||||
assert file_md5_counter.mock.call_count == 7
|
||||
assert file_md5_counter.mock.call_count == 5
|
||||
|
||||
ret = main(["status"])
|
||||
assert ret == 0
|
||||
assert file_md5_counter.mock.call_count == 9
|
||||
assert file_md5_counter.mock.call_count == 6
|
||||
|
||||
|
||||
def test_add_commit(tmp_dir, dvc):
|
||||
|
||||
@@ -11,7 +11,6 @@ from dvc.commands.data_sync import CmdDataPull, CmdDataPush
|
||||
from dvc.commands.init import CmdInit
|
||||
from dvc.commands.remove import CmdRemove
|
||||
from dvc.commands.repro import CmdRepro
|
||||
from dvc.commands.run import CmdRun
|
||||
from dvc.commands.status import CmdDataStatus
|
||||
from dvc.exceptions import NotDvcRepoError
|
||||
|
||||
@@ -21,54 +20,6 @@ def test_argparse(dvc):
|
||||
assert isinstance(args.func(args), CmdInit)
|
||||
|
||||
|
||||
def test_run(dvc):
|
||||
dep1 = "dep1"
|
||||
dep2 = "dep2"
|
||||
|
||||
out1 = "out1"
|
||||
out2 = "out2"
|
||||
|
||||
out_no_cache1 = "out_no_cache1"
|
||||
out_no_cache2 = "out_no_cache2"
|
||||
|
||||
fname = "dvc.dvc"
|
||||
cmd = "cmd"
|
||||
arg1 = "arg1"
|
||||
arg2 = "arg2"
|
||||
|
||||
args = parse_args(
|
||||
[
|
||||
"run",
|
||||
"-d",
|
||||
dep1,
|
||||
"--deps",
|
||||
dep2,
|
||||
"-o",
|
||||
out1,
|
||||
"--outs",
|
||||
out2,
|
||||
"-O",
|
||||
out_no_cache1,
|
||||
"--outs-no-cache",
|
||||
out_no_cache2,
|
||||
"--file",
|
||||
fname,
|
||||
cmd,
|
||||
arg1,
|
||||
arg2,
|
||||
]
|
||||
)
|
||||
cmd_cls = args.func(args)
|
||||
assert isinstance(cmd_cls, CmdRun)
|
||||
assert args.deps == [dep1, dep2]
|
||||
assert args.outs == [out1, out2]
|
||||
assert args.outs_no_cache == [out_no_cache1, out_no_cache2]
|
||||
assert args.file == fname
|
||||
assert args.command == [cmd, arg1, arg2]
|
||||
|
||||
cmd_cls.repo.close()
|
||||
|
||||
|
||||
def test_pull(dvc):
|
||||
args = parse_args(["pull"])
|
||||
cmd = args.func(args)
|
||||
|
||||
@@ -147,8 +147,6 @@ def test_hash_recalculation(mocker, dvc, tmp_dir, local_remote):
|
||||
assert ret == 0
|
||||
ret = main(["push"])
|
||||
assert ret == 0
|
||||
ret = main(["run", "--single-stage", "-d", "foo", "echo foo"])
|
||||
assert ret == 0
|
||||
assert test_file_md5.mock.call_count == 1
|
||||
|
||||
|
||||
|
||||
+51
-27
@@ -335,9 +335,10 @@ def test_repro_dry_no_exec(tmp_dir, dvc):
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"--no-exec",
|
||||
"--single-stage",
|
||||
"stage",
|
||||
"add",
|
||||
"-n",
|
||||
f"copy-{idir}-{odir}",
|
||||
"-d",
|
||||
idir,
|
||||
"-o",
|
||||
@@ -351,18 +352,17 @@ def test_repro_dry_no_exec(tmp_dir, dvc):
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"--no-exec",
|
||||
"--single-stage",
|
||||
"--file",
|
||||
DVC_FILE,
|
||||
"stage",
|
||||
"add",
|
||||
"-n",
|
||||
"ls",
|
||||
*deps,
|
||||
"ls {}".format(" ".join(dep for i, dep in enumerate(deps) if i % 2)),
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
|
||||
ret = main(["repro", "--dry", DVC_FILE])
|
||||
ret = main(["repro", "--dry", "ls"])
|
||||
assert ret == 0
|
||||
|
||||
|
||||
@@ -1114,14 +1114,27 @@ def test_downstream(dvc):
|
||||
# \ /
|
||||
# A
|
||||
#
|
||||
assert main(["run", "--single-stage", "-o", "A", "echo A>A"]) == 0
|
||||
assert main(["run", "--single-stage", "-d", "A", "-o", "B", "echo B>B"]) == 0
|
||||
assert main(["run", "--single-stage", "-d", "A", "-o", "C", "echo C>C"]) == 0
|
||||
assert main(["stage", "add", "-n", "stage-A", "--run", "-o", "A", "echo A>A"]) == 0
|
||||
assert (
|
||||
main(
|
||||
["stage", "add", "-n", "stage-B", "--run", "-d", "A", "-o", "B", "echo B>B"]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert (
|
||||
main(
|
||||
["stage", "add", "-n", "stage-C", "--run", "-d", "A", "-o", "C", "echo C>C"]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"run",
|
||||
"--single-stage",
|
||||
"stage",
|
||||
"add",
|
||||
"-n",
|
||||
"stage-D",
|
||||
"--run",
|
||||
"-d",
|
||||
"B",
|
||||
"-d",
|
||||
@@ -1133,13 +1146,21 @@ def test_downstream(dvc):
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert main(["run", "--single-stage", "-o", "G", "echo G>G"]) == 0
|
||||
assert main(["run", "--single-stage", "-d", "G", "-o", "F", "echo F>F"]) == 0
|
||||
assert main(["stage", "add", "-n", "stage-G", "--run", "-o", "G", "echo G>G"]) == 0
|
||||
assert (
|
||||
main(
|
||||
["stage", "add", "-n", "stage-F", "--run", "-d", "G", "-o", "F", "echo F>F"]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"run",
|
||||
"--single-stage",
|
||||
"stage",
|
||||
"add",
|
||||
"-n",
|
||||
"stage-E",
|
||||
"--run",
|
||||
"-d",
|
||||
"D",
|
||||
"-d",
|
||||
@@ -1160,22 +1181,25 @@ def test_downstream(dvc):
|
||||
# /
|
||||
# B
|
||||
#
|
||||
evaluation = dvc.reproduce("B.dvc", downstream=True, force=True)
|
||||
evaluation = dvc.reproduce("stage-B", downstream=True, force=True)
|
||||
|
||||
assert len(evaluation) == 3
|
||||
assert evaluation[0].relpath == "B.dvc"
|
||||
assert evaluation[1].relpath == "D.dvc"
|
||||
assert evaluation[2].relpath == "E.dvc"
|
||||
assert evaluation[0].addressing == "stage-B"
|
||||
assert evaluation[1].addressing == "stage-D"
|
||||
assert evaluation[2].addressing == "stage-E"
|
||||
|
||||
# B, C should be run (in any order) before D
|
||||
# See https://github.com/iterative/dvc/issues/3602
|
||||
evaluation = dvc.reproduce("A.dvc", downstream=True, force=True)
|
||||
evaluation = dvc.reproduce("stage-A", downstream=True, force=True)
|
||||
|
||||
assert len(evaluation) == 5
|
||||
assert evaluation[0].relpath == "A.dvc"
|
||||
assert {evaluation[1].relpath, evaluation[2].relpath} == {"B.dvc", "C.dvc"}
|
||||
assert evaluation[3].relpath == "D.dvc"
|
||||
assert evaluation[4].relpath == "E.dvc"
|
||||
assert evaluation[0].addressing == "stage-A"
|
||||
assert {evaluation[1].addressing, evaluation[2].addressing} == {
|
||||
"stage-B",
|
||||
"stage-C",
|
||||
}
|
||||
assert evaluation[3].addressing == "stage-D"
|
||||
assert evaluation[4].addressing == "stage-E"
|
||||
|
||||
|
||||
def test_repro_when_cmd_changes(tmp_dir, dvc, run_copy, mocker):
|
||||
|
||||
@@ -36,7 +36,7 @@ def test_repro_frozen(tmp_dir, dvc, run_copy):
|
||||
assert stages == [data_stage, stage0]
|
||||
|
||||
|
||||
def test_downstream(tmp_dir, dvc):
|
||||
def test_downstream(M, tmp_dir, dvc):
|
||||
# The dependency graph should look like this:
|
||||
#
|
||||
# E
|
||||
@@ -47,19 +47,60 @@ def test_downstream(tmp_dir, dvc):
|
||||
# \ /
|
||||
# A
|
||||
#
|
||||
assert main(["run", "-n", "A-gen", "-o", "A", "echo A>A"]) == 0
|
||||
assert main(["run", "-n", "B-gen", "-d", "A", "-o", "B", "echo B>B"]) == 0
|
||||
assert main(["run", "--single-stage", "-d", "A", "-o", "C", "echo C>C"]) == 0
|
||||
assert main(["stage", "add", "--run", "-n", "A-gen", "-o", "A", "echo A>A"]) == 0
|
||||
assert (
|
||||
main(["run", "-n", "D-gen", "-d", "B", "-d", "C", "-o", "D", "echo D>D"]) == 0
|
||||
main(["stage", "add", "--run", "-n", "B-gen", "-d", "A", "-o", "B", "echo B>B"])
|
||||
== 0
|
||||
)
|
||||
assert main(["run", "--single-stage", "-o", "G", "echo G>G"]) == 0
|
||||
assert main(["run", "-n", "F-gen", "-d", "G", "-o", "F", "echo F>F"]) == 0
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"run",
|
||||
"--single-stage",
|
||||
"stage",
|
||||
"add",
|
||||
"--run",
|
||||
"-n",
|
||||
"C-gen",
|
||||
"-d",
|
||||
"A",
|
||||
"-o",
|
||||
"C",
|
||||
"echo C>C",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"stage",
|
||||
"add",
|
||||
"--run",
|
||||
"-n",
|
||||
"D-gen",
|
||||
"-d",
|
||||
"B",
|
||||
"-d",
|
||||
"C",
|
||||
"-o",
|
||||
"D",
|
||||
"echo D>D",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert main(["stage", "add", "--run", "-n", "G-gen", "-o", "G", "echo G>G"]) == 0
|
||||
assert (
|
||||
main(["stage", "add", "--run", "-n", "F-gen", "-d", "G", "-o", "F", "echo F>F"])
|
||||
== 0
|
||||
)
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"stage",
|
||||
"add",
|
||||
"--run",
|
||||
"-n",
|
||||
"E-gen",
|
||||
"-d",
|
||||
"D",
|
||||
"-d",
|
||||
@@ -83,41 +124,24 @@ def test_downstream(tmp_dir, dvc):
|
||||
evaluation = dvc.reproduce(PROJECT_FILE + ":B-gen", downstream=True, force=True)
|
||||
|
||||
assert len(evaluation) == 3
|
||||
assert isinstance(evaluation[0], PipelineStage)
|
||||
assert evaluation[0].relpath == PROJECT_FILE
|
||||
assert evaluation[0].name == "B-gen"
|
||||
|
||||
assert isinstance(evaluation[1], PipelineStage)
|
||||
assert evaluation[1].relpath == PROJECT_FILE
|
||||
assert evaluation[1].name == "D-gen"
|
||||
|
||||
assert not isinstance(evaluation[2], PipelineStage)
|
||||
assert evaluation[2].relpath == "E.dvc"
|
||||
assert all(isinstance(stage, PipelineStage) for stage in evaluation)
|
||||
assert all(stage.relpath == PROJECT_FILE for stage in evaluation)
|
||||
assert [stage.name for stage in evaluation] == ["B-gen", "D-gen", "E-gen"]
|
||||
|
||||
# B, C should be run (in any order) before D
|
||||
# See https://github.com/iterative/dvc/issues/3602
|
||||
evaluation = dvc.reproduce(PROJECT_FILE + ":A-gen", downstream=True, force=True)
|
||||
|
||||
assert len(evaluation) == 5
|
||||
assert isinstance(evaluation[0], PipelineStage)
|
||||
assert evaluation[0].relpath == PROJECT_FILE
|
||||
assert evaluation[0].name == "A-gen"
|
||||
|
||||
names = set()
|
||||
for stage in evaluation[1:3]:
|
||||
if isinstance(stage, PipelineStage):
|
||||
assert stage.relpath == PROJECT_FILE
|
||||
names.add(stage.name)
|
||||
else:
|
||||
names.add(stage.relpath)
|
||||
assert names == {"B-gen", "C.dvc"}
|
||||
|
||||
assert isinstance(evaluation[3], PipelineStage)
|
||||
assert evaluation[3].relpath == PROJECT_FILE
|
||||
assert evaluation[3].name == "D-gen"
|
||||
|
||||
assert not isinstance(evaluation[4], PipelineStage)
|
||||
assert evaluation[4].relpath == "E.dvc"
|
||||
assert all(isinstance(stage, PipelineStage) for stage in evaluation)
|
||||
assert all(stage.relpath == PROJECT_FILE for stage in evaluation)
|
||||
assert [stage.name for stage in evaluation] == [
|
||||
"A-gen",
|
||||
M.any_of("B-gen", "C-gen"),
|
||||
M.any_of("B-gen", "C-gen"),
|
||||
"D-gen",
|
||||
"E-gen",
|
||||
]
|
||||
|
||||
|
||||
def test_repro_when_cmd_changes(tmp_dir, dvc, run_copy, mocker):
|
||||
|
||||
@@ -18,8 +18,7 @@ from dvc.exceptions import (
|
||||
OverlappingOutputPathsError,
|
||||
StagePathAsOutputError,
|
||||
)
|
||||
from dvc.fs import system
|
||||
from dvc.output import Output, OutputIsStageFileError
|
||||
from dvc.output import OutputIsStageFileError
|
||||
from dvc.stage import Stage
|
||||
from dvc.stage.exceptions import (
|
||||
StageFileAlreadyExistsError,
|
||||
@@ -307,262 +306,6 @@ def test_run_remove_outs(tmp_dir, dvc, append_foo_script):
|
||||
)
|
||||
|
||||
|
||||
def test_run_unprotect_outs_copy(tmp_dir, dvc, append_foo_script):
|
||||
ret = main(["config", "cache.type", "copy"])
|
||||
assert ret == 0
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-d",
|
||||
"append_foo.py",
|
||||
"-o",
|
||||
"foo",
|
||||
"--single-stage",
|
||||
"python",
|
||||
"append_foo.py",
|
||||
"foo",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
assert os.access("foo", os.W_OK)
|
||||
with open("foo", encoding="utf-8") as fd:
|
||||
assert fd.read() == "foo"
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"--force",
|
||||
"--no-run-cache",
|
||||
"--single-stage",
|
||||
"-d",
|
||||
"append_foo.py",
|
||||
"-o",
|
||||
"foo",
|
||||
"python",
|
||||
"append_foo.py",
|
||||
"foo",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
assert os.access("foo", os.W_OK)
|
||||
with open("foo", encoding="utf-8") as fd:
|
||||
assert fd.read() == "foo"
|
||||
|
||||
|
||||
def test_run_unprotect_outs_symlink(tmp_dir, dvc, append_foo_script):
|
||||
ret = main(["config", "cache.type", "symlink"])
|
||||
assert ret == 0
|
||||
|
||||
assert ret == 0
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-d",
|
||||
"append_foo.py",
|
||||
"-o",
|
||||
"foo",
|
||||
"--single-stage",
|
||||
"python",
|
||||
"append_foo.py",
|
||||
"foo",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
|
||||
if os.name == "nt":
|
||||
# NOTE: Windows symlink perms don't propagate to the target
|
||||
assert os.access("foo", os.W_OK)
|
||||
else:
|
||||
assert not os.access("foo", os.W_OK)
|
||||
|
||||
assert system.is_symlink("foo")
|
||||
with open("foo", encoding="utf-8") as fd:
|
||||
assert fd.read() == "foo"
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"--force",
|
||||
"--no-run-cache",
|
||||
"--single-stage",
|
||||
"-d",
|
||||
"append_foo.py",
|
||||
"-o",
|
||||
"foo",
|
||||
"python",
|
||||
"append_foo.py",
|
||||
"foo",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
|
||||
if os.name == "nt":
|
||||
# NOTE: Windows symlink perms don't propagate to the target
|
||||
assert os.access("foo", os.W_OK)
|
||||
else:
|
||||
assert not os.access("foo", os.W_OK)
|
||||
|
||||
assert system.is_symlink("foo")
|
||||
with open("foo", encoding="utf-8") as fd:
|
||||
assert fd.read() == "foo"
|
||||
|
||||
|
||||
def test_run_unprotect_outs_hardlink(tmp_dir, dvc, append_foo_script):
|
||||
ret = main(["config", "cache.type", "hardlink"])
|
||||
assert ret == 0
|
||||
|
||||
assert ret == 0
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-d",
|
||||
"append_foo.py",
|
||||
"-o",
|
||||
"foo",
|
||||
"--single-stage",
|
||||
"python",
|
||||
"append_foo.py",
|
||||
"foo",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
assert not os.access("foo", os.W_OK)
|
||||
assert system.is_hardlink("foo")
|
||||
with open("foo", encoding="utf-8") as fd:
|
||||
assert fd.read() == "foo"
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"--force",
|
||||
"--no-run-cache",
|
||||
"--single-stage",
|
||||
"-d",
|
||||
"append_foo.py",
|
||||
"-o",
|
||||
"foo",
|
||||
"python",
|
||||
"append_foo.py",
|
||||
"foo",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
assert not os.access("foo", os.W_OK)
|
||||
assert system.is_hardlink("foo")
|
||||
with open("foo", encoding="utf-8") as fd:
|
||||
assert fd.read() == "foo"
|
||||
|
||||
|
||||
def test_cmd_run_overwrite(tmp_dir, dvc, copy_script):
|
||||
# NOTE: using sleep() is a workaround for filesystems
|
||||
# with low mtime resolution. We have to use mtime since
|
||||
# comparing mtime's is the only way to check that the stage
|
||||
# file didn't change(size and inode in the first test down
|
||||
# below don't change).
|
||||
tmp_dir.gen({"foo": "foo", "bar": "bar"})
|
||||
import time
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-d",
|
||||
"foo",
|
||||
"-d",
|
||||
"copy.py",
|
||||
"-o",
|
||||
"out",
|
||||
"--file",
|
||||
"out.dvc",
|
||||
"--single-stage",
|
||||
"python",
|
||||
"copy.py",
|
||||
"foo",
|
||||
"out",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
|
||||
stage_mtime = os.path.getmtime("out.dvc")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-d",
|
||||
"foo",
|
||||
"-d",
|
||||
"copy.py",
|
||||
"--force",
|
||||
"--no-run-cache",
|
||||
"--single-stage",
|
||||
"-o",
|
||||
"out",
|
||||
"--file",
|
||||
"out.dvc",
|
||||
"python",
|
||||
"copy.py",
|
||||
"foo",
|
||||
"out",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
|
||||
# NOTE: check that dvcfile was overwritten
|
||||
assert stage_mtime != os.path.getmtime("out.dvc")
|
||||
stage_mtime = os.path.getmtime("out.dvc")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"--force",
|
||||
"--single-stage",
|
||||
"--file",
|
||||
"out.dvc",
|
||||
"-d",
|
||||
"bar",
|
||||
"cat bar",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
|
||||
# NOTE: check that dvcfile was overwritten
|
||||
assert stage_mtime != os.path.getmtime("out.dvc")
|
||||
|
||||
|
||||
class TestCmdRunCliMetrics:
|
||||
def test_cached(self, dvc):
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-m",
|
||||
"metrics.txt",
|
||||
"--single-stage",
|
||||
"echo test > metrics.txt",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
with open("metrics.txt", encoding="utf-8") as fd:
|
||||
assert fd.read().rstrip() == "test"
|
||||
|
||||
def test_not_cached(self, dvc):
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-M",
|
||||
"metrics.txt",
|
||||
"--single-stage",
|
||||
"echo test > metrics.txt",
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
with open("metrics.txt", encoding="utf-8") as fd:
|
||||
assert fd.read().rstrip() == "test"
|
||||
|
||||
|
||||
class TestCmdRunWorkingDirectory:
|
||||
def test_default_wdir_is_not_written(self, tmp_dir, dvc):
|
||||
stage = dvc.run(
|
||||
@@ -665,62 +408,6 @@ def test_rerun_changed_out(tmp_dir, run_copy):
|
||||
run_copy("foo", "out", force=False, single_stage=True)
|
||||
|
||||
|
||||
def test_run_commit(dvc):
|
||||
fname = "test"
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-o",
|
||||
fname,
|
||||
"--no-commit",
|
||||
"--single-stage",
|
||||
"echo",
|
||||
"test",
|
||||
">",
|
||||
fname,
|
||||
]
|
||||
)
|
||||
assert ret == 0
|
||||
assert os.path.isfile(fname)
|
||||
assert not os.path.exists(dvc.cache.local.path)
|
||||
|
||||
ret = main(["commit", fname + ".dvc"])
|
||||
assert ret == 0
|
||||
assert os.path.isfile(fname)
|
||||
assert len(list(dvc.cache.local.all())) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"outs_command",
|
||||
[
|
||||
"--outs-persist",
|
||||
"--outs-persist-no-cache",
|
||||
],
|
||||
)
|
||||
def test_run_persist(tmp_dir, dvc, outs_command):
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"run",
|
||||
"--single-stage",
|
||||
"--always-changed",
|
||||
outs_command,
|
||||
"file",
|
||||
"echo content>>file",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
d = (tmp_dir / "file.dvc").load_yaml()
|
||||
assert d["outs"][0][Output.PARAM_PERSIST]
|
||||
|
||||
assert main(["repro", "file.dvc"]) == 0
|
||||
assert (tmp_dir / "file").read_text() == "content\ncontent\n"
|
||||
|
||||
assert main(["remove", "file.dvc", "--outs"]) == 0
|
||||
assert not (tmp_dir / "file").exists()
|
||||
|
||||
|
||||
def test_should_raise_on_overlapping_output_paths(tmp_dir, dvc, append_foo_script):
|
||||
tmp_dir.gen("data", {"foo": "foo", "bar": "bar"})
|
||||
ret = main(["add", "data"])
|
||||
@@ -746,45 +433,6 @@ def test_should_raise_on_overlapping_output_paths(tmp_dir, dvc, append_foo_scrip
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"outs_command, first_expected, second_expected",
|
||||
[
|
||||
("--outs", "foo\n", "bar\n"),
|
||||
("--outs-persist", "foo\n", "foo\nbar\n"),
|
||||
],
|
||||
)
|
||||
def test_rerun_with_same_outputs(
|
||||
tmp_dir, dvc, outs_command, first_expected, second_expected
|
||||
):
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"run",
|
||||
"--single-stage",
|
||||
"--outs",
|
||||
"foo",
|
||||
"echo foo>foo",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert (tmp_dir / "foo").read_text() == first_expected
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"run",
|
||||
outs_command,
|
||||
"foo",
|
||||
"--force",
|
||||
"--single-stage",
|
||||
"echo bar>>foo",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert (tmp_dir / "foo").read_text() == second_expected
|
||||
|
||||
|
||||
def test_should_not_checkout_upon_corrupted_local_hardlink_cache(
|
||||
mocker, tmp_dir, dvc, copy_script
|
||||
):
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
from dvc.cli import parse_args
|
||||
from dvc.commands.run import CmdRun
|
||||
from tests.utils.asserts import called_once_with_subset
|
||||
|
||||
|
||||
def test_run(mocker, dvc):
|
||||
cli_args = parse_args(
|
||||
[
|
||||
"run",
|
||||
"--name",
|
||||
"name",
|
||||
"--deps",
|
||||
"deps",
|
||||
"--outs",
|
||||
"outs",
|
||||
"--outs-no-cache",
|
||||
"outs-no-cache",
|
||||
"--metrics",
|
||||
"metrics",
|
||||
"--metrics-no-cache",
|
||||
"metrics-no-cache",
|
||||
"--plots",
|
||||
"plots",
|
||||
"--plots-no-cache",
|
||||
"plots-no-cache",
|
||||
"--file",
|
||||
"file",
|
||||
"--wdir",
|
||||
"wdir",
|
||||
"--no-exec",
|
||||
"--force",
|
||||
"--no-run-cache",
|
||||
"--no-commit",
|
||||
"--outs-persist",
|
||||
"outs-persist",
|
||||
"--outs-persist-no-cache",
|
||||
"outs-persist-no-cache",
|
||||
"--always-changed",
|
||||
"--params",
|
||||
"file:param1,param2",
|
||||
"--params",
|
||||
"param3",
|
||||
"--external",
|
||||
"--desc",
|
||||
"description",
|
||||
"command",
|
||||
]
|
||||
)
|
||||
assert cli_args.func == CmdRun
|
||||
|
||||
cmd = cli_args.func(cli_args)
|
||||
m = mocker.patch.object(cmd.repo, "run", autospec=True)
|
||||
|
||||
assert cmd.run() == 0
|
||||
|
||||
assert called_once_with_subset(
|
||||
m,
|
||||
deps=["deps"],
|
||||
outs=["outs"],
|
||||
outs_no_cache=["outs-no-cache"],
|
||||
metrics=["metrics"],
|
||||
metrics_no_cache=["metrics-no-cache"],
|
||||
plots=["plots"],
|
||||
plots_no_cache=["plots-no-cache"],
|
||||
outs_persist=["outs-persist"],
|
||||
outs_persist_no_cache=["outs-persist-no-cache"],
|
||||
params=["file:param1,param2", "param3"],
|
||||
fname="file",
|
||||
wdir="wdir",
|
||||
no_exec=True,
|
||||
force=True,
|
||||
run_cache=False,
|
||||
no_commit=True,
|
||||
always_changed=True,
|
||||
cmd="command",
|
||||
name="name",
|
||||
single_stage=False,
|
||||
external=True,
|
||||
desc="description",
|
||||
)
|
||||
|
||||
|
||||
def test_run_args_from_cli(mocker, dvc):
|
||||
args = parse_args(["run", "echo", "foo"])
|
||||
cmd = args.func(args)
|
||||
m = mocker.patch.object(cmd.repo, "run", autospec=True)
|
||||
assert cmd.run() == 0
|
||||
assert called_once_with_subset(
|
||||
m,
|
||||
deps=[],
|
||||
outs=[],
|
||||
outs_no_cache=[],
|
||||
metrics=[],
|
||||
metrics_no_cache=[],
|
||||
plots=[],
|
||||
plots_no_cache=[],
|
||||
outs_persist=[],
|
||||
outs_persist_no_cache=[],
|
||||
params=[],
|
||||
fname=None,
|
||||
wdir=None,
|
||||
no_exec=False,
|
||||
force=False,
|
||||
run_cache=True,
|
||||
no_commit=False,
|
||||
always_changed=False,
|
||||
cmd="echo foo",
|
||||
name=None,
|
||||
single_stage=False,
|
||||
external=False,
|
||||
desc=None,
|
||||
)
|
||||
|
||||
|
||||
def test_run_args_with_spaces(mocker, dvc):
|
||||
args = parse_args(["run", "echo", "foo bar"])
|
||||
cmd = args.func(args)
|
||||
m = mocker.patch.object(cmd.repo, "run", autospec=True)
|
||||
assert cmd.run() == 0
|
||||
assert called_once_with_subset(
|
||||
m,
|
||||
deps=[],
|
||||
outs=[],
|
||||
outs_no_cache=[],
|
||||
metrics=[],
|
||||
metrics_no_cache=[],
|
||||
plots=[],
|
||||
plots_no_cache=[],
|
||||
outs_persist=[],
|
||||
outs_persist_no_cache=[],
|
||||
params=[],
|
||||
fname=None,
|
||||
wdir=None,
|
||||
no_exec=False,
|
||||
force=False,
|
||||
run_cache=True,
|
||||
no_commit=False,
|
||||
always_changed=False,
|
||||
cmd='echo "foo bar"',
|
||||
name=None,
|
||||
single_stage=False,
|
||||
external=False,
|
||||
desc=None,
|
||||
)
|
||||
Reference in New Issue
Block a user