Coverage for python/lsst/obs/base/formatters/filter.py: 52%

Shortcuts on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

46 statements  

1# This file is part of obs_base. 

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 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 <http://www.gnu.org/licenses/>. 

21 

22# TODO: remove this entire file in DM-27177 

23 

24from __future__ import annotations 

25 

26__all__ = ("FilterFormatter", "FilterTranslator",) 

27 

28import yaml 

29from lsst.afw.image import Filter 

30 

31from typing import ( 

32 Any, 

33 Optional, 

34 Type, 

35) 

36 

37from lsst.afw.image import FilterLabel 

38from lsst.daf.butler.formatters.file import FileFormatter 

39from lsst.daf.butler import StorageClassDelegate 

40 

41 

42class FilterFormatter(FileFormatter): 

43 """Read and write `~lsst.afw.image.Filter` filter information.""" 

44 

45 extension = ".yaml" 

46 

47 unsupportedParameters = None 

48 """This formatter does not support any parameters.""" 

49 

50 def _readFile(self, path: str, pytype: Type[Any] = None) -> Any: 

51 """Read a file from the path in YAML format. 

52 

53 Parameters 

54 ---------- 

55 path : `str` 

56 Path to use to open the file. 

57 pytype : `class`, optional 

58 The type expected to be returned. 

59 

60 Returns 

61 ------- 

62 data : `object` 

63 Either data as Python object read from YAML file, or None 

64 if the file could not be opened. 

65 """ 

66 try: 

67 with open(path, "rb") as fd: 

68 data = self._fromBytes(fd.read(), pytype) 

69 except FileNotFoundError: 

70 data = None 

71 

72 return data 

73 

74 def _fromBytes(self, serializedDataset: bytes, pytype: Optional[Type[Any]] = None) -> Any: 

75 """Read the bytes object as a python object. 

76 

77 Parameters 

78 ---------- 

79 serializedDataset : `bytes` 

80 Bytes object to unserialize. 

81 pytype : `type`, optional 

82 Expected python type to be returned. 

83 

84 Returns 

85 ------- 

86 inMemoryDataset : `lsst.afw.image.Filter` 

87 The requested data as an object. 

88 """ 

89 data = yaml.load(serializedDataset, Loader=yaml.SafeLoader) 

90 

91 if pytype is None: 

92 pytype = Filter 

93 

94 # This will be a simple dict so we need to convert it to 

95 # the Filter type -- just needs the name 

96 filter = pytype(data["canonicalName"], force=True) 

97 

98 return filter 

99 

100 def _writeFile(self, inMemoryDataset: Any) -> None: 

101 """Write the in memory dataset to file on disk. 

102 

103 Parameters 

104 ---------- 

105 inMemoryDataset : `lsst.afw.image.Filter` 

106 Filter to serialize. 

107 

108 Raises 

109 ------ 

110 Exception 

111 Raised if the file could not be written or the dataset could not be 

112 serialized. 

113 """ 

114 with open(self.fileDescriptor.location.path, "wb") as fd: 

115 fd.write(self._toBytes(inMemoryDataset)) 

116 

117 def _toBytes(self, inMemoryDataset: Any) -> bytes: 

118 """Write the in memory dataset to a bytestring. 

119 

120 Parameters 

121 ---------- 

122 inMemoryDataset : `lsst.afw.image.Filter` 

123 Object to serialize. 

124 

125 Returns 

126 ------- 

127 serializedDataset : `bytes` 

128 YAML string encoded to bytes. 

129 

130 Raises 

131 ------ 

132 Exception 

133 Raised if the object could not be serialized. 

134 """ 

135 

136 # Convert the Filter to a dict for dumping 

137 # Given the singleton situation, only the name is really 

138 # needed but it does not hurt to put some detail in the file 

139 # to aid debugging. 

140 filter = {} 

141 filter["canonicalName"] = inMemoryDataset.getCanonicalName() 

142 filter["name"] = inMemoryDataset.getName() 

143 filter["aliases"] = inMemoryDataset.getAliases() 

144 

145 return yaml.dump(filter).encode() 

146 

147 

148class FilterTranslator(StorageClassDelegate): 

149 """Derived-component converter for a Filter that has been stored as 

150 a FilterLabel. 

151 """ 

152 # More complex than a Formatter that can read both Filter and FilterLabel, 

153 # but can be phased out once Filter is gone without breaking compatibility 

154 # with old FilterLabels. 

155 

156 def getComponent(self, label, derivedName): 

157 """Derive a Filter from a FilterLabel. 

158 

159 Parameters 

160 ---------- 

161 label : `~lsst.afw.image.FilterLabel` 

162 The object to convert. 

163 derivedName : `str` 

164 Name of type to convert to. Only "filter" is supported. 

165 

166 Returns 

167 ------- 

168 derived : `object` 

169 The converted type. Can be `None`. 

170 

171 Raises 

172 ------ 

173 AttributeError 

174 An unknown component was requested. 

175 """ 

176 if derivedName == "filter": 176 ↛ 196line 176 didn't jump to line 196, because the condition on line 176 was never false

177 # Port of backwards-compatibility code in afw; don't want to 

178 # expose it as API. 

179 

180 # Filters still have standard aliases, so can use almost any name 

181 # to define them. Prefer afw_name or band because that's what most 

182 # code assumes is Filter.getName(). 

183 if label == FilterLabel(band="r", physical="HSC-R2"): 183 ↛ 184line 183 didn't jump to line 184, because the condition on line 183 was never true

184 return Filter("r2", force=True) 

185 elif label == FilterLabel(band="i", physical="HSC-I2"): 185 ↛ 186line 185 didn't jump to line 186, because the condition on line 185 was never true

186 return Filter("i2", force=True) 

187 elif label == FilterLabel(physical="solid plate 0.0 0.0"): 187 ↛ 188line 187 didn't jump to line 188, because the condition on line 187 was never true

188 return Filter("SOLID", force=True) 

189 elif label.hasBandLabel(): 189 ↛ 190line 189 didn't jump to line 190, because the condition on line 189 was never true

190 return Filter(label.bandLabel, force=True) 

191 else: 

192 # FilterLabel guarantees at least one of band or physical 

193 # is defined. 

194 return Filter(label.physicalLabel, force=True) 

195 else: 

196 raise AttributeError(f"Do not know how to convert {type(label)} to {derivedName}")