mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-11 07:18:28 +01:00
metrics: properly handle explicitly specified file
Related to #865 Signed-off-by: Ruslan Kuprieiev <[email protected]>
This commit is contained in:
committed by
Ruslan Kuprieiev
parent
4bbbdb334c
commit
9e576cd55b
+13
-2
@@ -14,6 +14,17 @@ class DvcException(Exception):
|
||||
|
||||
|
||||
class UnsupportedRemoteError(DvcException):
|
||||
def __init__(self, config, cause=None):
|
||||
def __init__(self, config):
|
||||
msg = "Remote '{}' is not supported.".format(config)
|
||||
super(UnsupportedRemoteError, self).__init__(msg, cause=cause)
|
||||
super(UnsupportedRemoteError, self).__init__(msg)
|
||||
|
||||
|
||||
class OutputDuplicationError(DvcException):
|
||||
def __init__(self, output, stages):
|
||||
assert isinstance(output, str)
|
||||
assert isinstance(stages, list)
|
||||
assert all(isinstance(stage, str) for stage in stages)
|
||||
msg = "File '{}' is specified as an output in more than one stage: {}"
|
||||
super(OutputDuplicationError, self).__init__(msg.format(output,
|
||||
str(stages)))
|
||||
|
||||
|
||||
+43
-25
@@ -455,6 +455,21 @@ class Project(object):
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _find_output_by_path(self, path, outs=None):
|
||||
from dvc.exceptions import OutputDuplicationError
|
||||
|
||||
if not outs:
|
||||
outs = [out for stage in self.active_stages() 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.path for out in matched]
|
||||
if len(stages) > 1:
|
||||
raise OutputDuplicationError(path, stages)
|
||||
|
||||
return matched[0] if matched else None
|
||||
|
||||
def metrics_show(self, path=None, json_path=None,
|
||||
tsv_path=None,
|
||||
htsv_path=None,
|
||||
@@ -464,9 +479,20 @@ class Project(object):
|
||||
res = {}
|
||||
for branch in self.scm.brancher(all_branches=all_branches):
|
||||
outs = [out for stage in self.active_stages() for out in stage.outs]
|
||||
metrics = filter(lambda o: o.metric, outs)
|
||||
fnames = [path] if path else map(lambda o: o.path, metrics)
|
||||
|
||||
if path:
|
||||
out = self._find_output_by_path(path, outs=outs)
|
||||
stage = out.stage.path if out else None
|
||||
fnames = [path]
|
||||
else:
|
||||
metrics = filter(lambda o: o.metric, outs)
|
||||
stage = None
|
||||
fnames = map(lambda o: o.path, metrics)
|
||||
|
||||
for fname in fnames:
|
||||
if stage:
|
||||
self.checkout(stage)
|
||||
|
||||
rel = os.path.relpath(fname)
|
||||
metric = self._read_metric(fname,
|
||||
json_path=json_path,
|
||||
@@ -491,7 +517,6 @@ class Project(object):
|
||||
if res:
|
||||
return res
|
||||
|
||||
|
||||
if path:
|
||||
msg = 'File \'{}\' does not exist'.format(path)
|
||||
else:
|
||||
@@ -500,32 +525,25 @@ class Project(object):
|
||||
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']))
|
||||
|
||||
if out.use_cache:
|
||||
msg = 'Cached output \'{}\' is not supported for metrics'
|
||||
raise DvcException(msg.format(out.rel_path))
|
||||
|
||||
out.metric = val
|
||||
out._verify_metric()
|
||||
|
||||
stage.dump()
|
||||
|
||||
if not found:
|
||||
out = self._find_output_by_path(path)
|
||||
if not out:
|
||||
msg = 'Unable to find file \'{}\' in the pipeline'.format(path)
|
||||
raise DvcException(msg)
|
||||
|
||||
if out.path_info['scheme'] != 'local':
|
||||
msg = 'Output \'{}\' scheme \'{}\' is not supported for metrics'
|
||||
raise DvcException(msg.format(out.path, out.path_info['scheme']))
|
||||
|
||||
if out.use_cache:
|
||||
msg = 'Cached output \'{}\' is not supported for metrics'
|
||||
raise DvcException(msg.format(out.rel_path))
|
||||
|
||||
out.metric = val
|
||||
out._verify_metric()
|
||||
|
||||
out.stage.dump()
|
||||
|
||||
def metrics_add(self, path):
|
||||
self._metrics_modify(path, True)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
from dvc.project import Project
|
||||
from dvc.main import main
|
||||
from dvc.exceptions import DvcException
|
||||
from tests.basic_env import TestDvc
|
||||
@@ -159,3 +160,38 @@ class TestNoMetrics(TestDvc):
|
||||
def test(self):
|
||||
ret = main(['metrics', 'show'])
|
||||
self.assertNotEqual(ret, 0)
|
||||
|
||||
|
||||
class TestCachedMetrics(TestDvc):
|
||||
def _do_write(self, branch):
|
||||
self.dvc.scm.checkout(branch)
|
||||
self.dvc.checkout()
|
||||
|
||||
with open('metrics.json', 'w+') as fd:
|
||||
json.dump({'metrics': branch}, fd)
|
||||
|
||||
stage = self.dvc.add('metrics.json')
|
||||
self.assertNotEqual(stage, None)
|
||||
|
||||
self.dvc.scm.add(['.gitignore', 'metrics.json.dvc'])
|
||||
self.dvc.scm.commit(branch)
|
||||
|
||||
def test(self):
|
||||
self.dvc.scm.commit('init')
|
||||
|
||||
self.dvc.scm.branch('one')
|
||||
self.dvc.scm.branch('two')
|
||||
|
||||
self._do_write('master')
|
||||
self._do_write('one')
|
||||
self._do_write('two')
|
||||
|
||||
self.dvc = Project('.')
|
||||
|
||||
res = self.dvc.metrics_show('metrics.json',
|
||||
all_branches=True,
|
||||
json_path='metrics')
|
||||
|
||||
self.assertEqual(res, {"master": {"metrics.json": ["master"]},
|
||||
"one": {"metrics.json": ["one"]},
|
||||
"two": {"metrics.json": ["two"]}})
|
||||
|
||||
Reference in New Issue
Block a user