Skip to content

dvc: redefine is_callback as cmd and no outs/deps #5187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions dvc/stage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def is_callback(self):
A callback stage is always considered as changed,
so it runs on every `dvc repro` call.
"""
return not self.is_data_source and len(self.deps) == 0
return self.cmd and not any((self.deps, self.outs))

@property
def is_import(self):
Expand Down Expand Up @@ -265,13 +265,7 @@ def changed_deps(self):
if self.frozen:
return False

if self.is_callback:
logger.debug(
"%s has a command but no dependencies", self.addressing
)
return True

if self.always_changed or self.is_checkpoint:
if self.is_callback or self.always_changed or self.is_checkpoint:
return True

return self._changed_deps()
Expand Down
6 changes: 1 addition & 5 deletions dvc/stage/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,7 @@ def _run(stage, executable, cmd, checkpoint_func, **kwargs):


def cmd_run(stage, dry=False, checkpoint_func=None):
logger.info(
"Running %s" "stage '%s':",
"callback " if stage.is_callback else "",
stage.addressing,
)
logger.info("Running stage '%s':", stage.addressing)
commands = _enforce_cmd_list(stage.cmd)
kwargs = prepare_kwargs(stage, checkpoint_func=checkpoint_func)
executable = get_executable()
Expand Down
5 changes: 1 addition & 4 deletions tests/func/test_lockfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,7 @@ def v1_repo_lock(tmp_dir, dvc):

def test_can_read_v1_lockfile(tmp_dir, dvc, v1_repo_lock):
assert dvc.status() == {
"bar": [
{"changed outs": {"bar.txt": "not in cache"}},
"always changed",
],
"bar": [{"changed outs": {"bar.txt": "not in cache"}}],
"foo": ["always changed"],
}

Expand Down
26 changes: 2 additions & 24 deletions tests/func/test_repro.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,28 +266,6 @@ def test(self):
self.assertEqual(len(stages), 2)


class TestReproNoDeps(TestRepro):
def test(self):
out = "out"
code_file = "out.py"
stage_file = "out.dvc"
code = (
'import uuid\nwith open("{}", "w+") as fd:\n'
"\tfd.write(str(uuid.uuid4()))\n".format(out)
)
with open(code_file, "w+") as fd:
fd.write(code)
stage = self._run(
fname=stage_file,
outs=[out],
cmd=f"python {code_file}",
name="uuid",
)

stages = self.dvc.reproduce(self._get_stage_target(stage))
self.assertEqual(len(stages), 1)


class TestReproForce(TestRepro):
def test(self):
stages = self.dvc.reproduce(
Expand Down Expand Up @@ -572,11 +550,10 @@ class TestReproFrozenCallback(SingleStageRun, TestDvc):
def test(self):
file1 = "file1"
file1_stage = file1 + ".dvc"
# NOTE: purposefully not specifying dependencies
# NOTE: purposefully not specifying deps or outs
# to create a callback stage.
stage = self._run(
fname=file1_stage,
outs=[file1],
cmd=f"python {self.CODE} {self.FOO} {file1}",
name="copy-FOO-file1",
)
Expand Down Expand Up @@ -864,6 +841,7 @@ class TestReproAlreadyCached(TestRepro):
def test(self):
stage = self._run(
fname="datetime.dvc",
always_changed=True,
deps=[],
outs=["datetime.txt"],
cmd='python -c "import time; print(time.time())" > datetime.txt',
Expand Down
4 changes: 0 additions & 4 deletions tests/func/test_repro_multistage.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ class TestReproDepDirWithOutputsUnderItMultiStage(
pass


class TestReproNoDepsMultiStage(MultiStageRun, test_repro.TestReproNoDeps):
pass


class TestReproForceMultiStage(MultiStageRun, test_repro.TestReproForce):
pass

Expand Down
7 changes: 2 additions & 5 deletions tests/func/test_run_single_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,11 +679,7 @@ def test_rerun_deterministic_ignore_cache(tmp_dir, run_copy):
def test_rerun_callback(dvc):
def run_callback(force=False):
return dvc.run(
cmd="echo content > out",
outs=["out"],
deps=[],
force=force,
single_stage=True,
cmd="echo content > out", force=force, single_stage=True,
)

assert run_callback() is not None
Expand Down Expand Up @@ -768,6 +764,7 @@ def run_command(self, file, file_content):
[
"run",
"--single-stage",
"--always-changed",
self.outs_command,
file,
f"echo {file_content} >> {file}",
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/stage/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ def test_run_stage_dry(caplog, cmd, expected):
run_stage(stage, dry=True)

expected.insert(
0, "Running callback stage 'stage.dvc':",
0, "Running stage 'stage.dvc':",
)
assert caplog.messages == expected