mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-04 07:18:27 +01:00
Implement -R option for dvc metrics show (#1543)
This commit is contained in:
committed by
Ruslan Kuprieiev
parent
413b938160
commit
70a16b2dec
+11
-1
@@ -34,6 +34,7 @@ class CmdMetricsShow(CmdBase):
|
||||
xpath=xpath,
|
||||
all_branches=self.args.all_branches,
|
||||
all_tags=self.args.all_tags,
|
||||
recursive=self.args.recursive,
|
||||
)
|
||||
except DvcException:
|
||||
logger.error("failed to show metrics")
|
||||
@@ -98,7 +99,9 @@ def add_parser(subparsers, parent_parser):
|
||||
description=METRICS_SHOW_HELP,
|
||||
help=METRICS_SHOW_HELP,
|
||||
)
|
||||
metrics_show_parser.add_argument("path", nargs="?", help="Path to metrics file.")
|
||||
metrics_show_parser.add_argument(
|
||||
"path", nargs="?", help="Path to metrics file or directory"
|
||||
)
|
||||
metrics_show_parser.add_argument(
|
||||
"-t", "--type", help="Type of metrics(RAW/JSON/TSV/HTSV/CSV/HCSV)."
|
||||
)
|
||||
@@ -133,6 +136,13 @@ def add_parser(subparsers, parent_parser):
|
||||
default=False,
|
||||
help="Show metrics for all tags.",
|
||||
)
|
||||
metrics_show_parser.add_argument(
|
||||
"-R",
|
||||
"--recursive",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="If path is a directory, recursively search and process metric files in path.",
|
||||
)
|
||||
metrics_show_parser.set_defaults(func=CmdMetricsShow)
|
||||
|
||||
METRICS_ADD_HELP = "Add metrics."
|
||||
|
||||
+64
-24
@@ -1020,13 +1020,13 @@ class Project(object):
|
||||
elif typ == "htsv":
|
||||
ret = self._read_metric_hxsv(fd, xpath, "\t")
|
||||
else:
|
||||
ret = fd.read()
|
||||
ret = fd.read().strip()
|
||||
except Exception:
|
||||
logger.error("unable to read metric in '{}'".format(path))
|
||||
|
||||
return ret
|
||||
|
||||
def _find_output_by_path(self, path, outs=None):
|
||||
def _find_output_by_path(self, path, outs=None, recursive=False):
|
||||
from dvc.exceptions import OutputDuplicationError
|
||||
|
||||
if not outs:
|
||||
@@ -1034,37 +1034,62 @@ class Project(object):
|
||||
outs = [out for stage in astages for out in stage.outs]
|
||||
|
||||
abs_path = os.path.abspath(path)
|
||||
matched = [out for out in outs if out.path == abs_path]
|
||||
stages = [out.stage.relpath for out in matched]
|
||||
if len(stages) > 1:
|
||||
raise OutputDuplicationError(path, stages)
|
||||
if os.path.isdir(abs_path) and recursive:
|
||||
matched = [
|
||||
out for out in outs if os.path.abspath(out.path).startswith(abs_path)
|
||||
]
|
||||
else:
|
||||
matched = [out for out in outs if out.path == abs_path]
|
||||
stages = [out.stage.relpath for out in matched]
|
||||
if len(stages) > 1:
|
||||
raise OutputDuplicationError(path, stages)
|
||||
|
||||
return matched[0] if matched else None
|
||||
return matched if matched else []
|
||||
|
||||
def metrics_show(
|
||||
self, path=None, typ=None, xpath=None, all_branches=False, all_tags=False
|
||||
self,
|
||||
path=None,
|
||||
typ=None,
|
||||
xpath=None,
|
||||
all_branches=False,
|
||||
all_tags=False,
|
||||
recursive=False,
|
||||
):
|
||||
res = {}
|
||||
for branch in self.scm.brancher(all_branches=all_branches, all_tags=all_tags):
|
||||
|
||||
astages = self.active_stages()
|
||||
outs = [out for stage in astages for out in stage.outs]
|
||||
|
||||
if path:
|
||||
out = self._find_output_by_path(path, outs=outs)
|
||||
stage = out.stage.path if out else None
|
||||
if out and all([out.metric, not typ, isinstance(out.metric, dict)]):
|
||||
entries = [
|
||||
(
|
||||
path,
|
||||
out.metric.get(out.PARAM_METRIC_TYPE, None),
|
||||
out.metric.get(out.PARAM_METRIC_XPATH, None),
|
||||
outs = self._find_output_by_path(path, outs=outs, recursive=recursive)
|
||||
stages = [out.stage.path for out in outs]
|
||||
entries = []
|
||||
for out in outs:
|
||||
if all([out.metric, not typ, isinstance(out.metric, dict)]):
|
||||
entries += [
|
||||
(
|
||||
out.path,
|
||||
out.metric.get(out.PARAM_METRIC_TYPE, None),
|
||||
out.metric.get(out.PARAM_METRIC_XPATH, None),
|
||||
)
|
||||
]
|
||||
else:
|
||||
entries += [(out.path, typ, xpath)]
|
||||
if not entries:
|
||||
if os.path.isdir(path):
|
||||
logger.warning(
|
||||
"Path '{path}' is a directory. "
|
||||
"Consider runnig with '-R'.".format(path=path)
|
||||
)
|
||||
]
|
||||
else:
|
||||
entries = [(path, typ, xpath)]
|
||||
return {}
|
||||
|
||||
else:
|
||||
entries += [(path, typ, xpath)]
|
||||
|
||||
else:
|
||||
metrics = filter(lambda o: o.metric, outs)
|
||||
stage = None
|
||||
stages = None
|
||||
entries = []
|
||||
for o in metrics:
|
||||
if not typ and isinstance(o.metric, dict):
|
||||
@@ -1076,8 +1101,9 @@ class Project(object):
|
||||
entries.append((o.path, t, x))
|
||||
|
||||
for fname, t, x in entries:
|
||||
if stage:
|
||||
self.checkout(stage, force=True)
|
||||
if stages:
|
||||
for stage in stages:
|
||||
self.checkout(stage, force=True)
|
||||
|
||||
rel = os.path.relpath(fname)
|
||||
metric = self._read_metric(fname, typ=t, xpath=x)
|
||||
@@ -1098,6 +1124,10 @@ class Project(object):
|
||||
if res:
|
||||
return res
|
||||
|
||||
if path and os.path.isdir(path):
|
||||
msg = "file '{}' does not exist".format(path)
|
||||
return res
|
||||
|
||||
if path:
|
||||
msg = "file '{}' does not exist".format(path)
|
||||
else:
|
||||
@@ -1109,11 +1139,21 @@ class Project(object):
|
||||
raise DvcException(msg)
|
||||
|
||||
def _metrics_modify(self, path, typ=None, xpath=None, delete=False):
|
||||
out = self._find_output_by_path(path)
|
||||
if not out:
|
||||
outs = self._find_output_by_path(path)
|
||||
|
||||
if not outs:
|
||||
msg = "unable to find file '{}' in the pipeline".format(path)
|
||||
raise DvcException(msg)
|
||||
|
||||
if len(outs) != 1:
|
||||
msg = (
|
||||
"-R not yet supported for metrics modify. "
|
||||
"Make sure only one metric is referred to by '{}'".format(path)
|
||||
)
|
||||
raise DvcException(msg)
|
||||
|
||||
out = outs[0]
|
||||
|
||||
if out.scheme != "local":
|
||||
msg = "output '{}' scheme '{}' is not supported for metrics"
|
||||
raise DvcException(msg.format(out.path, out.path_info["scheme"]))
|
||||
|
||||
@@ -97,6 +97,65 @@ class TestMetrics(TestDvc):
|
||||
self.assertTrue(ret["baz"]["metric_hcsv"] == ["baz"])
|
||||
|
||||
|
||||
class TestMetricsRecursive(TestDvc):
|
||||
def setUp(self):
|
||||
super(TestMetricsRecursive, self).setUp()
|
||||
self.dvc.scm.commit("init")
|
||||
|
||||
self.dvc.scm.checkout("nested", create_new=True)
|
||||
|
||||
os.mkdir("nested")
|
||||
os.mkdir(os.path.join("nested", "subnested"))
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-M",
|
||||
os.path.join("nested", "metric_nested"),
|
||||
"echo",
|
||||
"nested",
|
||||
">>",
|
||||
os.path.join("nested", "metric_nested"),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
ret = main(
|
||||
[
|
||||
"run",
|
||||
"-M",
|
||||
os.path.join("nested", "subnested", "metric_subnested"),
|
||||
"echo",
|
||||
"subnested",
|
||||
">>",
|
||||
os.path.join("nested", "subnested", "metric_subnested"),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
self.dvc.scm.add(["nested"])
|
||||
self.dvc.scm.commit("nested metrics")
|
||||
|
||||
self.dvc.scm.checkout("master")
|
||||
|
||||
def test(self):
|
||||
|
||||
ret = self.dvc.metrics_show("nested", all_branches=True, recursive=False)
|
||||
self.assertEqual(len(ret), 0)
|
||||
|
||||
ret = self.dvc.metrics_show("nested", all_branches=True, recursive=True)
|
||||
self.assertEqual(len(ret), 1)
|
||||
self.assertEqual(
|
||||
ret["nested"][os.path.join("nested", "subnested", "metric_subnested")],
|
||||
"subnested",
|
||||
)
|
||||
self.assertEqual(
|
||||
ret["nested"][os.path.join("nested", "metric_nested")], "nested"
|
||||
)
|
||||
|
||||
|
||||
class TestMetricsReproCLI(TestDvc):
|
||||
def test(self):
|
||||
stage = self.dvc.run(
|
||||
|
||||
Reference in New Issue
Block a user