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

Hot-keys 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
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/>.
22# TODO: remove this entire file in DM-27177
24from __future__ import annotations
26__all__ = ("FilterFormatter", "FilterTranslator",)
28import yaml
29from lsst.afw.image import Filter
31from typing import (
32 Any,
33 Optional,
34 Type,
35)
37from lsst.afw.image import FilterLabel
38from lsst.daf.butler.formatters.file import FileFormatter
39from lsst.daf.butler import StorageClassDelegate
42class FilterFormatter(FileFormatter):
43 """Read and write `~lsst.afw.image.Filter` filter information."""
45 extension = ".yaml"
47 unsupportedParameters = None
48 """This formatter does not support any parameters."""
50 def _readFile(self, path: str, pytype: Type[Any] = None) -> Any:
51 """Read a file from the path in YAML format.
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.
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
72 return data
74 def _fromBytes(self, serializedDataset: bytes, pytype: Optional[Type[Any]] = None) -> Any:
75 """Read the bytes object as a python object.
77 Parameters
78 ----------
79 serializedDataset : `bytes`
80 Bytes object to unserialize.
81 pytype : `type`, optional
82 Expected python type to be returned.
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)
91 if pytype is None:
92 pytype = Filter
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)
98 return filter
100 def _writeFile(self, inMemoryDataset: Any) -> None:
101 """Write the in memory dataset to file on disk.
103 Parameters
104 ----------
105 inMemoryDataset : `lsst.afw.image.Filter`
106 Filter to serialize.
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))
117 def _toBytes(self, inMemoryDataset: Any) -> bytes:
118 """Write the in memory dataset to a bytestring.
120 Parameters
121 ----------
122 inMemoryDataset : `lsst.afw.image.Filter`
123 Object to serialize.
125 Returns
126 -------
127 serializedDataset : `bytes`
128 YAML string encoded to bytes.
130 Raises
131 ------
132 Exception
133 Raised if the object could not be serialized.
134 """
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()
145 return yaml.dump(filter).encode()
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.
156 def getComponent(self, label, derivedName):
157 """Derive a Filter from a FilterLabel.
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.
166 Returns
167 -------
168 derived : `object`
169 The converted type. Can be `None`.
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.
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}")