LSST Applications  21.0.0+75b29a8a7f,21.0.0+e70536a077,21.0.0-1-ga51b5d4+62c747d40b,21.0.0-10-gbfb87ad6+3307648ee3,21.0.0-15-gedb9d5423+47cba9fc36,21.0.0-2-g103fe59+fdf0863a2a,21.0.0-2-g1367e85+d38a93257c,21.0.0-2-g45278ab+e70536a077,21.0.0-2-g5242d73+d38a93257c,21.0.0-2-g7f82c8f+e682ffb718,21.0.0-2-g8dde007+d179fbfa6a,21.0.0-2-g8f08a60+9402881886,21.0.0-2-ga326454+e682ffb718,21.0.0-2-ga63a54e+08647d4b1b,21.0.0-2-gde069b7+26c92b3210,21.0.0-2-gecfae73+0445ed2f95,21.0.0-2-gfc62afb+d38a93257c,21.0.0-27-gbbd0d29+ae871e0f33,21.0.0-28-g5fc5e037+feb0e9397b,21.0.0-3-g21c7a62+f4b9c0ff5c,21.0.0-3-g357aad2+57b0bddf0b,21.0.0-3-g4be5c26+d38a93257c,21.0.0-3-g65f322c+3f454acf5d,21.0.0-3-g7d9da8d+75b29a8a7f,21.0.0-3-gaa929c8+9e4ef6332c,21.0.0-3-ge02ed75+4b120a55c4,21.0.0-4-g3300ddd+e70536a077,21.0.0-4-g591bb35+4b120a55c4,21.0.0-4-gc004bbf+4911b9cd27,21.0.0-4-gccdca77+f94adcd104,21.0.0-4-ge8fba5a+2b3a696ff9,21.0.0-5-gb155db7+2c5429117a,21.0.0-5-gdf36809+637e4641ee,21.0.0-6-g00874e7+c9fd7f7160,21.0.0-6-g4e60332+4b120a55c4,21.0.0-7-gc8ca178+40eb9cf840,21.0.0-8-gfbe0b4b+9e4ef6332c,21.0.0-9-g2fd488a+d83b7cd606,w.2021.05
LSST Data Management Base Package
filter.py
Go to the documentation of this file.
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 
24 from __future__ import annotations
25 
26 __all__ = ("FilterFormatter", "FilterTranslator",)
27 
28 import yaml
29 from lsst.afw.image import Filter
30 
31 from typing import (
32  Any,
33  Optional,
34  Type,
35 )
36 
37 from lsst.afw.image import FilterLabel
38 from lsst.daf.butler.formatters.file import FileFormatter
39 from lsst.daf.butler import StorageClassDelegate
40 
41 
42 class 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_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_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 
148 class 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":
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"):
184  return Filter("r2", force=True)
185  elif label == FilterLabel(band="i", physical="HSC-I2"):
186  return Filter("i2", force=True)
187  elif label == FilterLabel(physical="solid plate 0.0 0.0"):
188  return Filter("SOLID", force=True)
189  elif label.hasBandLabel():
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}")
A group of labels for a filter in an exposure or coadd.
Definition: FilterLabel.h:58
bytes _toBytes(self, Any inMemoryDataset)
Definition: filter.py:117
Any _fromBytes(self, bytes serializedDataset, Optional[Type[Any]] pytype=None)
Definition: filter.py:74
def getComponent(self, label, derivedName)
Definition: filter.py:156
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.