Coverage for python/lsst/verify/bin/inspectjob.py: 15%

45 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-08-19 12:27 -0700

1# This file is part of verify. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21"""Print the measurements and metadata in lsst.verify JSON files. 

22 

23This script takes as arguments one or more lsst.verify JSON files, and prints 

24the top-level metadata and a summary of any measurements. 

25 

26This script does not print information about metrics or specifications. 

27""" 

28 

29__all__ = ["main", "inspect_job"] 

30 

31import argparse 

32import json 

33 

34from lsst.verify import Job 

35 

36 

37def _is_measurement_metadata(key, metrics): 

38 """Test whether a job-level metadata key is really measurement metadata. 

39 

40 Parameters 

41 ---------- 

42 key : `str` 

43 The metadata key to test. 

44 metrics : iterable of `lsst.verify.Name` or of `str` 

45 The metrics recorded in the job. 

46 

47 Returns 

48 ------- 

49 result : `bool` 

50 `True` if ``key`` represents measurement metadata, `False` if it 

51 represents purely job-level metadata. 

52 """ 

53 for metric in metrics: 

54 if str(metric) in key: 

55 return True 

56 return False 

57 

58 

59def _simplify_key(key, prefix): 

60 """Remove a prefix from a key, if it's present. 

61 

62 Parameters 

63 ---------- 

64 key : `str` 

65 The key to simplify. 

66 prefix : `str` 

67 The prefix to remove from ``key``. 

68 

69 Returns 

70 ------- 

71 simplifiedKey : `str` 

72 ``key`` with any initial ``prefix`` removed 

73 """ 

74 if key.startswith(prefix): 

75 return key.replace(prefix, "", 1) 

76 else: 

77 return key 

78 

79 

80def _get_first_col_width(job): 

81 """Return the width to use for the output's first column. 

82 

83 This column displays metadata and metric keys. 

84 

85 Parameters 

86 ---------- 

87 job : `lsst.verify.Job` 

88 The Job to print. 

89 

90 Returns 

91 ------- 

92 width : `int` 

93 The minimum width to use to format the Job's values. May be 0 if the 

94 Job is empty. 

95 """ 

96 max_meta = max(len(key) for key in job.meta) if job.meta else 0 

97 max_meas = max(len(str(metric)) for metric in job.measurements) \ 

98 if job.measurements else 0 

99 

100 return max(max_meta, max_meas) 

101 

102 

103def inspect_job(job): 

104 """Present the measurements in a Job object. 

105 

106 The measurements and any metadata are printed to standard output. 

107 

108 Parameters 

109 ---------- 

110 job : `lsst.verify.Job` 

111 The Job to examine. 

112 """ 

113 # Leave enough space for output so that all '=' characters are aligned 

114 max_metric_length = _get_first_col_width(job) 

115 

116 print("Common metadata:") 

117 for key, value in job.meta.items(): 

118 if _is_measurement_metadata(key, job.measurements.keys()): 

119 continue 

120 print("%*s = %s" % (max_metric_length, key, value)) 

121 

122 print("\nMeasurements:") 

123 for metric, measurement in job.measurements.items(): 

124 pretty_quantity = measurement.quantity.round(4) 

125 if measurement.notes: 

126 prefix = str(measurement.metric_name) + "." 

127 # Raw representation of measurement.notes hard to read 

128 simple_notes = {_simplify_key(key, prefix): value 

129 for key, value in measurement.notes.items()} 

130 print("%*s = %10s (%s)" 

131 % (max_metric_length, metric, pretty_quantity, simple_notes)) 

132 else: 

133 print("%*s = %10s" % (max_metric_length, metric, pretty_quantity)) 

134 

135 

136def build_argparser(): 

137 """Construct an argument parser for the ``inspect_job.py`` script. 

138 

139 Returns 

140 ------- 

141 argparser : `argparse.ArgumentParser` 

142 The argument parser that defines the ``inspect_job.py`` command-line 

143 interface. 

144 """ 

145 parser = argparse.ArgumentParser( 

146 description=__doc__, 

147 formatter_class=argparse.RawDescriptionHelpFormatter, 

148 epilog='More information is available at https://pipelines.lsst.io.') 

149 parser.add_argument( 

150 'json_paths', 

151 nargs='+', 

152 metavar='json', 

153 help='lsst.verify JSON file, or files (``*verify.json``).') 

154 return parser 

155 

156 

157def main(): 

158 """Present all Job files. 

159 """ 

160 args = build_argparser().parse_args() 

161 for filename in args.json_paths: 

162 if len(args.json_paths) > 1: 

163 print("\n%s:" % filename) 

164 with open(filename) as f: 

165 job = Job.deserialize(**json.load(f)) 

166 inspect_job(job)