diff --git a/dvc/command/run.py b/dvc/command/run.py index 207a9c4486..8b3e856dc6 100644 --- a/dvc/command/run.py +++ b/dvc/command/run.py @@ -133,7 +133,7 @@ def add_parser(subparsers, parent_parser): "--metrics", action="append", default=[], - help="Declare output metric file or directory.", + help="Declare output metric file.", metavar="", ) run_parser.add_argument( @@ -141,8 +141,7 @@ def add_parser(subparsers, parent_parser): "--metrics-no-cache", action="append", default=[], - help="Declare output metric file or directory " - "(do not put into DVC cache).", + help="Declare output metric file (do not put into DVC cache).", metavar="", ) run_parser.add_argument( diff --git a/dvc/output/base.py b/dvc/output/base.py index c651d570a4..75bac38216 100644 --- a/dvc/output/base.py +++ b/dvc/output/base.py @@ -246,10 +246,11 @@ def save(self): self.ignore() + if self.metric or self.plot: + self.verify_metric() + if not self.use_cache: self.info = self.save_info() - if self.metric or self.plot: - self.verify_metric() if not self.IS_DEPENDENCY: logger.debug( "Output '%s' doesn't use cache. Skipping saving.", self diff --git a/dvc/output/local.py b/dvc/output/local.py index f84d3478b4..f7d153efe8 100644 --- a/dvc/output/local.py +++ b/dvc/output/local.py @@ -81,7 +81,7 @@ def verify_metric(self): name = "metrics" if self.metric else "plot" if os.path.isdir(path): msg = "directory '{}' cannot be used as {}." - raise DvcException(msg.format(self.path_info, name)) + raise IsADirectoryError(msg.format(self.path_info, name)) if not istextfile(path): msg = "binary file '{}' cannot be used as {}." diff --git a/tests/func/test_run_single_stage.py b/tests/func/test_run_single_stage.py index 57f0a9d2c0..b92b9bc82e 100644 --- a/tests/func/test_run_single_stage.py +++ b/tests/func/test_run_single_stage.py @@ -989,3 +989,31 @@ def test_should_raise_on_stage_output(tmp_dir, dvc, run_copy): with pytest.raises(OutputIsStageFileError): run_copy("foo", "name.dvc", single_stage=True) + + +class TestRunDirMetrics: + @pytest.fixture(autouse=True) + def setup(self, dvc): + with open("script.py", "w+") as fobj: + fobj.write("import sys\n") + fobj.write("import os\n") + fobj.write("os.makedirs(sys.argv[1])\n") + fobj.write( + "with open(os.path.join(sys.argv[1], " + "'metrics.json'), 'a+') as fobj:\n" + ) + fobj.write(" fobj.write('foo')\n") + + def test_metrics_dir_cached(self, dvc): + with pytest.raises(IsADirectoryError): + dvc.run( + cmd="python script.py dir", metrics=["dir"], single_stage=True, + ) + + def test_metrics_dir_not_cached(self, dvc): + with pytest.raises(IsADirectoryError): + dvc.run( + cmd="python script.py dir", + metrics_no_cache=["dir"], + single_stage=True, + )