diff --git a/dvc/repo/brancher.py b/dvc/repo/brancher.py index c88f2abf0..6b78d62fb 100644 --- a/dvc/repo/brancher.py +++ b/dvc/repo/brancher.py @@ -1,3 +1,5 @@ +from functools import partial + from funcy import group_by @@ -58,7 +60,10 @@ def brancher( # noqa: E302 try: if revs: - for sha, names in group_by(scm.resolve_rev, revs).items(): + from dvc.scm import resolve_rev + + rev_resolver = partial(resolve_rev, scm) + for sha, names in group_by(rev_resolver, revs).items(): self.fs = scm.get_fs(sha) # ignore revs that don't contain repo root # (i.e. revs from before a subdir=True repo was init'ed) diff --git a/dvc/repo/experiments/__init__.py b/dvc/repo/experiments/__init__.py index 4c2cadf68..417c85178 100644 --- a/dvc/repo/experiments/__init__.py +++ b/dvc/repo/experiments/__init__.py @@ -409,7 +409,9 @@ class Experiments: self.scm.reset() if checkpoint_resume: - resume_rev = self.scm.resolve_rev(checkpoint_resume) + from dvc.scm import resolve_rev + + resume_rev = resolve_rev(self.scm, checkpoint_resume) try: self.check_baseline(resume_rev) checkpoint_resume = resume_rev @@ -879,7 +881,9 @@ class Experiments: return self._get_baseline(rev) def _get_baseline(self, rev): - rev = self.scm.resolve_rev(rev) + from dvc.scm import resolve_rev + + rev = resolve_rev(self.scm, rev) if rev in self.stash_revs: entry = self.stash_revs.get(rev) diff --git a/dvc/repo/experiments/apply.py b/dvc/repo/experiments/apply.py index 88f657f97..af4f42671 100644 --- a/dvc/repo/experiments/apply.py +++ b/dvc/repo/experiments/apply.py @@ -3,7 +3,6 @@ import os from dvc.repo import locked from dvc.repo.scm_context import scm_context -from dvc.scm.base import RevError from dvc.utils.fs import remove from .base import ( @@ -21,13 +20,14 @@ logger = logging.getLogger(__name__) @scm_context def apply(repo, rev, force=True, **kwargs): from dvc.repo.checkout import checkout as dvc_checkout - from dvc.scm.base import SCMError + from dvc.scm import resolve_rev + from dvc.scm.base import RevError, SCMError from dvc.scm.exceptions import MergeConflictError exps = repo.experiments try: - exp_rev = repo.scm.resolve_rev(rev) + exp_rev = resolve_rev(repo.scm, rev) exps.check_baseline(exp_rev) except (RevError, BaselineMismatchError) as exc: raise InvalidExpRevError(rev) from exc diff --git a/dvc/repo/experiments/branch.py b/dvc/repo/experiments/branch.py index 31b0fc4f6..299fddba7 100644 --- a/dvc/repo/experiments/branch.py +++ b/dvc/repo/experiments/branch.py @@ -14,8 +14,10 @@ logger = logging.getLogger(__name__) @locked @scm_context def branch(repo, exp_rev, branch_name, *args, **kwargs): + from dvc.scm import resolve_rev + try: - rev = repo.scm.resolve_rev(exp_rev) + rev = resolve_rev(repo.scm, exp_rev) except RevError: raise InvalidArgumentError(exp_rev) ref_info = None diff --git a/dvc/repo/experiments/diff.py b/dvc/repo/experiments/diff.py index 38f206950..66c4584e0 100644 --- a/dvc/repo/experiments/diff.py +++ b/dvc/repo/experiments/diff.py @@ -9,13 +9,14 @@ logger = logging.getLogger(__name__) def diff(repo, *args, a_rev=None, b_rev=None, param_deps=False, **kwargs): from dvc.repo.experiments.show import _collect_experiment_commit + from dvc.scm import resolve_rev if repo.scm.no_commits: return {} if a_rev: a_rev = fix_exp_head(repo.scm, a_rev) - rev = repo.scm.resolve_rev(a_rev) + rev = resolve_rev(repo.scm, a_rev) old = _collect_experiment_commit(repo, rev, param_deps=param_deps) else: old = _collect_experiment_commit( @@ -24,7 +25,7 @@ def diff(repo, *args, a_rev=None, b_rev=None, param_deps=False, **kwargs): if b_rev: b_rev = fix_exp_head(repo.scm, b_rev) - rev = repo.scm.resolve_rev(b_rev) + rev = resolve_rev(repo.scm, b_rev) new = _collect_experiment_commit(repo, rev, param_deps=param_deps) else: new = _collect_experiment_commit( diff --git a/dvc/repo/experiments/ls.py b/dvc/repo/experiments/ls.py index 812a39d6f..da6878e46 100644 --- a/dvc/repo/experiments/ls.py +++ b/dvc/repo/experiments/ls.py @@ -3,7 +3,6 @@ from collections import defaultdict from dvc.repo import locked from dvc.repo.scm_context import scm_context -from dvc.scm.base import RevError from .utils import ( exp_refs, @@ -18,11 +17,13 @@ logger = logging.getLogger(__name__) @locked @scm_context def ls(repo, *args, rev=None, git_remote=None, all_=False, **kwargs): + from dvc.scm import resolve_rev + from dvc.scm.base import RevError from dvc.scm.git import Git if rev: try: - rev = repo.scm.resolve_rev(rev) + rev = resolve_rev(repo.scm, rev) except RevError: if not (git_remote and Git.is_sha(rev)): # This could be a remote rev that has not been fetched yet diff --git a/dvc/repo/experiments/remove.py b/dvc/repo/experiments/remove.py index 4d66ca61e..7508a338f 100644 --- a/dvc/repo/experiments/remove.py +++ b/dvc/repo/experiments/remove.py @@ -52,8 +52,11 @@ def _get_exp_stash_index(repo, ref_or_rev: str) -> Optional[int]: for _, ref_info in stash_revs.items(): if ref_info.name == ref_or_rev: return ref_info.index + + from dvc.scm import resolve_rev + try: - rev = repo.scm.resolve_rev(ref_or_rev) + rev = resolve_rev(repo.scm, ref_or_rev) if rev in stash_revs: return stash_revs.get(rev).index except RevError: diff --git a/dvc/repo/experiments/show.py b/dvc/repo/experiments/show.py index e37a199d3..216289926 100644 --- a/dvc/repo/experiments/show.py +++ b/dvc/repo/experiments/show.py @@ -10,7 +10,6 @@ from dvc.repo.experiments.executor.base import ExecutorInfo from dvc.repo.experiments.utils import fix_exp_head from dvc.repo.metrics.show import _gather_metrics from dvc.repo.params.show import _gather_params -from dvc.scm.base import SCMError from dvc.utils import error_handler, onerror_collect logger = logging.getLogger(__name__) @@ -121,12 +120,16 @@ def show( raise InvalidArgumentError(f"Invalid number of commits '{num}'") if revs is None: + from dvc.scm import resolve_rev + from dvc.scm.base import RevError + revs = [] for n in range(num): try: head = fix_exp_head(repo.scm, f"HEAD~{n}") - revs.append(repo.scm.resolve_rev(head)) - except SCMError: + assert head + revs.append(resolve_rev(repo.scm, head)) + except RevError: break revs = OrderedDict( diff --git a/dvc/scm/__init__.py b/dvc/scm/__init__.py index 3dccfb298..b3942b9ae 100644 --- a/dvc/scm/__init__.py +++ b/dvc/scm/__init__.py @@ -34,10 +34,20 @@ def SCM( def clone(url: str, to_path: str, **kwargs): - from .exceptions import CloneError as InternalCloneError from .base import CloneError + from .exceptions import CloneError as InternalCloneError try: return Git.clone(url, to_path, **kwargs) except InternalCloneError as exc: raise CloneError(str(exc)) + + +def resolve_rev(scm: "Git", rev: str) -> str: + from .base import RevError + from .exceptions import RevError as InternalRevError + + try: + return scm.resolve_rev(rev) + except InternalRevError as exc: + raise RevError(str(exc)) diff --git a/dvc/scm/exceptions.py b/dvc/scm/exceptions.py index cb549e065..622c7f6c7 100644 --- a/dvc/scm/exceptions.py +++ b/dvc/scm/exceptions.py @@ -34,4 +34,8 @@ class CloneError(SCMError): def __init__(self, url: str, path: str) -> None: self.url = url self.path = path - super().__init__(f"Failed to clone repo '{url}' to '{path}'") \ No newline at end of file + super().__init__(f"Failed to clone repo '{url}' to '{path}'") + + +class RevError(SCMError): + pass diff --git a/dvc/scm/git/__init__.py b/dvc/scm/git/__init__.py index 756416529..d66a7d71a 100644 --- a/dvc/scm/git/__init__.py +++ b/dvc/scm/git/__init__.py @@ -11,8 +11,8 @@ from typing import Dict, Iterable, Optional, Tuple, Type from funcy import cached_property, first from pathspec.patterns import GitWildMatchPattern -from dvc.scm.base import Base, RevError -from dvc.scm.exceptions import FileNotInRepoError +from dvc.scm.base import Base +from dvc.scm.exceptions import FileNotInRepoError, RevError from dvc.utils import relpath from dvc.utils.fs import path_isin diff --git a/dvc/scm/git/backend/gitpython.py b/dvc/scm/git/backend/gitpython.py index 658896db8..4cc3ba60c 100644 --- a/dvc/scm/git/backend/gitpython.py +++ b/dvc/scm/git/backend/gitpython.py @@ -17,8 +17,8 @@ from typing import ( from funcy import ignore from dvc.progress import Tqdm -from dvc.scm.base import RevError, SCMError -from dvc.scm.exceptions import MergeConflictError, CloneError +from dvc.scm.base import SCMError +from dvc.scm.exceptions import CloneError, MergeConflictError, RevError from dvc.utils import fix_env, is_binary, relpath from ..objects import GitCommit, GitObject diff --git a/dvc/scm/git/backend/pygit2.py b/dvc/scm/git/backend/pygit2.py index bf0be8efd..284fe1c5c 100644 --- a/dvc/scm/git/backend/pygit2.py +++ b/dvc/scm/git/backend/pygit2.py @@ -17,8 +17,8 @@ from typing import ( from funcy import cached_property -from dvc.scm.base import RevError, SCMError -from dvc.scm.exceptions import MergeConflictError +from dvc.scm.base import SCMError +from dvc.scm.exceptions import MergeConflictError, RevError from dvc.utils import relpath from ..objects import GitCommit, GitObject diff --git a/tests/unit/scm/test_git.py b/tests/unit/scm/test_git.py index e98c1849c..3cbae66d0 100644 --- a/tests/unit/scm/test_git.py +++ b/tests/unit/scm/test_git.py @@ -422,7 +422,7 @@ def test_checkout_index_conflicts(tmp_dir, scm, git, strategy, expected): def test_resolve_rev(tmp_dir, scm, make_tmp_dir, git): - from dvc.scm.base import RevError + from dvc.scm.exceptions import RevError if git.test_backend == "dulwich": pytest.skip()