diff --git a/dvc/utils/__init__.py b/dvc/utils/__init__.py index 81157ed997..05e3545f6b 100644 --- a/dvc/utils/__init__.py +++ b/dvc/utils/__init__.py @@ -476,17 +476,25 @@ def is_exec(mode): def glob_targets(targets, glob=True, recursive=True): + from ..exceptions import DvcException + if not glob: return targets from glob import iglob - return [ + results = [ exp_target for target in targets for exp_target in iglob(target, recursive=recursive) ] + if not results: + msg = f"Glob {targets} has no matches." + raise DvcException(msg) + + return results + def error_handler(func): def wrapper(*args, **kwargs): diff --git a/tests/func/test_utils.py b/tests/func/test_utils.py index 026357afd8..7910f4fbac 100644 --- a/tests/func/test_utils.py +++ b/tests/func/test_utils.py @@ -1,4 +1,9 @@ +import re + +import pytest + from dvc import utils +from dvc.exceptions import DvcException from dvc.fs.local import LocalFileSystem @@ -42,3 +47,10 @@ def test_boxify(): ) assert expected == utils.boxify("message") + + +def test_glob_no_match(): + with pytest.raises( + DvcException, match=re.escape("Glob ['invalid*'] has no matches.") + ): + utils.glob_targets(["invalid*"], glob=True)