Skip to content
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: 9 additions & 1 deletion dvc/stage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,15 @@ def run(
if kwargs.get("checkpoint_func", None) or no_download:
allow_missing = True

self.save(allow_missing=allow_missing, run_cache=not no_commit)
no_cache_outs = any(
not out.use_cache
for out in self.outs
if not (out.is_metric or out.is_plot)
)
self.save(
allow_missing=allow_missing,
run_cache=not no_commit and not no_cache_outs,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

           cache_outs = not (no_commit or any(
                not out.use_cache
                for out in self.outs
                if not (out.is_metric or out.is_plot)
            ))

)

if no_download:
self.ignore_outs()
Expand Down
23 changes: 16 additions & 7 deletions tests/func/test_run_cache.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os

import pytest

from dvc.dvcfile import PIPELINE_LOCK
from dvc.utils import relpath
from dvc.utils.fs import remove


Expand Down Expand Up @@ -65,16 +66,24 @@ def test_do_not_save_on_no_exec_and_dry(tmp_dir, dvc, run_copy):
assert not dvc.stage_cache._load(stage)


def test_uncached_outs_are_cached(tmp_dir, dvc, run_copy):
@pytest.mark.parametrize(
"out_type,run_cache",
[
("metrics_no_cache", True),
("plots_no_cache", True),
("outs_no_cache", False),
],
)
def test_outs_no_cache_deactivate_run_cache(tmp_dir, dvc, out_type, run_cache):
tmp_dir.gen("foo", "foo")
stage = dvc.run(
dvc.run(
deps=["foo"],
cmd="cp foo bar",
outs_no_cache=["bar"],
cmd="cp foo bar && cp foo goo",
outs=["goo"],
name="copy-foo-bar",
**{out_type: ["bar"]}
)
stage.outs[0].hash_info = stage.outs[0].get_hash()
assert os.path.exists(relpath(stage.outs[0].cache_path))
assert os.path.isdir(dvc.stage_cache.cache_dir) == run_cache


def test_memory_for_multiple_runs_of_same_stage(
Expand Down
51 changes: 15 additions & 36 deletions tests/unit/stage/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,29 @@ def test_stage_cache(tmp_dir, dvc, mocker):
tmp_dir.gen("dep", "dep")
tmp_dir.gen(
"script.py",
(
'open("out", "w+").write("out"); '
'open("out_no_cache", "w+").write("out_no_cache")'
),
('open("out", "w+").write("out"); '),
)
stage = dvc.run(
cmd="python script.py",
deps=["script.py", "dep"],
outs=["out"],
outs_no_cache=["out_no_cache"],
single_stage=True,
)

with dvc.lock:
stage.remove(remove_outs=True, force=True)

assert not (tmp_dir / "out").exists()
assert not (tmp_dir / "out_no_cache").exists()
assert not (tmp_dir / "out.dvc").exists()

cache_dir = os.path.join(
dvc.stage_cache.cache_dir,
"10",
"10b45372fdf4ec14d3f779c5b256378d7a12780e4c7f549a44138e492f098bfe",
"4b",
"4b495dc2b14e1ca5bd5f2765a99ddd8785523a8342efe6bcadac012c2db01165",
)
cache_file = os.path.join(
cache_dir,
"bb32e04c6da96a7192513390acedbe4cd6123f8fe5b0ba5fffe39716fe87f6f4",
"78c427104a8e20216031c36d9c7620733066fff33ada254ad3fca551c1f8152b",
)

assert os.path.isdir(cache_dir)
Expand All @@ -49,47 +44,40 @@ def test_stage_cache(tmp_dir, dvc, mocker):
stage.run()

assert not run_spy.called
assert checkout_spy.call_count == 4
assert checkout_spy.call_count == 2

assert (tmp_dir / "out").exists()
assert (tmp_dir / "out_no_cache").exists()
assert (tmp_dir / "out").read_text() == "out"
assert (tmp_dir / "out_no_cache").read_text() == "out_no_cache"


def test_stage_cache_params(tmp_dir, dvc, mocker):
tmp_dir.gen("params.yaml", "foo: 1\nbar: 2")
tmp_dir.gen("myparams.yaml", "baz: 3\nqux: 4")
tmp_dir.gen(
"script.py",
(
'open("out", "w+").write("out"); '
'open("out_no_cache", "w+").write("out_no_cache")'
),
('open("out", "w+").write("out"); '),
)
stage = dvc.run(
cmd="python script.py",
params=["foo,bar", "myparams.yaml:baz,qux"],
outs=["out"],
outs_no_cache=["out_no_cache"],
single_stage=True,
)

with dvc.lock:
stage.remove(remove_outs=True, force=True)

assert not (tmp_dir / "out").exists()
assert not (tmp_dir / "out_no_cache").exists()
assert not (tmp_dir / "out.dvc").exists()

cache_dir = os.path.join(
dvc.stage_cache.cache_dir,
"65",
"651d0a5b82e05e48b03acf44954f6a8599760e652a143d517a17d1065eca61a1",
"8f",
"8fdb377d1b4c0a303b788771b122dfba9bbbbc43f14ce41d35715cf4fea08459",
)
cache_file = os.path.join(
cache_dir,
"2196a5a4dd24c5759437511fcf9d6aa66b259e1dac58e3f212aefd1797a6f114",
"202ea269108bf98bea3e15f978e7929864728956c9df8d927a5c7d74fc4fedc8",
)

assert os.path.isdir(cache_dir)
Expand All @@ -102,29 +90,23 @@ def test_stage_cache_params(tmp_dir, dvc, mocker):
stage.run()

assert not run_spy.called
assert checkout_spy.call_count == 4
assert checkout_spy.call_count == 2

assert (tmp_dir / "out").exists()
assert (tmp_dir / "out_no_cache").exists()
assert (tmp_dir / "out").read_text() == "out"
assert (tmp_dir / "out_no_cache").read_text() == "out_no_cache"


def test_stage_cache_wdir(tmp_dir, dvc, mocker):
tmp_dir.gen("dep", "dep")
tmp_dir.gen(
"script.py",
(
'open("out", "w+").write("out"); '
'open("out_no_cache", "w+").write("out_no_cache")'
),
('open("out", "w+").write("out"); '),
)
tmp_dir.gen({"wdir": {}})
stage = dvc.run(
cmd="python ../script.py",
deps=["../script.py", "../dep"],
outs=["out"],
outs_no_cache=["out_no_cache"],
single_stage=True,
wdir="wdir",
)
Expand All @@ -133,17 +115,16 @@ def test_stage_cache_wdir(tmp_dir, dvc, mocker):
stage.remove(remove_outs=True, force=True)

assert not (tmp_dir / "wdir" / "out").exists()
assert not (tmp_dir / "wdir" / "out_no_cache").exists()
assert not (tmp_dir / "wdir" / "out.dvc").exists()

cache_dir = os.path.join(
dvc.stage_cache.cache_dir,
"d2",
"d2b5da199f4da73a861027f5f76020a948794011db9704814fdb2a488ca93ec2",
"b5",
"b5d5548c43725139aa3419eb50717e062fe9b81f866f401fd6fd778d2a97822d",
)
cache_file = os.path.join(
cache_dir,
"65cc63ade5ab338541726b26185ebaf42331141ec3a670a7d6e8a227505afade",
"e0a59f6a5bd193032a4d1500abd89c9b08a2e9b26c724015e0bc6374295a3b9f",
)

assert os.path.isdir(cache_dir)
Expand All @@ -156,12 +137,10 @@ def test_stage_cache_wdir(tmp_dir, dvc, mocker):
stage.run()

assert not run_spy.called
assert checkout_spy.call_count == 4
assert checkout_spy.call_count == 2

assert (tmp_dir / "wdir" / "out").exists()
assert (tmp_dir / "wdir" / "out_no_cache").exists()
assert (tmp_dir / "wdir" / "out").read_text() == "out"
assert (tmp_dir / "wdir" / "out_no_cache").read_text() == "out_no_cache"


def test_shared_stage_cache(tmp_dir, dvc, run_copy):
Expand Down