We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
"dvc metrics show -a" doesn't work if a metric file is missing
> Hi everyone,

I have three branches. Every branch is one experiment. One experiment should create a metric file as output. Two experiments are already finished, the third experiment is still running. So I have two experiments (= branches) with a metric file and one without.

Now I want to use "dvc metrics show -a" to get the result from the two already finished experiments. But I got an error that the branch with the running experiment does not have a metric file.

I am working with the pip installed DVC (version 0.35.7). The system is a ubuntu 18.04 and use anaconda.

I got help from ruslan in the forum: https://discordapp.com/channels/485586884165107732/563406153334128681/570262271847039028

thanks for the help!

> cmd: python code/train.py 
> deps:
> - path: data/toy_3dpatients_on_mrt.npy
> - path: data/toy_3dpatients_on_mrt_settings.npy
> - path: data/toy_3dpatients_on_mrt_test.npy
> outs:
> - cache: false
>   metric: true
>   path: metrics/test_local_False.json
> - cache: true
>   metric: false
>   path: tensorboards/test_local_False_test
> - cache: true
>   metric: false
>   path: tensorboards/test_local_False_train
> - cache: true
>   metric: false
>   path: tensorflow_models/model_weights_test_local_False.h5

And here is the output from the command `dvc metrics show -v -a`
> (tf-gpu) j@t:~/Documents/gitlab/0005_3d_siamesenet$ dvc metrics show -v -a
> ERROR: unexpected error - [Errno 2] No such file in branch 'test_local': 'metrics/test_local_False.json'
> ------------------------------------------------------------
> Traceback (most recent call last):
>   File "/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/main.py", line 37, in main
>     ret = cmd.run_cmd()
>   File "/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/command/base.py", line 60, in run_cmd
>     return self.run()
>   File "/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/command/metrics.py", line 47, in run
>     recursive=self.args.recursive,
>   File "/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/repo/metrics/init.py", line 18, in show
>     return show(self.repo, *args, **kwargs)
>   File "/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/repo/metrics/show.py", line 263, in show
>     metrics = _read_metrics(self, entries, branch)
>   File "/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/repo/metrics/show.py", line 237, in _read_metrics
>     fd = self.tree.open(out.path)
>   File "/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/scm/git/tree.py", line 34, in open
>     raise IOError(errno.ENOENT, msg, relpath)
> FileNotFoundError: [Errno 2] No such file in branch 'test_local': 'metrics/test_local_False.json'


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dvc/repo/metrics/show.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import os
4 import csv
5 import json
6 import logging
7 from jsonpath_ng.ext import parse
8 
9 from dvc.exceptions import OutputNotFoundError, BadMetricError, NoMetricsError
10 from dvc.utils.compat import builtin_str, open, StringIO, csv_reader
11 
12 
13 logger = logging.getLogger(__name__)
14 
15 
16 def _read_metric_json(fd, json_path):
17     parser = parse(json_path)
18     return [x.value for x in parser.find(json.load(fd))]
19 
20 
21 def _get_values(row):
22     if isinstance(row, dict):
23         return list(row.values())
24     else:
25         return row
26 
27 
28 def _do_read_metric_xsv(reader, row, col):
29     if col is not None and row is not None:
30         return [reader[row][col]]
31     elif col is not None:
32         return [r[col] for r in reader]
33     elif row is not None:
34         return _get_values(reader[row])
35     return [_get_values(r) for r in reader]
36 
37 
38 def _read_metric_hxsv(fd, hxsv_path, delimiter):
39     indices = hxsv_path.split(",")
40     row = indices[0]
41     row = int(row) if row else None
42     col = indices[1] if len(indices) > 1 and indices[1] else None
43     reader = list(csv.DictReader(fd, delimiter=builtin_str(delimiter)))
44     return _do_read_metric_xsv(reader, row, col)
45 
46 
47 def _read_metric_xsv(fd, xsv_path, delimiter):
48     indices = xsv_path.split(",")
49     row = indices[0]
50     row = int(row) if row else None
51     col = int(indices[1]) if len(indices) > 1 and indices[1] else None
52     reader = list(csv.reader(fd, delimiter=builtin_str(delimiter)))
53     return _do_read_metric_xsv(reader, row, col)
54 
55 
56 def _read_typed_metric(typ, xpath, fd):
57     if typ == "json":
58         ret = _read_metric_json(fd, xpath)
59     elif typ == "csv":
60         ret = _read_metric_xsv(fd, xpath, ",")
61     elif typ == "tsv":
62         ret = _read_metric_xsv(fd, xpath, "\t")
63     elif typ == "hcsv":
64         ret = _read_metric_hxsv(fd, xpath, ",")
65     elif typ == "htsv":
66         ret = _read_metric_hxsv(fd, xpath, "\t")
67     else:
68         ret = fd.read().strip()
69     return ret
70 
71 
72 def _format_csv(content, delimiter):
73     """Format delimited text to have same column width.
74 
75     Args:
76         content (str): The content of a metric.
77         delimiter (str): Value separator
78 
79     Returns:
80         str: Formatted content.
81 
82     Example:
83 
84         >>> content = (
85             "value_mse,deviation_mse,data_set\n"
86             "0.421601,0.173461,train\n"
87             "0.67528,0.289545,testing\n"
88             "0.671502,0.297848,validation\n"
89         )
90         >>> _format_csv(content, ",")
91 
92         "value_mse  deviation_mse   data_set\n"
93         "0.421601   0.173461        train\n"
94         "0.67528    0.289545        testing\n"
95         "0.671502   0.297848        validation\n"
96     """
97     reader = csv_reader(StringIO(content), delimiter=builtin_str(delimiter))
98     rows = [row for row in reader]
99     max_widths = [max(map(len, column)) for column in zip(*rows)]
100 
101     lines = [
102         " ".join(
103             "{entry:{width}}".format(entry=entry, width=width + 2)
104             for entry, width in zip(row, max_widths)
105         )
106         for row in rows
107     ]
108 
109     return "\n".join(lines)
110 
111 
112 def _format_output(content, typ):
113     """Tabularize the content according to its type.
114 
115     Args:
116         content (str): The content of a metric.
117         typ (str): The type of metric -- (raw|json|tsv|htsv|csv|hcsv).
118 
119     Returns:
120         str: Content in a raw or tabular format.
121     """
122 
123     if "csv" in str(typ):
124         return _format_csv(content, delimiter=",")
125 
126     if "tsv" in str(typ):
127         return _format_csv(content, delimiter="\t")
128 
129     return content
130 
131 
132 def _read_metric(fd, typ=None, xpath=None, rel_path=None, branch=None):
133     typ = typ.lower().strip() if typ else typ
134     try:
135         if xpath:
136             return _read_typed_metric(typ, xpath.strip(), fd)
137         else:
138             return _format_output(fd.read().strip(), typ)
139     # Json path library has to be replaced or wrapped in
140     # order to fix this too broad except clause.
141     except Exception:
142         logger.exception(
143             "unable to read metric in '{}' in branch '{}'".format(
144                 rel_path, branch
145             )
146         )
147         return None
148 
149 
150 def _collect_metrics(self, path, recursive, typ, xpath, branch):
151     """Gather all the metric outputs.
152 
153     Args:
154         path (str): Path to a metric file or a directory.
155         recursive (bool): If path is a directory, do a recursive search for
156             metrics on the given path.
157         typ (str): The type of metric to search for, could be one of the
158             following (raw|json|tsv|htsv|csv|hcsv).
159         xpath (str): Path to search for.
160         branch (str): Branch to look up for metrics.
161 
162     Returns:
163         list(tuple): (output, typ, xpath)
164             - output:
165             - typ:
166             - xpath:
167     """
168     outs = [out for stage in self.stages() for out in stage.outs]
169 
170     if path:
171         try:
172             outs = self.find_outs_by_path(path, outs=outs, recursive=recursive)
173         except OutputNotFoundError:
174             logger.debug(
175                 "stage file not for found for '{}' in branch '{}'".format(
176                     path, branch
177                 )
178             )
179             return []
180 
181     res = []
182     for o in outs:
183         if not o.metric:
184             continue
185 
186         if not typ and isinstance(o.metric, dict):
187             t = o.metric.get(o.PARAM_METRIC_TYPE, typ)
188             x = o.metric.get(o.PARAM_METRIC_XPATH, xpath)
189         else:
190             t = typ
191             x = xpath
192 
193         res.append((o, t, x))
194 
195     return res
196 
197 
198 def _read_metrics_filesystem(path, typ, xpath, rel_path, branch):
199     if not os.path.exists(path):
200         return None
201     with open(path, "r") as fd:
202         return _read_metric(
203             fd, typ=typ, xpath=xpath, rel_path=rel_path, branch=branch
204         )
205 
206 
207 def _read_metrics(self, metrics, branch):
208     """Read the content of each metric file and format it.
209 
210     Args:
211         metrics (list): List of metric touples
212         branch (str): Branch to look up for metrics.
213 
214     Returns:
215         A dict mapping keys with metrics path name and content.
216         For example:
217 
218         {'metric.csv': ("value_mse  deviation_mse   data_set\n"
219                         "0.421601   0.173461        train\n"
220                         "0.67528    0.289545        testing\n"
221                         "0.671502   0.297848        validation\n")}
222     """
223     res = {}
224     for out, typ, xpath in metrics:
225         assert out.scheme == "local"
226         if not typ:
227             typ = os.path.splitext(out.path.lower())[1].replace(".", "")
228         if out.use_cache:
229             metric = _read_metrics_filesystem(
230                 self.cache.local.get(out.checksum),
231                 typ=typ,
232                 xpath=xpath,
233                 rel_path=out.rel_path,
234                 branch=branch,
235             )
236         else:
237             with self.tree.open(out.path) as fd:
238                 metric = _read_metric(
239                     fd,
240                     typ=typ,
241                     xpath=xpath,
242                     rel_path=out.rel_path,
243                     branch=branch,
244                 )
245 
246         if not metric:
247             continue
248 
249         res[out.rel_path] = metric
250 
251     return res
252 
253 
254 def show(
255     self,
256     path=None,
257     typ=None,
258     xpath=None,
259     all_branches=False,
260     all_tags=False,
261     recursive=False,
262 ):
263     res = {}
264 
265     for branch in self.brancher(all_branches=all_branches, all_tags=all_tags):
266         entries = _collect_metrics(self, path, recursive, typ, xpath, branch)
267         metrics = _read_metrics(self, entries, branch)
268         if metrics:
269             res[branch] = metrics
270 
271     if not res:
272         if path:
273             raise BadMetricError(path)
274         raise NoMetricsError()
275 
276     return res
277
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/dvc/repo/metrics/show.py b/dvc/repo/metrics/show.py
--- a/dvc/repo/metrics/show.py
+++ b/dvc/repo/metrics/show.py
@@ -1,14 +1,19 @@
 from __future__ import unicode_literals
 
+import errno
 import os
 import csv
 import json
 import logging
+
 from jsonpath_ng.ext import parse
 
 from dvc.exceptions import OutputNotFoundError, BadMetricError, NoMetricsError
 from dvc.utils.compat import builtin_str, open, StringIO, csv_reader
 
+NO_METRICS_FILE_AT_REFERENCE_WARNING = (
+    "Metrics file '{}' does not exist at reference: '{}'"
+)
 
 logger = logging.getLogger(__name__)
 
@@ -147,7 +152,7 @@
         return None
 
 
-def _collect_metrics(self, path, recursive, typ, xpath, branch):
+def _collect_metrics(repo, path, recursive, typ, xpath, branch):
     """Gather all the metric outputs.
 
     Args:
@@ -165,11 +170,11 @@
             - typ:
             - xpath:
     """
-    outs = [out for stage in self.stages() for out in stage.outs]
+    outs = [out for stage in repo.stages() for out in stage.outs]
 
     if path:
         try:
-            outs = self.find_outs_by_path(path, outs=outs, recursive=recursive)
+            outs = repo.find_outs_by_path(path, outs=outs, recursive=recursive)
         except OutputNotFoundError:
             logger.debug(
                 "stage file not for found for '{}' in branch '{}'".format(
@@ -195,16 +200,7 @@
     return res
 
 
-def _read_metrics_filesystem(path, typ, xpath, rel_path, branch):
-    if not os.path.exists(path):
-        return None
-    with open(path, "r") as fd:
-        return _read_metric(
-            fd, typ=typ, xpath=xpath, rel_path=rel_path, branch=branch
-        )
-
-
-def _read_metrics(self, metrics, branch):
+def _read_metrics(repo, metrics, branch):
     """Read the content of each metric file and format it.
 
     Args:
@@ -226,15 +222,14 @@
         if not typ:
             typ = os.path.splitext(out.path.lower())[1].replace(".", "")
         if out.use_cache:
-            metric = _read_metrics_filesystem(
-                self.cache.local.get(out.checksum),
-                typ=typ,
-                xpath=xpath,
-                rel_path=out.rel_path,
-                branch=branch,
-            )
+            open_fun = open
+            path = repo.cache.local.get(out.checksum)
         else:
-            with self.tree.open(out.path) as fd:
+            open_fun = repo.tree.open
+            path = out.path
+        try:
+
+            with open_fun(path) as fd:
                 metric = _read_metric(
                     fd,
                     typ=typ,
@@ -242,6 +237,16 @@
                     rel_path=out.rel_path,
                     branch=branch,
                 )
+        except IOError as e:
+            if e.errno == errno.ENOENT:
+                logger.warning(
+                    NO_METRICS_FILE_AT_REFERENCE_WARNING.format(
+                        out.rel_path, branch
+                    )
+                )
+                metric = None
+            else:
+                raise
 
         if not metric:
             continue
@@ -252,7 +257,7 @@
 
 
 def show(
-    self,
+    repo,
     path=None,
     typ=None,
     xpath=None,
@@ -262,9 +267,9 @@
 ):
     res = {}
 
-    for branch in self.brancher(all_branches=all_branches, all_tags=all_tags):
-        entries = _collect_metrics(self, path, recursive, typ, xpath, branch)
-        metrics = _read_metrics(self, entries, branch)
+    for branch in repo.brancher(all_branches=all_branches, all_tags=all_tags):
+        entries = _collect_metrics(repo, path, recursive, typ, xpath, branch)
+        metrics = _read_metrics(repo, entries, branch)
         if metrics:
             res[branch] = metrics

{"golden_diff": "diff --git a/dvc/repo/metrics/show.py b/dvc/repo/metrics/show.py\n--- a/dvc/repo/metrics/show.py\n+++ b/dvc/repo/metrics/show.py\n@@ -1,14 +1,19 @@\n from __future__ import unicode_literals\n \n+import errno\n import os\n import csv\n import json\n import logging\n+\n from jsonpath_ng.ext import parse\n \n from dvc.exceptions import OutputNotFoundError, BadMetricError, NoMetricsError\n from dvc.utils.compat import builtin_str, open, StringIO, csv_reader\n \n+NO_METRICS_FILE_AT_REFERENCE_WARNING = (\n+    \"Metrics file '{}' does not exist at reference: '{}'\"\n+)\n \n logger = logging.getLogger(__name__)\n \n@@ -147,7 +152,7 @@\n         return None\n \n \n-def _collect_metrics(self, path, recursive, typ, xpath, branch):\n+def _collect_metrics(repo, path, recursive, typ, xpath, branch):\n     \"\"\"Gather all the metric outputs.\n \n     Args:\n@@ -165,11 +170,11 @@\n             - typ:\n             - xpath:\n     \"\"\"\n-    outs = [out for stage in self.stages() for out in stage.outs]\n+    outs = [out for stage in repo.stages() for out in stage.outs]\n \n     if path:\n         try:\n-            outs = self.find_outs_by_path(path, outs=outs, recursive=recursive)\n+            outs = repo.find_outs_by_path(path, outs=outs, recursive=recursive)\n         except OutputNotFoundError:\n             logger.debug(\n                 \"stage file not for found for '{}' in branch '{}'\".format(\n@@ -195,16 +200,7 @@\n     return res\n \n \n-def _read_metrics_filesystem(path, typ, xpath, rel_path, branch):\n-    if not os.path.exists(path):\n-        return None\n-    with open(path, \"r\") as fd:\n-        return _read_metric(\n-            fd, typ=typ, xpath=xpath, rel_path=rel_path, branch=branch\n-        )\n-\n-\n-def _read_metrics(self, metrics, branch):\n+def _read_metrics(repo, metrics, branch):\n     \"\"\"Read the content of each metric file and format it.\n \n     Args:\n@@ -226,15 +222,14 @@\n         if not typ:\n             typ = os.path.splitext(out.path.lower())[1].replace(\".\", \"\")\n         if out.use_cache:\n-            metric = _read_metrics_filesystem(\n-                self.cache.local.get(out.checksum),\n-                typ=typ,\n-                xpath=xpath,\n-                rel_path=out.rel_path,\n-                branch=branch,\n-            )\n+            open_fun = open\n+            path = repo.cache.local.get(out.checksum)\n         else:\n-            with self.tree.open(out.path) as fd:\n+            open_fun = repo.tree.open\n+            path = out.path\n+        try:\n+\n+            with open_fun(path) as fd:\n                 metric = _read_metric(\n                     fd,\n                     typ=typ,\n@@ -242,6 +237,16 @@\n                     rel_path=out.rel_path,\n                     branch=branch,\n                 )\n+        except IOError as e:\n+            if e.errno == errno.ENOENT:\n+                logger.warning(\n+                    NO_METRICS_FILE_AT_REFERENCE_WARNING.format(\n+                        out.rel_path, branch\n+                    )\n+                )\n+                metric = None\n+            else:\n+                raise\n \n         if not metric:\n             continue\n@@ -252,7 +257,7 @@\n \n \n def show(\n-    self,\n+    repo,\n     path=None,\n     typ=None,\n     xpath=None,\n@@ -262,9 +267,9 @@\n ):\n     res = {}\n \n-    for branch in self.brancher(all_branches=all_branches, all_tags=all_tags):\n-        entries = _collect_metrics(self, path, recursive, typ, xpath, branch)\n-        metrics = _read_metrics(self, entries, branch)\n+    for branch in repo.brancher(all_branches=all_branches, all_tags=all_tags):\n+        entries = _collect_metrics(repo, path, recursive, typ, xpath, branch)\n+        metrics = _read_metrics(repo, entries, branch)\n         if metrics:\n             res[branch] = metrics\n", "issue": "\"dvc metrics show -a\" doesn't work if a metric file is missing\n> Hi everyone,\r\n\r\nI have three branches. Every branch is one experiment. One experiment should create a metric file as output. Two experiments are already finished, the third experiment is still running. So I have two experiments (= branches) with a metric file and one without.\r\n\r\nNow I want to use \"dvc metrics show -a\" to get the result from the two already finished experiments. But I got an error that the branch with the running experiment does not have a metric file.\r\n\r\nI am working with the pip installed DVC (version 0.35.7). The system is a ubuntu 18.04 and use anaconda.\r\n\r\nI got help from ruslan in the forum: https://discordapp.com/channels/485586884165107732/563406153334128681/570262271847039028\r\n\r\nthanks for the help!\r\n\r\n> cmd: python code/train.py \r\n> deps:\r\n> - path: data/toy_3dpatients_on_mrt.npy\r\n> - path: data/toy_3dpatients_on_mrt_settings.npy\r\n> - path: data/toy_3dpatients_on_mrt_test.npy\r\n> outs:\r\n> - cache: false\r\n>   metric: true\r\n>   path: metrics/test_local_False.json\r\n> - cache: true\r\n>   metric: false\r\n>   path: tensorboards/test_local_False_test\r\n> - cache: true\r\n>   metric: false\r\n>   path: tensorboards/test_local_False_train\r\n> - cache: true\r\n>   metric: false\r\n>   path: tensorflow_models/model_weights_test_local_False.h5\r\n\r\nAnd here is the output from the command `dvc metrics show -v -a`\r\n> (tf-gpu) j@t:~/Documents/gitlab/0005_3d_siamesenet$ dvc metrics show -v -a\r\n> ERROR: unexpected error - [Errno 2] No such file in branch 'test_local': 'metrics/test_local_False.json'\r\n> ------------------------------------------------------------\r\n> Traceback (most recent call last):\r\n>   File \"/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/main.py\", line 37, in main\r\n>     ret = cmd.run_cmd()\r\n>   File \"/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/command/base.py\", line 60, in run_cmd\r\n>     return self.run()\r\n>   File \"/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/command/metrics.py\", line 47, in run\r\n>     recursive=self.args.recursive,\r\n>   File \"/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/repo/metrics/init.py\", line 18, in show\r\n>     return show(self.repo, *args, **kwargs)\r\n>   File \"/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/repo/metrics/show.py\", line 263, in show\r\n>     metrics = _read_metrics(self, entries, branch)\r\n>   File \"/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/repo/metrics/show.py\", line 237, in _read_metrics\r\n>     fd = self.tree.open(out.path)\r\n>   File \"/home/j/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/dvc/scm/git/tree.py\", line 34, in open\r\n>     raise IOError(errno.ENOENT, msg, relpath)\r\n> FileNotFoundError: [Errno 2] No such file in branch 'test_local': 'metrics/test_local_False.json'\r\n\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport os\nimport csv\nimport json\nimport logging\nfrom jsonpath_ng.ext import parse\n\nfrom dvc.exceptions import OutputNotFoundError, BadMetricError, NoMetricsError\nfrom dvc.utils.compat import builtin_str, open, StringIO, csv_reader\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef _read_metric_json(fd, json_path):\n    parser = parse(json_path)\n    return [x.value for x in parser.find(json.load(fd))]\n\n\ndef _get_values(row):\n    if isinstance(row, dict):\n        return list(row.values())\n    else:\n        return row\n\n\ndef _do_read_metric_xsv(reader, row, col):\n    if col is not None and row is not None:\n        return [reader[row][col]]\n    elif col is not None:\n        return [r[col] for r in reader]\n    elif row is not None:\n        return _get_values(reader[row])\n    return [_get_values(r) for r in reader]\n\n\ndef _read_metric_hxsv(fd, hxsv_path, delimiter):\n    indices = hxsv_path.split(\",\")\n    row = indices[0]\n    row = int(row) if row else None\n    col = indices[1] if len(indices) > 1 and indices[1] else None\n    reader = list(csv.DictReader(fd, delimiter=builtin_str(delimiter)))\n    return _do_read_metric_xsv(reader, row, col)\n\n\ndef _read_metric_xsv(fd, xsv_path, delimiter):\n    indices = xsv_path.split(\",\")\n    row = indices[0]\n    row = int(row) if row else None\n    col = int(indices[1]) if len(indices) > 1 and indices[1] else None\n    reader = list(csv.reader(fd, delimiter=builtin_str(delimiter)))\n    return _do_read_metric_xsv(reader, row, col)\n\n\ndef _read_typed_metric(typ, xpath, fd):\n    if typ == \"json\":\n        ret = _read_metric_json(fd, xpath)\n    elif typ == \"csv\":\n        ret = _read_metric_xsv(fd, xpath, \",\")\n    elif typ == \"tsv\":\n        ret = _read_metric_xsv(fd, xpath, \"\\t\")\n    elif typ == \"hcsv\":\n        ret = _read_metric_hxsv(fd, xpath, \",\")\n    elif typ == \"htsv\":\n        ret = _read_metric_hxsv(fd, xpath, \"\\t\")\n    else:\n        ret = fd.read().strip()\n    return ret\n\n\ndef _format_csv(content, delimiter):\n    \"\"\"Format delimited text to have same column width.\n\n    Args:\n        content (str): The content of a metric.\n        delimiter (str): Value separator\n\n    Returns:\n        str: Formatted content.\n\n    Example:\n\n        >>> content = (\n            \"value_mse,deviation_mse,data_set\\n\"\n            \"0.421601,0.173461,train\\n\"\n            \"0.67528,0.289545,testing\\n\"\n            \"0.671502,0.297848,validation\\n\"\n        )\n        >>> _format_csv(content, \",\")\n\n        \"value_mse  deviation_mse   data_set\\n\"\n        \"0.421601   0.173461        train\\n\"\n        \"0.67528    0.289545        testing\\n\"\n        \"0.671502   0.297848        validation\\n\"\n    \"\"\"\n    reader = csv_reader(StringIO(content), delimiter=builtin_str(delimiter))\n    rows = [row for row in reader]\n    max_widths = [max(map(len, column)) for column in zip(*rows)]\n\n    lines = [\n        \" \".join(\n            \"{entry:{width}}\".format(entry=entry, width=width + 2)\n            for entry, width in zip(row, max_widths)\n        )\n        for row in rows\n    ]\n\n    return \"\\n\".join(lines)\n\n\ndef _format_output(content, typ):\n    \"\"\"Tabularize the content according to its type.\n\n    Args:\n        content (str): The content of a metric.\n        typ (str): The type of metric -- (raw|json|tsv|htsv|csv|hcsv).\n\n    Returns:\n        str: Content in a raw or tabular format.\n    \"\"\"\n\n    if \"csv\" in str(typ):\n        return _format_csv(content, delimiter=\",\")\n\n    if \"tsv\" in str(typ):\n        return _format_csv(content, delimiter=\"\\t\")\n\n    return content\n\n\ndef _read_metric(fd, typ=None, xpath=None, rel_path=None, branch=None):\n    typ = typ.lower().strip() if typ else typ\n    try:\n        if xpath:\n            return _read_typed_metric(typ, xpath.strip(), fd)\n        else:\n            return _format_output(fd.read().strip(), typ)\n    # Json path library has to be replaced or wrapped in\n    # order to fix this too broad except clause.\n    except Exception:\n        logger.exception(\n            \"unable to read metric in '{}' in branch '{}'\".format(\n                rel_path, branch\n            )\n        )\n        return None\n\n\ndef _collect_metrics(self, path, recursive, typ, xpath, branch):\n    \"\"\"Gather all the metric outputs.\n\n    Args:\n        path (str): Path to a metric file or a directory.\n        recursive (bool): If path is a directory, do a recursive search for\n            metrics on the given path.\n        typ (str): The type of metric to search for, could be one of the\n            following (raw|json|tsv|htsv|csv|hcsv).\n        xpath (str): Path to search for.\n        branch (str): Branch to look up for metrics.\n\n    Returns:\n        list(tuple): (output, typ, xpath)\n            - output:\n            - typ:\n            - xpath:\n    \"\"\"\n    outs = [out for stage in self.stages() for out in stage.outs]\n\n    if path:\n        try:\n            outs = self.find_outs_by_path(path, outs=outs, recursive=recursive)\n        except OutputNotFoundError:\n            logger.debug(\n                \"stage file not for found for '{}' in branch '{}'\".format(\n                    path, branch\n                )\n            )\n            return []\n\n    res = []\n    for o in outs:\n        if not o.metric:\n            continue\n\n        if not typ and isinstance(o.metric, dict):\n            t = o.metric.get(o.PARAM_METRIC_TYPE, typ)\n            x = o.metric.get(o.PARAM_METRIC_XPATH, xpath)\n        else:\n            t = typ\n            x = xpath\n\n        res.append((o, t, x))\n\n    return res\n\n\ndef _read_metrics_filesystem(path, typ, xpath, rel_path, branch):\n    if not os.path.exists(path):\n        return None\n    with open(path, \"r\") as fd:\n        return _read_metric(\n            fd, typ=typ, xpath=xpath, rel_path=rel_path, branch=branch\n        )\n\n\ndef _read_metrics(self, metrics, branch):\n    \"\"\"Read the content of each metric file and format it.\n\n    Args:\n        metrics (list): List of metric touples\n        branch (str): Branch to look up for metrics.\n\n    Returns:\n        A dict mapping keys with metrics path name and content.\n        For example:\n\n        {'metric.csv': (\"value_mse  deviation_mse   data_set\\n\"\n                        \"0.421601   0.173461        train\\n\"\n                        \"0.67528    0.289545        testing\\n\"\n                        \"0.671502   0.297848        validation\\n\")}\n    \"\"\"\n    res = {}\n    for out, typ, xpath in metrics:\n        assert out.scheme == \"local\"\n        if not typ:\n            typ = os.path.splitext(out.path.lower())[1].replace(\".\", \"\")\n        if out.use_cache:\n            metric = _read_metrics_filesystem(\n                self.cache.local.get(out.checksum),\n                typ=typ,\n                xpath=xpath,\n                rel_path=out.rel_path,\n                branch=branch,\n            )\n        else:\n            with self.tree.open(out.path) as fd:\n                metric = _read_metric(\n                    fd,\n                    typ=typ,\n                    xpath=xpath,\n                    rel_path=out.rel_path,\n                    branch=branch,\n                )\n\n        if not metric:\n            continue\n\n        res[out.rel_path] = metric\n\n    return res\n\n\ndef show(\n    self,\n    path=None,\n    typ=None,\n    xpath=None,\n    all_branches=False,\n    all_tags=False,\n    recursive=False,\n):\n    res = {}\n\n    for branch in self.brancher(all_branches=all_branches, all_tags=all_tags):\n        entries = _collect_metrics(self, path, recursive, typ, xpath, branch)\n        metrics = _read_metrics(self, entries, branch)\n        if metrics:\n            res[branch] = metrics\n\n    if not res:\n        if path:\n            raise BadMetricError(path)\n        raise NoMetricsError()\n\n    return res\n", "path": "dvc/repo/metrics/show.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport errno\nimport os\nimport csv\nimport json\nimport logging\n\nfrom jsonpath_ng.ext import parse\n\nfrom dvc.exceptions import OutputNotFoundError, BadMetricError, NoMetricsError\nfrom dvc.utils.compat import builtin_str, open, StringIO, csv_reader\n\nNO_METRICS_FILE_AT_REFERENCE_WARNING = (\n    \"Metrics file '{}' does not exist at reference: '{}'\"\n)\n\nlogger = logging.getLogger(__name__)\n\n\ndef _read_metric_json(fd, json_path):\n    parser = parse(json_path)\n    return [x.value for x in parser.find(json.load(fd))]\n\n\ndef _get_values(row):\n    if isinstance(row, dict):\n        return list(row.values())\n    else:\n        return row\n\n\ndef _do_read_metric_xsv(reader, row, col):\n    if col is not None and row is not None:\n        return [reader[row][col]]\n    elif col is not None:\n        return [r[col] for r in reader]\n    elif row is not None:\n        return _get_values(reader[row])\n    return [_get_values(r) for r in reader]\n\n\ndef _read_metric_hxsv(fd, hxsv_path, delimiter):\n    indices = hxsv_path.split(\",\")\n    row = indices[0]\n    row = int(row) if row else None\n    col = indices[1] if len(indices) > 1 and indices[1] else None\n    reader = list(csv.DictReader(fd, delimiter=builtin_str(delimiter)))\n    return _do_read_metric_xsv(reader, row, col)\n\n\ndef _read_metric_xsv(fd, xsv_path, delimiter):\n    indices = xsv_path.split(\",\")\n    row = indices[0]\n    row = int(row) if row else None\n    col = int(indices[1]) if len(indices) > 1 and indices[1] else None\n    reader = list(csv.reader(fd, delimiter=builtin_str(delimiter)))\n    return _do_read_metric_xsv(reader, row, col)\n\n\ndef _read_typed_metric(typ, xpath, fd):\n    if typ == \"json\":\n        ret = _read_metric_json(fd, xpath)\n    elif typ == \"csv\":\n        ret = _read_metric_xsv(fd, xpath, \",\")\n    elif typ == \"tsv\":\n        ret = _read_metric_xsv(fd, xpath, \"\\t\")\n    elif typ == \"hcsv\":\n        ret = _read_metric_hxsv(fd, xpath, \",\")\n    elif typ == \"htsv\":\n        ret = _read_metric_hxsv(fd, xpath, \"\\t\")\n    else:\n        ret = fd.read().strip()\n    return ret\n\n\ndef _format_csv(content, delimiter):\n    \"\"\"Format delimited text to have same column width.\n\n    Args:\n        content (str): The content of a metric.\n        delimiter (str): Value separator\n\n    Returns:\n        str: Formatted content.\n\n    Example:\n\n        >>> content = (\n            \"value_mse,deviation_mse,data_set\\n\"\n            \"0.421601,0.173461,train\\n\"\n            \"0.67528,0.289545,testing\\n\"\n            \"0.671502,0.297848,validation\\n\"\n        )\n        >>> _format_csv(content, \",\")\n\n        \"value_mse  deviation_mse   data_set\\n\"\n        \"0.421601   0.173461        train\\n\"\n        \"0.67528    0.289545        testing\\n\"\n        \"0.671502   0.297848        validation\\n\"\n    \"\"\"\n    reader = csv_reader(StringIO(content), delimiter=builtin_str(delimiter))\n    rows = [row for row in reader]\n    max_widths = [max(map(len, column)) for column in zip(*rows)]\n\n    lines = [\n        \" \".join(\n            \"{entry:{width}}\".format(entry=entry, width=width + 2)\n            for entry, width in zip(row, max_widths)\n        )\n        for row in rows\n    ]\n\n    return \"\\n\".join(lines)\n\n\ndef _format_output(content, typ):\n    \"\"\"Tabularize the content according to its type.\n\n    Args:\n        content (str): The content of a metric.\n        typ (str): The type of metric -- (raw|json|tsv|htsv|csv|hcsv).\n\n    Returns:\n        str: Content in a raw or tabular format.\n    \"\"\"\n\n    if \"csv\" in str(typ):\n        return _format_csv(content, delimiter=\",\")\n\n    if \"tsv\" in str(typ):\n        return _format_csv(content, delimiter=\"\\t\")\n\n    return content\n\n\ndef _read_metric(fd, typ=None, xpath=None, rel_path=None, branch=None):\n    typ = typ.lower().strip() if typ else typ\n    try:\n        if xpath:\n            return _read_typed_metric(typ, xpath.strip(), fd)\n        else:\n            return _format_output(fd.read().strip(), typ)\n    # Json path library has to be replaced or wrapped in\n    # order to fix this too broad except clause.\n    except Exception:\n        logger.exception(\n            \"unable to read metric in '{}' in branch '{}'\".format(\n                rel_path, branch\n            )\n        )\n        return None\n\n\ndef _collect_metrics(repo, path, recursive, typ, xpath, branch):\n    \"\"\"Gather all the metric outputs.\n\n    Args:\n        path (str): Path to a metric file or a directory.\n        recursive (bool): If path is a directory, do a recursive search for\n            metrics on the given path.\n        typ (str): The type of metric to search for, could be one of the\n            following (raw|json|tsv|htsv|csv|hcsv).\n        xpath (str): Path to search for.\n        branch (str): Branch to look up for metrics.\n\n    Returns:\n        list(tuple): (output, typ, xpath)\n            - output:\n            - typ:\n            - xpath:\n    \"\"\"\n    outs = [out for stage in repo.stages() for out in stage.outs]\n\n    if path:\n        try:\n            outs = repo.find_outs_by_path(path, outs=outs, recursive=recursive)\n        except OutputNotFoundError:\n            logger.debug(\n                \"stage file not for found for '{}' in branch '{}'\".format(\n                    path, branch\n                )\n            )\n            return []\n\n    res = []\n    for o in outs:\n        if not o.metric:\n            continue\n\n        if not typ and isinstance(o.metric, dict):\n            t = o.metric.get(o.PARAM_METRIC_TYPE, typ)\n            x = o.metric.get(o.PARAM_METRIC_XPATH, xpath)\n        else:\n            t = typ\n            x = xpath\n\n        res.append((o, t, x))\n\n    return res\n\n\ndef _read_metrics(repo, metrics, branch):\n    \"\"\"Read the content of each metric file and format it.\n\n    Args:\n        metrics (list): List of metric touples\n        branch (str): Branch to look up for metrics.\n\n    Returns:\n        A dict mapping keys with metrics path name and content.\n        For example:\n\n        {'metric.csv': (\"value_mse  deviation_mse   data_set\\n\"\n                        \"0.421601   0.173461        train\\n\"\n                        \"0.67528    0.289545        testing\\n\"\n                        \"0.671502   0.297848        validation\\n\")}\n    \"\"\"\n    res = {}\n    for out, typ, xpath in metrics:\n        assert out.scheme == \"local\"\n        if not typ:\n            typ = os.path.splitext(out.path.lower())[1].replace(\".\", \"\")\n        if out.use_cache:\n            open_fun = open\n            path = repo.cache.local.get(out.checksum)\n        else:\n            open_fun = repo.tree.open\n            path = out.path\n        try:\n\n            with open_fun(path) as fd:\n                metric = _read_metric(\n                    fd,\n                    typ=typ,\n                    xpath=xpath,\n                    rel_path=out.rel_path,\n                    branch=branch,\n                )\n        except IOError as e:\n            if e.errno == errno.ENOENT:\n                logger.warning(\n                    NO_METRICS_FILE_AT_REFERENCE_WARNING.format(\n                        out.rel_path, branch\n                    )\n                )\n                metric = None\n            else:\n                raise\n\n        if not metric:\n            continue\n\n        res[out.rel_path] = metric\n\n    return res\n\n\ndef show(\n    repo,\n    path=None,\n    typ=None,\n    xpath=None,\n    all_branches=False,\n    all_tags=False,\n    recursive=False,\n):\n    res = {}\n\n    for branch in repo.brancher(all_branches=all_branches, all_tags=all_tags):\n        entries = _collect_metrics(repo, path, recursive, typ, xpath, branch)\n        metrics = _read_metrics(repo, entries, branch)\n        if metrics:\n            res[branch] = metrics\n\n    if not res:\n        if path:\n            raise BadMetricError(path)\n        raise NoMetricsError()\n\n    return res\n", "path": "dvc/repo/metrics/show.py"}]}