Files
dvc/tests/func/experiments/test_checkpoints.py
T
Peter Rowlands (변기호) f5d46c2fdf experiments: run single experiments in user's workspace by default (#5124)
* experiments: move executor into a module

* experiments: separate executor into base/local

* rename LocalExecutor to TempDirExecutor, run in .dvc/tmp by default

* git: restore HEAD using reset not checkout in detached_head()

* experiments: support calling BaseExecutor.reproduce directly for
workspace runs

* experiments: run single experiments in local workspace by default

* update experiments tests for workspace changes

* experiments: update checkpoints for workspace runs

* update checkpoints tests

* update test_show

* add force param for apply

* exp apply: add --force option

* exp run/res: add --temp option to force tempdir execution for single
experiments

* force apply in non-apply specific tests
2020-12-18 18:55:26 +09:00

212 lines
6.4 KiB
Python

import logging
import pytest
from funcy import first
from dvc.exceptions import DvcException
from dvc.repo.experiments import Experiments, MultipleBranchError
from dvc.repo.experiments.base import EXEC_APPLY, EXEC_CHECKPOINT
@pytest.mark.parametrize("workspace", [True, False])
def test_new_checkpoint(
tmp_dir, scm, dvc, checkpoint_stage, mocker, workspace
):
new_mock = mocker.spy(dvc.experiments, "new")
results = dvc.experiments.run(
checkpoint_stage.addressing, params=["foo=2"], tmp_dir=not workspace
)
exp = first(results)
new_mock.assert_called_once()
for rev in dvc.brancher([exp]):
if rev == "workspace":
continue
tree = dvc.repo_tree
with tree.open(tmp_dir / "foo") as fobj:
assert fobj.read().strip() == "5"
with tree.open(tmp_dir / "metrics.yaml") as fobj:
assert fobj.read().strip() == "foo: 2"
if workspace:
assert scm.get_ref(EXEC_APPLY) == exp
assert scm.get_ref(EXEC_CHECKPOINT) == exp
if workspace:
assert (tmp_dir / "foo").read_text().strip() == "5"
assert (tmp_dir / "metrics.yaml").read_text().strip() == "foo: 2"
@pytest.mark.parametrize(
"checkpoint_resume, workspace",
[
(Experiments.LAST_CHECKPOINT, True),
(Experiments.LAST_CHECKPOINT, False),
("foo", True),
("foo", False),
],
)
def test_resume_checkpoint(
tmp_dir, scm, dvc, checkpoint_stage, checkpoint_resume, workspace
):
with pytest.raises(DvcException):
dvc.experiments.run(
checkpoint_stage=checkpoint_stage.addressing,
checkpoint_resume=checkpoint_resume,
tmp_dir=not workspace,
)
results = dvc.experiments.run(
checkpoint_stage.addressing, params=["foo=2"], tmp_dir=not workspace
)
with pytest.raises(DvcException):
dvc.experiments.run(
checkpoint_stage.addressing,
checkpoint_resume="abc1234",
tmp_dir=not workspace,
)
if checkpoint_resume != Experiments.LAST_CHECKPOINT:
checkpoint_resume = first(results)
if not workspace:
dvc.experiments.apply(first(results))
results = dvc.experiments.run(
checkpoint_stage.addressing,
checkpoint_resume=checkpoint_resume,
tmp_dir=not workspace,
)
exp = first(results)
for rev in dvc.brancher([exp]):
if rev == "workspace":
continue
tree = dvc.repo_tree
with tree.open(tmp_dir / "foo") as fobj:
assert fobj.read().strip() == "10"
with tree.open(tmp_dir / "metrics.yaml") as fobj:
assert fobj.read().strip() == "foo: 2"
if workspace:
assert scm.get_ref(EXEC_APPLY) == exp
assert scm.get_ref(EXEC_CHECKPOINT) == exp
@pytest.mark.parametrize("workspace", [True, False])
def test_reset_checkpoint(
tmp_dir, scm, dvc, checkpoint_stage, caplog, workspace
):
from dvc.repo.experiments.base import CheckpointExistsError
dvc.experiments.run(
checkpoint_stage.addressing, name="foo", tmp_dir=not workspace,
)
if workspace:
scm.reset(hard=True)
scm.gitpython.repo.git.clean(force=True)
if workspace:
with caplog.at_level(logging.ERROR):
dvc.experiments.run(
checkpoint_stage.addressing,
name="foo",
params=["foo=2"],
tmp_dir=not workspace,
)
assert "checkpoint experiment conflicts with existing" in caplog.text
scm.reset(hard=True)
scm.gitpython.repo.git.clean(force=True)
else:
with pytest.raises(CheckpointExistsError):
dvc.experiments.run(
checkpoint_stage.addressing,
name="foo",
params=["foo=2"],
tmp_dir=not workspace,
)
results = dvc.experiments.run(
checkpoint_stage.addressing,
params=["foo=2"],
name="foo",
force=True,
tmp_dir=not workspace,
)
exp = first(results)
for rev in dvc.brancher([exp]):
if rev == "workspace":
continue
tree = dvc.repo_tree
with tree.open(tmp_dir / "foo") as fobj:
assert fobj.read().strip() == "5"
with tree.open(tmp_dir / "metrics.yaml") as fobj:
assert fobj.read().strip() == "foo: 2"
if workspace:
assert scm.get_ref(EXEC_APPLY) == exp
assert scm.get_ref(EXEC_CHECKPOINT) == exp
@pytest.mark.parametrize("workspace", [True, False])
def test_resume_branch(tmp_dir, scm, dvc, checkpoint_stage, workspace):
results = dvc.experiments.run(
checkpoint_stage.addressing, params=["foo=2"], tmp_dir=not workspace
)
branch_rev = first(results)
if not workspace:
dvc.experiments.apply(branch_rev)
results = dvc.experiments.run(
checkpoint_stage.addressing,
checkpoint_resume=branch_rev,
tmp_dir=not workspace,
)
checkpoint_a = first(results)
if not workspace:
dvc.experiments.apply(checkpoint_a, force=True)
with pytest.raises(DvcException):
results = dvc.experiments.run(
checkpoint_stage.addressing,
checkpoint_resume=branch_rev,
params=["foo=100"],
tmp_dir=not workspace,
)
dvc.experiments.apply(branch_rev, force=True)
results = dvc.experiments.run(
checkpoint_stage.addressing,
checkpoint_resume=branch_rev,
params=["foo=100"],
tmp_dir=not workspace,
)
checkpoint_b = first(results)
for rev in dvc.brancher([checkpoint_a]):
if rev == "workspace":
continue
tree = dvc.repo_tree
with tree.open(tmp_dir / "foo") as fobj:
assert fobj.read().strip() == "10"
with tree.open(tmp_dir / "metrics.yaml") as fobj:
assert fobj.read().strip() == "foo: 2"
for rev in dvc.brancher([checkpoint_b]):
if rev == "workspace":
continue
tree = dvc.repo_tree
with tree.open(tmp_dir / "foo") as fobj:
assert fobj.read().strip() == "10"
with tree.open(tmp_dir / "metrics.yaml") as fobj:
assert fobj.read().strip() == "foo: 100"
with pytest.raises(MultipleBranchError):
dvc.experiments.get_branch_by_rev(branch_rev)
assert branch_rev == dvc.experiments.scm.gitpython.repo.git.merge_base(
checkpoint_a, checkpoint_b
)