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

47 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-22 10:04 +0000

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 if (measurement.quantity.value < 1e-2): 

125 pretty_quantity = '{0.value:0.2e} {0.unit}'.format(measurement.quantity) 

126 else: 

127 pretty_quantity = measurement.quantity.round(4) 

128 if measurement.notes: 

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

130 # Raw representation of measurement.notes hard to read 

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

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

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

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

135 else: 

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

137 

138 

139def build_argparser(): 

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

141 

142 Returns 

143 ------- 

144 argparser : `argparse.ArgumentParser` 

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

146 interface. 

147 """ 

148 parser = argparse.ArgumentParser( 

149 description=__doc__, 

150 formatter_class=argparse.RawDescriptionHelpFormatter, 

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

152 parser.add_argument( 

153 'json_paths', 

154 nargs='+', 

155 metavar='json', 

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

157 return parser 

158 

159 

160def main(): 

161 """Present all Job files. 

162 """ 

163 args = build_argparser().parse_args() 

164 for filename in args.json_paths: 

165 if len(args.json_paths) > 1: 

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

167 with open(filename) as f: 

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

169 inspect_job(job)