diff --git a/dvc/git_wrapper.py b/dvc/git_wrapper.py index 9bbb0e2ba..f7c886bc1 100644 --- a/dvc/git_wrapper.py +++ b/dvc/git_wrapper.py @@ -2,6 +2,7 @@ import os import re from collections import defaultdict +from dvc.exceptions import DvcException from dvc.logger import Logger from dvc.config import Config from dvc.executor import Executor, ExecutorError @@ -11,6 +12,11 @@ from dvc.graph.workflow import Workflow from dvc.graph.commit import Commit +class GitWrapperError(DvcException): + def __init__(self, msg): + DvcException.__init__(self, msg) + + class GitWrapperI(object): COMMIT_LEN = 7 @@ -325,21 +331,33 @@ class GitWrapper(GitWrapperI): if not os.path.exists(full_file_name): return None - lines = open(full_file_name).readlines(2) - if len(lines) != 1: - msg = '[dvc-git] Target file {} with hash {} has wrong format: {} lines were obtained, 1 expected.' - Logger.warn(msg.format(target, hash, len(lines))) + try: + return self.parse_target_metric(full_file_name) + except GitWrapperError as ex: + msg = '[dvc-git] Unable to parse target file {} from Git commit {}: {}' + Logger.warn(msg.format(target, hash, ex)) return None + @staticmethod + def parse_target_metric(file_name): + lines = open(file_name).readlines(2) + if len(lines) != 1: + raise GitWrapperError('file contains more then one line') + # Extract float from string. I.e. from 'AUC: 0.596182' - nums = self.FLOATS_FROM_STRING.findall(lines[0]) + nums = GitWrapper.FLOATS_FROM_STRING.findall(lines[0]) if len(nums) < 1: - msg = '[dvc-git] Unable to parse metrics from \'{}\' file {}' - Logger.warn(msg.format(lines[0], target)) - return None + raise GitWrapperError("Unable to parse metrics from the first line") return float(nums[0]) + @staticmethod + def try_parse_target_metric(file_name): + try: + return GitWrapper.parse_target_metric(file_name) + except GitWrapperError: + return None + @staticmethod def get_merges_map(): # git log --merges --all --abbrev=7 diff --git a/dvc/state_file.py b/dvc/state_file.py index b474dac4b..53fa24526 100644 --- a/dvc/state_file.py +++ b/dvc/state_file.py @@ -5,6 +5,7 @@ import json import time from dvc.exceptions import DvcException +from dvc.git_wrapper import GitWrapper from dvc.path.data_item import NotInDataDirError from dvc.system import System @@ -39,6 +40,8 @@ class StateFile(object): PARAM_STDOUT = "Stdout" PARAM_STDERR = "Stderr" PARAM_SHELL = "Shell" + PARAM_TARGET_METRICS = 'target_metrics' + TARGET_METRICS_SINGLE_METRIC = 'single_metric' def __init__(self, command, @@ -55,7 +58,7 @@ class StateFile(object): cwd=None, shell=False): self.data_item = data_item - self.file = data_item.state.relative + self.file = self.data_item.state.relative self.settings = settings self.input_files = input_files self.output_files = output_files @@ -78,7 +81,12 @@ class StateFile(object): self.cwd = cwd else: self.cwd = self.get_dvc_path() - pass + + self.target_metrics = {} + + target_metric = GitWrapper.try_parse_target_metric(self.data_item.data.relative) + if target_metric: + self.target_metrics[StateFile.TARGET_METRICS_SINGLE_METRIC] = target_metric @property def is_import_file(self): @@ -158,6 +166,7 @@ class StateFile(object): self.PARAM_STDOUT: self.encode_path(self.stdout), self.PARAM_STDERR: self.encode_path(self.stderr), self.PARAM_SHELL: self.shell, + self.PARAM_TARGET_METRICS: self.target_metrics } if self.locked: