Repository: iterative/dvc

Issue:
Show a proper message if repository does not have metrics and show is called
Let's show something like:

"No metric files in this repository. Use `dvc metrics add` to add a metric file to track."

if `dvc metrics show` is called on a repository that does not have any metrics yet.


Discussion:

Resolving patch:
diff --git a/dvc/command/metrics.py b/dvc/command/metrics.py
--- a/dvc/command/metrics.py
+++ b/dvc/command/metrics.py
@@ -1,25 +1,43 @@
 from dvc.command.common.base import CmdBase
+from dvc.exceptions import DvcException
 
 
 class CmdMetricsShow(CmdBase):
     def run(self):
-        self.project.metrics_show(self.args.path,
-                                  json_path=self.args.json_path,
-                                  tsv_path=self.args.tsv_path,
-                                  htsv_path=self.args.htsv_path,
-                                  csv_path=self.args.csv_path,
-                                  hcsv_path=self.args.hcsv_path,
-                                  all_branches=self.args.all_branches)
+        try:
+            self.project.metrics_show(self.args.path,
+                                      json_path=self.args.json_path,
+                                      tsv_path=self.args.tsv_path,
+                                      htsv_path=self.args.htsv_path,
+                                      csv_path=self.args.csv_path,
+                                      hcsv_path=self.args.hcsv_path,
+                                      all_branches=self.args.all_branches)
+        except DvcException as exc:
+            self.project.logger.error('Failed to show metrics', exc)
+            return 1
+
         return 0
 
 
 class CmdMetricsAdd(CmdBase):
     def run(self):
-        self.project.metrics_add(self.args.path)
+        try:
+            self.project.metrics_add(self.args.path)
+        except DvcException as exc:
+            msg = 'Failed to add metric file \'{}\''.format(self.args.path)
+            self.project.logger.error(msg, exc)
+            return 1
+
         return 0
 
 
 class CmdMetricsRemove(CmdBase):
     def run(self):
-        self.project.metrics_remove(self.args.path)
+        try:
+            self.project.metrics_remove(self.args.path)
+        except DvcException as exc:
+            msg = 'Failed to remove metric file \'{}\''.format(self.args.path)
+            self.project.logger.error(msg, exc)
+            return 1
+
         return 0
diff --git a/dvc/project.py b/dvc/project.py
--- a/dvc/project.py
+++ b/dvc/project.py
@@ -488,15 +488,27 @@ def metrics_show(self, path=None, json_path=None,
             for fname, metric in val.items():
                 self.logger.info('\t{}: {}'.format(fname, metric))
 
-        return res
+        if res:
+            return res
+
+
+        if path:
+            msg = 'File \'{}\' does not exist'.format(path)
+        else:
+            msg = 'No metric files in this repository. ' \
+                  'Use \'dvc metrics add\' to add a metric file to track.'
+        raise DvcException(msg)
 
     def _metrics_modify(self, path, val):
         apath = os.path.abspath(path)
+        found = False
         for stage in self.stages():
             for out in stage.outs:
                 if apath != out.path:
                     continue
 
+                found = True
+
                 if out.path_info['scheme'] != 'local':
                     msg = 'Output \'{}\' scheme \'{}\' is not supported for metrics'
                     raise DvcException(msg.format(out.path, out.path_info['scheme']))
@@ -510,6 +522,10 @@ def _metrics_modify(self, path, val):
 
             stage.dump()
 
+        if not found:
+            msg = 'Unable to find file \'{}\' in the pipeline'.format(path)
+            raise DvcException(msg)
+
     def metrics_add(self, path):
         self._metrics_modify(path, True)
 


Test patch:
diff --git a/tests/test_metrics.py b/tests/test_metrics.py
--- a/tests/test_metrics.py
+++ b/tests/test_metrics.py
@@ -89,7 +89,7 @@ def test(self):
         self.assertEqual(ret, 0)
 
         ret = main(['repro', '-f', '-m', stage.path])
-        self.assertEqual(ret, 0)
+        self.assertNotEqual(ret, 0)
 
     def test_dir(self):
         os.mkdir('metrics_dir')
@@ -140,3 +140,16 @@ def test_binary(self):
         with self.assertRaises(DvcException):
             self.dvc.run(outs_no_cache=['metrics_bin'])
             self.dvc.metrics_add('metrics_bin')
+
+    def test_non_existing(self):
+        ret = main(['metrics', 'add', 'non-existing'])
+        self.assertNotEqual(ret, 0)
+
+        ret = main(['metrics', 'remove', 'non-existing'])
+        self.assertNotEqual(ret, 0)
+
+
+class TestNoMetrics(TestDvc):
+    def test(self):
+        ret = main(['metrics', 'show'])
+        self.assertNotEqual(ret, 0)