mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-04 15:28:27 +01:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45c9b2c9f6 | ||
|
|
a9ae450a64 | ||
|
|
60e161004d |
+30
-1
@@ -1,5 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
|
from contextlib import contextmanager
|
||||||
from itertools import chain, filterfalse
|
from itertools import chain, filterfalse
|
||||||
from typing import TYPE_CHECKING, Dict, Iterable, List
|
from typing import TYPE_CHECKING, Dict, Iterable, List
|
||||||
|
|
||||||
@@ -119,8 +120,22 @@ def parse_cmd(commands: List[str]) -> str:
|
|||||||
return " ".join(map(quote_argument, commands))
|
return " ".join(map(quote_argument, commands))
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def _disable_logging(highest_level=logging.CRITICAL):
|
||||||
|
previous_level = logging.root.manager.disable
|
||||||
|
|
||||||
|
logging.disable(highest_level)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
logging.disable(previous_level)
|
||||||
|
|
||||||
|
|
||||||
class CmdStageAdd(CmdBase):
|
class CmdStageAdd(CmdBase):
|
||||||
def run(self):
|
def run(self):
|
||||||
|
from dvc.repo import lock_repo
|
||||||
|
|
||||||
kwargs = vars(self.args)
|
kwargs = vars(self.args)
|
||||||
kwargs.update(
|
kwargs.update(
|
||||||
{
|
{
|
||||||
@@ -128,7 +143,15 @@ class CmdStageAdd(CmdBase):
|
|||||||
"params": parse_params(self.args.params),
|
"params": parse_params(self.args.params),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.repo.stage.add(**kwargs)
|
|
||||||
|
with self.repo.scm_context, lock_repo(self.repo):
|
||||||
|
with _disable_logging(logging.INFO):
|
||||||
|
stage = self.repo.stage.add(**kwargs)
|
||||||
|
logger.info("Added stage %r in %r", stage.addressing, stage.relpath)
|
||||||
|
if self.args.run:
|
||||||
|
stage.run()
|
||||||
|
stage.dump(update_pipeline=False)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@@ -257,6 +280,12 @@ def _add_common_args(parser):
|
|||||||
"This doesn't affect any DVC operations."
|
"This doesn't affect any DVC operations."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--run",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Execute the stage after generating it.",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"command",
|
"command",
|
||||||
nargs=argparse.REMAINDER,
|
nargs=argparse.REMAINDER,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Optional
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
from dvc.repo import locked
|
from dvc.repo import locked
|
||||||
from dvc.repo.scm_context import scm_context
|
from dvc.repo.scm_context import scm_context
|
||||||
@@ -15,14 +15,17 @@ logger = logging.getLogger(__name__)
|
|||||||
@scm_context
|
@scm_context
|
||||||
def ls(
|
def ls(
|
||||||
repo,
|
repo,
|
||||||
rev: Optional[str] = None,
|
rev: Optional[Union[List[str], str]] = None,
|
||||||
all_commits: bool = False,
|
all_commits: bool = False,
|
||||||
num: int = 1,
|
num: int = 1,
|
||||||
git_remote: Optional[str] = None,
|
git_remote: Optional[str] = None,
|
||||||
):
|
):
|
||||||
rev_set = None
|
rev_set = None
|
||||||
if not all_commits:
|
if not all_commits:
|
||||||
revs = iter_revs(repo.scm, [rev or "HEAD"], num)
|
rev = rev or "HEAD"
|
||||||
|
if isinstance(rev, str):
|
||||||
|
rev = [rev]
|
||||||
|
revs = iter_revs(repo.scm, rev, num)
|
||||||
rev_set = set(revs.keys())
|
rev_set = set(revs.keys())
|
||||||
ref_info_dict = exp_refs_by_baseline(repo.scm, rev_set, git_remote)
|
ref_info_dict = exp_refs_by_baseline(repo.scm, rev_set, git_remote)
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def pull( # noqa: C901
|
|||||||
git_remote: str,
|
git_remote: str,
|
||||||
exp_names: Union[Iterable[str], str],
|
exp_names: Union[Iterable[str], str],
|
||||||
all_commits=False,
|
all_commits=False,
|
||||||
rev: Optional[str] = None,
|
rev: Optional[Union[List[str], str]] = None,
|
||||||
num=1,
|
num=1,
|
||||||
force: bool = False,
|
force: bool = False,
|
||||||
pull_cache: bool = False,
|
pull_cache: bool = False,
|
||||||
@@ -49,7 +49,9 @@ def pull( # noqa: C901
|
|||||||
raise UnresolvedExpNamesError(unresolved_exp_names)
|
raise UnresolvedExpNamesError(unresolved_exp_names)
|
||||||
|
|
||||||
if rev:
|
if rev:
|
||||||
rev_dict = iter_revs(repo.scm, [rev], num)
|
if isinstance(rev, str):
|
||||||
|
rev = [rev]
|
||||||
|
rev_dict = iter_revs(repo.scm, rev, num)
|
||||||
rev_set = set(rev_dict.keys())
|
rev_set = set(rev_dict.keys())
|
||||||
ref_info_dict = exp_refs_by_baseline(repo.scm, rev_set, git_remote)
|
ref_info_dict = exp_refs_by_baseline(repo.scm, rev_set, git_remote)
|
||||||
for _, ref_info_list in ref_info_dict.items():
|
for _, ref_info_list in ref_info_dict.items():
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
|
|||||||
def remove( # noqa: C901, PLR0912
|
def remove( # noqa: C901, PLR0912
|
||||||
repo: "Repo",
|
repo: "Repo",
|
||||||
exp_names: Union[None, str, List[str]] = None,
|
exp_names: Union[None, str, List[str]] = None,
|
||||||
rev: Optional[str] = None,
|
rev: Optional[Union[List[str], str]] = None,
|
||||||
all_commits: bool = False,
|
all_commits: bool = False,
|
||||||
num: int = 1,
|
num: int = 1,
|
||||||
queue: bool = False,
|
queue: bool = False,
|
||||||
@@ -60,6 +60,8 @@ def remove( # noqa: C901, PLR0912
|
|||||||
if remained:
|
if remained:
|
||||||
raise UnresolvedExpNamesError(remained, git_remote=git_remote)
|
raise UnresolvedExpNamesError(remained, git_remote=git_remote)
|
||||||
elif rev:
|
elif rev:
|
||||||
|
if isinstance(rev, str):
|
||||||
|
rev = [rev]
|
||||||
exp_ref_dict = _resolve_exp_by_baseline(repo, rev, num, git_remote)
|
exp_ref_dict = _resolve_exp_by_baseline(repo, rev, num, git_remote)
|
||||||
removed.extend(exp_ref_dict.keys())
|
removed.extend(exp_ref_dict.keys())
|
||||||
exp_ref_list.extend(exp_ref_dict.values())
|
exp_ref_list.extend(exp_ref_dict.values())
|
||||||
@@ -85,14 +87,14 @@ def remove( # noqa: C901, PLR0912
|
|||||||
|
|
||||||
def _resolve_exp_by_baseline(
|
def _resolve_exp_by_baseline(
|
||||||
repo: "Repo",
|
repo: "Repo",
|
||||||
rev: str,
|
rev: List[str],
|
||||||
num: int,
|
num: int,
|
||||||
git_remote: Optional[str] = None,
|
git_remote: Optional[str] = None,
|
||||||
) -> Dict[str, "ExpRefInfo"]:
|
) -> Dict[str, "ExpRefInfo"]:
|
||||||
assert isinstance(repo.scm, Git)
|
assert isinstance(repo.scm, Git)
|
||||||
|
|
||||||
commit_ref_dict: Dict[str, "ExpRefInfo"] = {}
|
commit_ref_dict: Dict[str, "ExpRefInfo"] = {}
|
||||||
rev_dict = iter_revs(repo.scm, [rev], num)
|
rev_dict = iter_revs(repo.scm, rev, num)
|
||||||
rev_set = set(rev_dict.keys())
|
rev_set = set(rev_dict.keys())
|
||||||
ref_info_dict = exp_refs_by_baseline(repo.scm, rev_set, git_remote)
|
ref_info_dict = exp_refs_by_baseline(repo.scm, rev_set, git_remote)
|
||||||
for _, ref_info_list in ref_info_dict.items():
|
for _, ref_info_list in ref_info_dict.items():
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+9
-10
@@ -122,16 +122,15 @@ class StageLoad:
|
|||||||
force=force,
|
force=force,
|
||||||
**stage_data,
|
**stage_data,
|
||||||
)
|
)
|
||||||
with self.repo.scm_context:
|
stage.dump(update_lock=update_lock)
|
||||||
stage.dump(update_lock=update_lock)
|
try:
|
||||||
try:
|
stage.ignore_outs()
|
||||||
stage.ignore_outs()
|
except FileNotFoundError as exc:
|
||||||
except FileNotFoundError as exc:
|
ui.warn(
|
||||||
ui.warn(
|
f"Could not create .gitignore entry in {exc.filename}."
|
||||||
f"Could not create .gitignore entry in {exc.filename}."
|
" DVC will attempt to create .gitignore entry again when"
|
||||||
" DVC will attempt to create .gitignore entry again when"
|
" the stage is run."
|
||||||
" the stage is run."
|
)
|
||||||
)
|
|
||||||
|
|
||||||
return stage
|
return stage
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -303,5 +303,5 @@ ignore-names = ["M", "SCM"]
|
|||||||
max-args = 10
|
max-args = 10
|
||||||
|
|
||||||
[tool.bandit]
|
[tool.bandit]
|
||||||
exclude_dirs = ["tests", "scripts"]
|
exclude_dirs = ["tests", "scripts", "dvc/repo/experiments/utils.py"]
|
||||||
skips = ["B101"]
|
skips = ["B101"]
|
||||||
|
|||||||
@@ -369,6 +369,12 @@ def test_list(tmp_dir, scm, dvc, exp_stage):
|
|||||||
baseline_a[:7]: {ref_info_a.name, ref_info_b.name}
|
baseline_a[:7]: {ref_info_a.name, ref_info_b.name}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exp_list = dvc.experiments.ls(rev=[baseline_a, scm.get_rev()])
|
||||||
|
assert {key: set(val) for key, val in exp_list.items()} == {
|
||||||
|
baseline_a[:7]: {ref_info_a.name, ref_info_b.name},
|
||||||
|
"master": {ref_info_c.name},
|
||||||
|
}
|
||||||
|
|
||||||
exp_list = dvc.experiments.ls(all_commits=True)
|
exp_list = dvc.experiments.ls(all_commits=True)
|
||||||
assert {key: set(val) for key, val in exp_list.items()} == {
|
assert {key: set(val) for key, val in exp_list.items()} == {
|
||||||
baseline_a[:7]: {ref_info_a.name, ref_info_b.name},
|
baseline_a[:7]: {ref_info_a.name, ref_info_b.name},
|
||||||
|
|||||||
@@ -251,6 +251,30 @@ def test_pull_args(tmp_dir, scm, dvc, git_downstream, exp_stage, all_, rev, resu
|
|||||||
assert git_downstream.tmp_dir.scm.get_ref(str(ref_info3)) == result3
|
assert git_downstream.tmp_dir.scm.get_ref(str(ref_info3)) == result3
|
||||||
|
|
||||||
|
|
||||||
|
def test_pull_multi_rev(tmp_dir, scm, dvc, git_downstream, exp_stage):
|
||||||
|
baseline = scm.get_rev()
|
||||||
|
|
||||||
|
results = dvc.experiments.run(exp_stage.addressing, params=["foo=1"])
|
||||||
|
exp1 = first(results)
|
||||||
|
ref_info1 = first(exp_refs_by_rev(scm, exp1))
|
||||||
|
results = dvc.experiments.run(exp_stage.addressing, params=["foo=2"])
|
||||||
|
exp2 = first(results)
|
||||||
|
ref_info2 = first(exp_refs_by_rev(scm, exp2))
|
||||||
|
|
||||||
|
scm.commit("new_baseline")
|
||||||
|
|
||||||
|
results = dvc.experiments.run(exp_stage.addressing, params=["foo=3"])
|
||||||
|
exp3 = first(results)
|
||||||
|
ref_info3 = first(exp_refs_by_rev(scm, exp3))
|
||||||
|
|
||||||
|
downstream_exp = git_downstream.tmp_dir.dvc.experiments
|
||||||
|
git_downstream.tmp_dir.scm.fetch_refspecs(str(tmp_dir), ["master:master"])
|
||||||
|
downstream_exp.pull(git_downstream.remote, [], rev=[baseline, scm.get_rev()])
|
||||||
|
assert git_downstream.tmp_dir.scm.get_ref(str(ref_info1)) == exp1
|
||||||
|
assert git_downstream.tmp_dir.scm.get_ref(str(ref_info2)) == exp2
|
||||||
|
assert git_downstream.tmp_dir.scm.get_ref(str(ref_info3)) == exp3
|
||||||
|
|
||||||
|
|
||||||
def test_pull_diverged(tmp_dir, scm, dvc, git_downstream, exp_stage):
|
def test_pull_diverged(tmp_dir, scm, dvc, git_downstream, exp_stage):
|
||||||
git_downstream.tmp_dir.scm_gen("foo", "foo", commit="init")
|
git_downstream.tmp_dir.scm_gen("foo", "foo", commit="init")
|
||||||
remote_rev = git_downstream.tmp_dir.scm.get_rev()
|
remote_rev = git_downstream.tmp_dir.scm.get_rev()
|
||||||
|
|||||||
@@ -156,3 +156,26 @@ def test_remove_experiments_by_rev(tmp_dir, scm, dvc, exp_stage):
|
|||||||
assert "queue2" in queue_revs
|
assert "queue2" in queue_revs
|
||||||
assert scm.get_ref(new_exp_ref) is not None
|
assert scm.get_ref(new_exp_ref) is not None
|
||||||
assert "queue4" in queue_revs
|
assert "queue4" in queue_revs
|
||||||
|
|
||||||
|
|
||||||
|
def test_remove_multi_rev(tmp_dir, scm, dvc, exp_stage):
|
||||||
|
baseline = scm.get_rev()
|
||||||
|
|
||||||
|
results = dvc.experiments.run(exp_stage.addressing, params=["foo=1"])
|
||||||
|
baseline_exp_ref = first(exp_refs_by_rev(scm, first(results)))
|
||||||
|
|
||||||
|
dvc.experiments.run(
|
||||||
|
exp_stage.addressing, params=["foo=2"], queue=True, name="queue2"
|
||||||
|
)
|
||||||
|
scm.commit("new_baseline")
|
||||||
|
|
||||||
|
results = dvc.experiments.run(exp_stage.addressing, params=["foo=3"])
|
||||||
|
new_exp_ref = first(exp_refs_by_rev(scm, first(results)))
|
||||||
|
|
||||||
|
assert set(dvc.experiments.remove(rev=[baseline, scm.get_rev()])) == {
|
||||||
|
baseline_exp_ref.name,
|
||||||
|
new_exp_ref.name,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert scm.get_ref(str(baseline_exp_ref)) is None
|
||||||
|
assert scm.get_ref(str(new_exp_ref)) is None
|
||||||
|
|||||||
@@ -2,18 +2,19 @@ from funcy import first
|
|||||||
|
|
||||||
|
|
||||||
def test_generate_random_exp_name(tmp_dir, dvc, scm, exp_stage, mocker):
|
def test_generate_random_exp_name(tmp_dir, dvc, scm, exp_stage, mocker):
|
||||||
|
mocked_generator = mocker.MagicMock()
|
||||||
|
mocked_generator.choice.side_effect = [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
]
|
||||||
mocker.patch(
|
mocker.patch(
|
||||||
"dvc.repo.experiments.utils.random.choice",
|
"dvc.repo.experiments.utils.random.Random", return_value=mocked_generator
|
||||||
side_effect=[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ref = first(dvc.experiments.run(exp_stage.addressing, params=["foo=1"]))
|
ref = first(dvc.experiments.run(exp_stage.addressing, params=["foo=1"]))
|
||||||
|
|||||||
@@ -86,3 +86,15 @@ def test_stage_add(mocker, dvc, command, parsed_command):
|
|||||||
cmd=parsed_command,
|
cmd=parsed_command,
|
||||||
force=True,
|
force=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_stage_add_and_run(mocker, dvc):
|
||||||
|
cli_args = parse_args(["stage", "add", "--run", "-n", "foo", "-o", "foo", "cmd"])
|
||||||
|
cmd = cli_args.func(cli_args)
|
||||||
|
add_mock = mocker.patch.object(cmd.repo.stage, "add")
|
||||||
|
|
||||||
|
assert cmd.run() == 0
|
||||||
|
|
||||||
|
assert called_once_with_subset(add_mock, name="foo", outs=["foo"], cmd="cmd")
|
||||||
|
add_mock.return_value.run.assert_called_once()
|
||||||
|
add_mock.return_value.dump.assert_called_once_with(update_pipeline=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user