Coverage for python/astro_metadata_translator/bin/writesidecar.py: 19%

46 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-03-28 02:59 -0700

1# This file is part of astro_metadata_translator. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

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

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

7# for details of code ownership. 

8# 

9# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11 

12from __future__ import annotations 

13 

14__all__ = ("write_sidecar_files", "write_sidecar_file") 

15 

16import logging 

17import os 

18import traceback 

19from collections.abc import Sequence 

20from typing import IO 

21 

22from ..file_helpers import find_files, read_file_info 

23 

24log = logging.getLogger(__name__) 

25 

26 

27def _split_ext(file: str) -> tuple[str, str]: 

28 """Split the extension from the file name and return it and the root. 

29 

30 Parameters 

31 ---------- 

32 file : `str` 

33 The file name to examine. 

34 

35 Returns 

36 ------- 

37 root : `str` 

38 The root of the file name. 

39 ext : `str` 

40 The file extension. There is special case handling of .gz and other 

41 compression extensions. 

42 """ 

43 special = {".gz", ".bz2", ".xz", ".fz"} 

44 

45 root, ext = os.path.splitext(file) 

46 

47 if ext in special: 

48 root, second_ext = os.path.splitext(root) 

49 ext = second_ext + ext 

50 

51 return root, ext 

52 

53 

54def write_sidecar_file( 

55 file: str, 

56 hdrnum: int, 

57 content_mode: str, 

58 print_trace: bool, 

59 outstream: IO | None = None, 

60) -> bool: 

61 """Write JSON summary to sidecar file. 

62 

63 Parameters 

64 ---------- 

65 file : `str` 

66 The file from which the header is to be read. 

67 hdrnum : `int` 

68 The HDU number to read. The primary header is always read and 

69 merged with the header from this HDU. 

70 content_mode : `str` 

71 Content mode to use when writing JSON to sidecar. Options are: 

72 ``metadata`` to write the unmodified header; 

73 ``translated`` to write the translated ObservationInfo. 

74 print_trace : `bool` 

75 If there is an error reading the file and this parameter is `True`, 

76 a full traceback of the exception will be reported. If `False` prints 

77 a one line summary of the error condition. If `None` the exception 

78 will be allowed. 

79 outstream : `io.StringIO`, optional 

80 Output stream to use for standard messages. Defaults to `None` which 

81 uses the default output stream. 

82 

83 Returns 

84 ------- 

85 success : `bool` 

86 `True` if the file was handled successfully, `False` if the file 

87 could not be processed. 

88 """ 

89 if content_mode not in ("metadata", "translated"): 

90 raise ValueError(f"Specified content mode '{content_mode}' is not understood.") 

91 

92 try: 

93 # Calculate the JSON from the file 

94 json_str = read_file_info( 

95 file, 

96 hdrnum, 

97 content_mode=content_mode, 

98 content_type="json", 

99 print_trace=print_trace, 

100 outstream=outstream, 

101 ) 

102 if json_str is None: 

103 return False 

104 

105 # Calculate sidecar file name derived from this file. 

106 # Match the ButlerURI behavior in that .fits.gz should be replaced 

107 # with .json, and not resulting in .fits.json. 

108 root, ext = _split_ext(file) 

109 newfile = root + ".json" 

110 with open(newfile, "w") as fd: 

111 print(json_str, file=fd) 

112 log.debug("Writing sidecar file %s", newfile) 

113 

114 except Exception as e: 

115 if print_trace is None: 

116 raise e 

117 if print_trace: 

118 traceback.print_exc(file=outstream) 

119 else: 

120 print(repr(e), file=outstream) 

121 return False 

122 return True 

123 

124 

125def write_sidecar_files( 

126 files: Sequence[str], 

127 regex: str, 

128 hdrnum: int, 

129 content_mode: str, 

130 print_trace: bool, 

131 outstream: IO | None = None, 

132) -> tuple[list[str], list[str]]: 

133 """Process each file and create sidecar file. 

134 

135 Parameters 

136 ---------- 

137 files : iterable of `str` 

138 The files or directories from which the headers are to be read. 

139 regex : `str` 

140 Regular expression string used to filter files when a directory is 

141 scanned. 

142 hdrnum : `int` 

143 The HDU number to read. The primary header is always read and 

144 merged with the header from this HDU. 

145 content_mode : `str` 

146 Content mode to use when writing JSON to sidecar. Options are: 

147 ``metadata`` to write the unmodified header; 

148 ``translated`` to write the translated ObservationInfo. 

149 print_trace : `bool` 

150 If there is an error reading the file and this parameter is `True`, 

151 a full traceback of the exception will be reported. If `False` prints 

152 a one line summary of the error condition. 

153 outstream : `io.StringIO`, optional 

154 Output stream to use for standard messages. Defaults to `None` which 

155 uses the default output stream. 

156 

157 Returns 

158 ------- 

159 okay : `list` of `str` 

160 All the files that were processed successfully. 

161 failed : `list` of `str` 

162 All the files that could not be processed. 

163 """ 

164 found_files = find_files(files, regex) 

165 

166 # Process each file 

167 failed = [] 

168 okay = [] 

169 for path in sorted(found_files): 

170 isok = write_sidecar_file(path, hdrnum, content_mode, print_trace, outstream) 

171 if isok: 

172 okay.append(path) 

173 else: 

174 failed.append(path) 

175 

176 return okay, failed