mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-05 23:09:32 +01:00
dvc: add dvc metrics
Fixes #592 Signed-off-by: Ruslan Kuprieiev <[email protected]>
This commit is contained in:
+19
@@ -17,6 +17,7 @@ from dvc.command.add import CmdAdd
|
||||
from dvc.command.config import CmdConfig
|
||||
from dvc.command.checkout import CmdCheckout
|
||||
from dvc.command.remote import CmdRemoteAdd, CmdRemoteRemove, CmdRemoteModify
|
||||
from dvc.command.metrics import CmdMetrics
|
||||
from dvc.stage import Stage
|
||||
from dvc import VERSION
|
||||
|
||||
@@ -321,6 +322,24 @@ def parse_args(argv=None):
|
||||
help='Use local config')
|
||||
remote_modify_parser.set_defaults(func=CmdRemoteModify)
|
||||
|
||||
# Metrics
|
||||
metrics_parser = subparsers.add_parser(
|
||||
'metrics',
|
||||
parents=[parent_parser],
|
||||
help='Get metrics from all branches')
|
||||
metrics_parser.add_argument(
|
||||
'path',
|
||||
help='Path to metrics file')
|
||||
metrics_parser.add_argument(
|
||||
'--json-path',
|
||||
help='JSON path')
|
||||
metrics_parser.add_argument(
|
||||
'--tsv-path',
|
||||
help='TSV path \'row,column\'(e.g. \'1,2\')')
|
||||
metrics_parser.add_argument(
|
||||
'--htsv-path',
|
||||
help='Headed TSV path \'row,column\'(e.g. \'Name,3\'')
|
||||
metrics_parser.set_defaults(func=CmdMetrics)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ from dvc.command.common.base import CmdBase
|
||||
|
||||
class CmdMetrics(CmdBase):
|
||||
def run(self):
|
||||
for branch, metric in self.project.metrics(self.args.path).items():
|
||||
for branch, metric in self.project.metrics(self.args.path,
|
||||
json_path=self.args.json_path,
|
||||
tsv_path=self.args.tsv_path,
|
||||
htsv_path=self.args.htsv_path).items():
|
||||
self.project.logger.info("{}: {}".format(branch, metric))
|
||||
return 0
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import os
|
||||
import csv
|
||||
import stat
|
||||
import json
|
||||
import networkx as nx
|
||||
from jsonpath_rw import parse
|
||||
|
||||
import dvc.cloud.base as cloud
|
||||
|
||||
@@ -258,6 +261,61 @@ class Project(object):
|
||||
return self._cloud_status(target, jobs, remote=remote)
|
||||
return self._local_status(target)
|
||||
|
||||
def _read_metric_json(self, fd, json_path):
|
||||
parser = parse(json_path)
|
||||
return [x.value for x in parser.find(json.load(fd))]
|
||||
|
||||
def _do_read_metric_tsv(self, reader, row, col):
|
||||
if col != None and row != None:
|
||||
return [reader[row][col]]
|
||||
elif col != None:
|
||||
return [r[col] for r in reader]
|
||||
elif row != None:
|
||||
return reader[row]
|
||||
return None
|
||||
|
||||
def _read_metric_htsv(self, fd, htsv_path):
|
||||
col, row = htsv_path.split(',')
|
||||
row = int(row)
|
||||
reader = list(csv.DictReader(fd, delimiter='\t'))
|
||||
return self._do_read_metric_tsv(reader, row, col)
|
||||
|
||||
def _read_metric_tsv(self, fd, tsv_path):
|
||||
col, row = tsv_path.split(',')
|
||||
row = int(row)
|
||||
col = int(col)
|
||||
reader = list(csv.reader(fd, delimiter='\t'))
|
||||
return self._do_read_metric_tsv(reader, row, col)
|
||||
|
||||
def _read_metric(self, path, json_path=None, tsv_path=None, htsv_path=None):
|
||||
ret = None
|
||||
try:
|
||||
with open(path, 'r') as fd:
|
||||
if json_path:
|
||||
ret = self._read_metric_json(fd, json_path)
|
||||
elif tsv_path:
|
||||
ret = self._read_metric_tsv(fd, tsv_path)
|
||||
elif htsv_path:
|
||||
ret = self._read_metric_htsv(fd, htsv_path)
|
||||
else:
|
||||
ret = fd.read()
|
||||
except Exception as exc:
|
||||
self.logger.error('Unable to read metric in \'{}\''.format(path), exc)
|
||||
|
||||
return ret
|
||||
|
||||
def metrics(self, path, json_path=None, tsv_path=None, htsv_path=None):
|
||||
res = {}
|
||||
saved = self.scm.active_branch()
|
||||
for branch in self.scm.list_branches():
|
||||
self.scm.checkout(branch)
|
||||
res[branch] = self._read_metric(path,
|
||||
json_path=json_path,
|
||||
tsv_path=tsv_path,
|
||||
htsv_path=htsv_path)
|
||||
self.scm.checkout(saved)
|
||||
return res
|
||||
|
||||
def graph(self):
|
||||
G = nx.DiGraph()
|
||||
|
||||
|
||||
+12
@@ -49,6 +49,12 @@ class Base(object):
|
||||
def is_tracked(self, path):
|
||||
pass
|
||||
|
||||
def active_branch(self):
|
||||
pass
|
||||
|
||||
def list_branches(self):
|
||||
pass
|
||||
|
||||
|
||||
class Git(Base):
|
||||
GITIGNORE = '.gitignore'
|
||||
@@ -133,6 +139,12 @@ class Git(Base):
|
||||
def is_tracked(self, path):
|
||||
return len(self.repo.git.ls_files(path)) != 0
|
||||
|
||||
def active_branch(self):
|
||||
return self.repo.active_branch.name
|
||||
|
||||
def list_branches(self):
|
||||
return [h.name for h in self.repo.heads]
|
||||
|
||||
|
||||
def SCM(root_dir=os.curdir, no_scm=False):
|
||||
if Git.is_repo(root_dir):
|
||||
|
||||
@@ -17,3 +17,4 @@ pyasn1>=0.4.1
|
||||
schema>=0.6.7
|
||||
paramiko>=2.4.1
|
||||
binaryornot==0.4.4
|
||||
jsonpath-rw==1.4.0
|
||||
|
||||
@@ -23,6 +23,7 @@ install_requires = [
|
||||
"schema>=0.6.7",
|
||||
"paramiko>=2.4.1",
|
||||
"binaryornot==0.4.4",
|
||||
"jsonpath-rw==1.4.0",
|
||||
]
|
||||
|
||||
setup(
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
from dvc.main import main
|
||||
from tests.basic_env import TestDvc
|
||||
|
||||
class TestMetrics(TestDvc):
|
||||
def setUp(self):
|
||||
super(TestMetrics, self).setUp()
|
||||
for branch in ['foo', 'bar', 'baz']:
|
||||
self.dvc.scm.checkout(branch, create_new=True)
|
||||
|
||||
with open('metric', 'w+') as fd:
|
||||
fd.write(branch)
|
||||
|
||||
with open('metric_json', 'w+') as fd:
|
||||
json.dump({'branch': branch}, fd)
|
||||
|
||||
with open('metric_tsv', 'w+') as fd:
|
||||
fd.write(branch)
|
||||
|
||||
with open('metric_htsv', 'w+') as fd:
|
||||
fd.write('branch\n')
|
||||
fd.write(branch)
|
||||
|
||||
self.dvc.scm.add(['metric', 'metric_json', 'metric_tsv', 'metric_htsv'])
|
||||
self.dvc.scm.commit('metric')
|
||||
|
||||
self.dvc.scm.checkout('master')
|
||||
|
||||
def test(self):
|
||||
ret = self.dvc.metrics('metric')
|
||||
self.assertEqual(len(ret), 4)
|
||||
self.assertTrue(ret['master'] == None)
|
||||
self.assertTrue(ret['foo'] == 'foo')
|
||||
self.assertTrue(ret['bar'] == 'bar')
|
||||
self.assertTrue(ret['baz'] == 'baz')
|
||||
|
||||
ret = self.dvc.metrics('metric_json', json_path='branch')
|
||||
self.assertEqual(len(ret), 4)
|
||||
self.assertTrue(ret['master'] == None)
|
||||
self.assertTrue(ret['foo'] == ['foo'])
|
||||
self.assertTrue(ret['bar'] == ['bar'])
|
||||
self.assertTrue(ret['baz'] == ['baz'])
|
||||
|
||||
ret = self.dvc.metrics('metric_tsv', tsv_path='0,0')
|
||||
self.assertEqual(len(ret), 4)
|
||||
self.assertTrue(ret['master'] == None)
|
||||
self.assertTrue(ret['foo'] == ['foo'])
|
||||
self.assertTrue(ret['bar'] == ['bar'])
|
||||
self.assertTrue(ret['baz'] == ['baz'])
|
||||
|
||||
ret = self.dvc.metrics('metric_htsv', htsv_path='branch,0')
|
||||
self.assertEqual(len(ret), 4)
|
||||
self.assertTrue(ret['master'] == None)
|
||||
self.assertTrue(ret['foo'] == ['foo'])
|
||||
self.assertTrue(ret['bar'] == ['bar'])
|
||||
self.assertTrue(ret['baz'] == ['baz'])
|
||||
|
||||
def test_cli(self):
|
||||
#FIXME check output
|
||||
ret = main(['metrics', 'metric'])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
ret = main(['metrics', 'metric_json', '--json-path', 'branch'])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
ret = main(['metrics', 'metric_tsv', '--tsv-path', '0,0'])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
ret = main(['metrics', 'metric_htsv', '--htsv-path', 'branch,0'])
|
||||
self.assertEqual(ret, 0)
|
||||
Reference in New Issue
Block a user