Coverage for tests/test_translation.py: 22%
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
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
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.
12import os.path
13import unittest
14from astropy.time import Time
16from astro_metadata_translator import FitsTranslator, StubTranslator, ObservationInfo
18TESTDIR = os.path.abspath(os.path.dirname(__file__))
21class InstrumentTestTranslator(FitsTranslator, StubTranslator):
22 """Simple FITS-like translator to test the infrastructure"""
24 # Needs a name to be registered
25 name = "TestTranslator"
27 # Indicate the instrument this class understands
28 supported_instrument = "SCUBA_test"
30 # Some new mappings, including an override
31 _trivial_map = {"telescope": "TELCODE",
32 "exposure_id": "EXPID",
33 "relative_humidity": "HUMIDITY",
34 "detector_name": "DETNAME",
35 "observation_id": "OBSID"}
37 # Add translator method to test joining
38 def to_physical_filter(self):
39 return self._join_keyword_values(["DETNAME", "HUMIDITY"], delim="_")
42class MissingMethodsTranslator(FitsTranslator):
43 """Translator class that does not implement all the methods."""
44 pass
47class TranslatorTestCase(unittest.TestCase):
49 def setUp(self):
50 # Known simple header
51 self.header = {"TELESCOP": "JCMT",
52 "TELCODE": "LSST",
53 "INSTRUME": "SCUBA_test",
54 "DATE-OBS": "2000-01-01T01:00:01.500",
55 "DATE-END": "2000-01-01T02:00:01.500",
56 "OBSGEO-X": "-5464588.84421314",
57 "OBSGEO-Y": "-2493000.19137644",
58 "OBSGEO-Z": "2150653.35350771",
59 "OBSID": "20000101_00002",
60 "EXPID": "22", # Should cast to a number
61 "DETNAME": 76, # Should cast to a string
62 "HUMIDITY": "55", # Should cast to a float
63 "BAZ": "bar"}
65 def test_manual_translation(self):
67 header = self.header
68 translator = FitsTranslator(header)
70 # Treat the header as standard FITS
71 self.assertFalse(FitsTranslator.can_translate(header))
72 self.assertEqual(translator.to_telescope(), "JCMT")
73 self.assertEqual(translator.to_instrument(), "SCUBA_test")
74 self.assertEqual(translator.to_datetime_begin(),
75 Time(header["DATE-OBS"], format="isot"))
77 # This class will issue warnings
78 with self.assertLogs("astro_metadata_translator") as cm:
79 class InstrumentTestTranslatorExtras(InstrumentTestTranslator):
80 """Version of InstrumentTestTranslator with unexpected
81 fields."""
82 name = "InstrumentTestTranslatorExtras"
83 _trivial_map = {"foobar": "BAZ"}
84 _const_map = {"format": "HDF5"}
86 self.assertIn("Unexpected trivial", cm.output[0])
87 self.assertIn("Unexpected constant", cm.output[1])
89 # Use the special test translator instead
90 translator = InstrumentTestTranslatorExtras(header)
91 self.assertTrue(InstrumentTestTranslator.can_translate(header))
92 self.assertEqual(translator.to_telescope(), "LSST")
93 self.assertEqual(translator.to_instrument(), "SCUBA_test")
94 self.assertEqual(translator.to_format(), "HDF5")
95 self.assertEqual(translator.to_foobar(), "bar")
97 def test_translator(self):
98 header = self.header
100 # Specify a translation class
101 with self.assertWarns(UserWarning):
102 # Since the translator is incomplete it should issue warnings
103 v1 = ObservationInfo(header, translator_class=InstrumentTestTranslator)
104 self.assertEqual(v1.instrument, "SCUBA_test")
105 self.assertEqual(v1.telescope, "LSST")
106 self.assertEqual(v1.exposure_id, 22)
107 self.assertIsInstance(v1.exposure_id, int)
108 self.assertEqual(v1.detector_name, "76")
109 self.assertEqual(v1.relative_humidity, 55.0)
110 self.assertIsInstance(v1.relative_humidity, float)
111 self.assertEqual(v1.physical_filter, "76_55")
113 # Now automated class
114 with self.assertWarns(UserWarning):
115 # Since the translator is incomplete it should issue warnings
116 v1 = ObservationInfo(header)
117 self.assertEqual(v1.instrument, "SCUBA_test")
118 self.assertEqual(v1.telescope, "LSST")
120 location = v1.location.to_geodetic()
121 self.assertAlmostEqual(location.height.to("m").to_value(), 4123.0, places=1)
123 # Check that headers have been removed
124 new_hdr = v1.stripped_header()
125 self.assertNotIn("INSTRUME", new_hdr)
126 self.assertNotIn("OBSGEO-X", new_hdr)
127 self.assertIn("TELESCOP", new_hdr)
129 # Check the list of cards that were used
130 used = v1.cards_used
131 self.assertIn("INSTRUME", used)
132 self.assertIn("OBSGEO-Y", used)
133 self.assertNotIn("TELESCOP", used)
135 # Stringification
136 summary = str(v1)
137 self.assertIn("datetime_begin", summary)
139 # Create with a subset of properties
140 v2 = ObservationInfo(header, translator_class=InstrumentTestTranslator,
141 subset={"telescope", "datetime_begin", "exposure_group"})
143 self.assertEqual(v2.telescope, v1.telescope)
144 self.assertEqual(v2.datetime_begin, v2.datetime_begin)
145 self.assertIsNone(v2.datetime_end)
146 self.assertIsNone(v2.location)
147 self.assertIsNone(v2.observation_id)
149 def test_corrections(self):
150 """Apply corrections before translation."""
151 header = self.header
153 # Specify a translation class
154 with self.assertWarns(UserWarning):
155 # Since the translator is incomplete it should issue warnings
156 v1 = ObservationInfo(header, translator_class=InstrumentTestTranslator,
157 search_path=[os.path.join(TESTDIR, "data", "corrections")])
159 # These values should match the expected translation
160 self.assertEqual(v1.instrument, "SCUBA_test")
161 self.assertEqual(v1.detector_name, "76")
162 self.assertEqual(v1.relative_humidity, 55.0)
163 self.assertIsInstance(v1.relative_humidity, float)
164 self.assertEqual(v1.physical_filter, "76_55")
166 # These two should be the "corrected" values
167 self.assertEqual(v1.telescope, "AuxTel")
168 self.assertEqual(v1.exposure_id, 42)
170 def test_failures(self):
171 header = {}
173 with self.assertRaises(TypeError):
174 ObservationInfo(header, translator_class=ObservationInfo)
176 with self.assertRaises(ValueError):
177 ObservationInfo(header, translator_class=InstrumentTestTranslator,
178 subset={"definitely_not_known"})
180 with self.assertRaises(ValueError):
181 ObservationInfo(header, translator_class=InstrumentTestTranslator,
182 required={"definitely_not_known"})
184 with self.assertLogs("astro_metadata_translator"):
185 with self.assertWarns(UserWarning):
186 ObservationInfo(header, translator_class=InstrumentTestTranslator, pedantic=False)
188 with self.assertRaises(KeyError):
189 with self.assertWarns(UserWarning):
190 ObservationInfo(header, translator_class=InstrumentTestTranslator, pedantic=True)
192 with self.assertLogs("astro_metadata_translator"):
193 with self.assertWarns(UserWarning):
194 ObservationInfo(header, translator_class=InstrumentTestTranslator, pedantic=False,
195 filename="testfile1")
197 with self.assertRaises(KeyError):
198 with self.assertWarns(UserWarning):
199 ObservationInfo(header, translator_class=InstrumentTestTranslator, pedantic=True,
200 filename="testfile2")
202 with self.assertRaises(NotImplementedError):
203 with self.assertLogs("astro_metadata_translator", level="WARN"):
204 ObservationInfo(header, translator_class=MissingMethodsTranslator)
206 with self.assertRaises(KeyError):
207 with self.assertWarns(UserWarning):
208 with self.assertLogs("astro_metadata_translator", level="WARN"):
209 ObservationInfo(header, translator_class=InstrumentTestTranslator, pedantic=False,
210 required={"boresight_airmass"})
213if __name__ == "__main__": 213 ↛ 214line 213 didn't jump to line 214, because the condition on line 213 was never true
214 unittest.main()