Coverage for tests/test_instrument.py: 28%
91 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-04-14 02:16 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2023-04-14 02:16 -0700
1# This file is part of pipe_base.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://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"""Tests of the Instrument class.
23"""
25import datetime
26import unittest
28from lsst.daf.butler import Registry, RegistryConfig
29from lsst.daf.butler.formatters.json import JsonFormatter
30from lsst.pipe.base import Instrument
31from lsst.utils.introspection import get_full_type_name
34class DummyInstrument(Instrument):
35 @classmethod
36 def getName(cls):
37 return "DummyInstrument"
39 def register(self, registry, update=False):
40 detector_max = 2
41 record = {
42 "instrument": self.getName(),
43 "class_name": get_full_type_name(DummyInstrument),
44 "detector_max": detector_max,
45 }
46 with registry.transaction():
47 registry.syncDimensionData("instrument", record, update=update)
49 def getRawFormatter(self, dataId):
50 return JsonFormatter
53class BadInstrument(DummyInstrument):
54 """Instrument with wrong class name."""
56 raw_definition = ("raw2", ("instrument", "detector", "exposure"), "StructuredDataDict")
58 @classmethod
59 def getName(cls):
60 return "BadInstrument"
62 def register(self, registry, update=False):
63 # Register a bad class name
64 record = {
65 "instrument": self.getName(),
66 "class_name": "builtins.str",
67 "detector_max": 1,
68 }
69 registry.syncDimensionData("instrument", record, update=update)
72class UnimportableInstrument(DummyInstrument):
73 """Instrument with class name that does not exist."""
75 @classmethod
76 def getName(cls):
77 return "NoImportInstr"
79 def register(self, registry, update=False):
80 # Register a bad class name
81 record = {
82 "instrument": self.getName(),
83 "class_name": "not.importable",
84 "detector_max": 1,
85 }
86 registry.syncDimensionData("instrument", record, update=update)
89class InstrumentTestCase(unittest.TestCase):
90 """Test for Instrument."""
92 def setUp(self):
93 self.instrument = DummyInstrument()
94 self.name = "DummyInstrument"
96 def test_basics(self):
97 self.assertEqual(self.instrument.getName(), self.name)
98 self.assertEqual(self.instrument.getRawFormatter({}), JsonFormatter)
99 self.assertIsNone(DummyInstrument.raw_definition)
100 raw = BadInstrument.raw_definition
101 self.assertEqual(raw[2], "StructuredDataDict")
103 def test_register(self):
104 """Test that register() sets appropriate Dimensions."""
105 registryConfig = RegistryConfig()
106 registryConfig["db"] = "sqlite://"
107 registry = Registry.createFromConfig(registryConfig)
108 # Check that the registry starts out empty.
109 self.instrument.importAll(registry)
110 self.assertFalse(list(registry.queryDimensionRecords("instrument")))
112 # Register and check again.
113 self.instrument.register(registry)
114 instruments = list(registry.queryDimensionRecords("instrument"))
115 self.assertEqual(len(instruments), 1)
116 self.assertEqual(instruments[0].name, self.name)
117 self.assertEqual(instruments[0].detector_max, 2)
118 self.assertIn("DummyInstrument", instruments[0].class_name)
120 self.instrument.importAll(registry)
121 from_registry = DummyInstrument.fromName("DummyInstrument", registry)
122 self.assertIsInstance(from_registry, Instrument)
123 with self.assertRaises(LookupError):
124 Instrument.fromName("NotThrere", registry)
126 # Register a bad instrument.
127 BadInstrument().register(registry)
128 with self.assertRaises(TypeError):
129 Instrument.fromName("BadInstrument", registry)
131 UnimportableInstrument().register(registry)
132 with self.assertRaises(ImportError):
133 Instrument.fromName("NoImportInstr", registry)
135 # This should work even with the bad class name.
136 self.instrument.importAll(registry)
138 def test_defaults(self):
139 self.assertEqual(self.instrument.makeDefaultRawIngestRunName(), "DummyInstrument/raw/all")
140 self.assertEqual(
141 self.instrument.makeUnboundedCalibrationRunName("a", "b"), "DummyInstrument/calib/a/b/unbounded"
142 )
143 self.assertEqual(
144 self.instrument.makeCuratedCalibrationRunName("2018-05-04", "a"),
145 "DummyInstrument/calib/a/curated/20180504T000000Z",
146 )
147 self.assertEqual(self.instrument.makeCalibrationCollectionName("c"), "DummyInstrument/calib/c")
148 self.assertEqual(self.instrument.makeRefCatCollectionName(), "refcats")
149 self.assertEqual(self.instrument.makeRefCatCollectionName("a"), "refcats/a")
150 self.assertEqual(self.instrument.makeUmbrellaCollectionName(), "DummyInstrument/defaults")
152 instrument = DummyInstrument(collection_prefix="Different")
153 self.assertEqual(instrument.makeCollectionName("a"), "Different/a")
154 self.assertEqual(self.instrument.makeCollectionName("a"), "DummyInstrument/a")
156 def test_collection_timestamps(self):
157 self.assertEqual(
158 Instrument.formatCollectionTimestamp("2018-05-03"),
159 "20180503T000000Z",
160 )
161 self.assertEqual(
162 Instrument.formatCollectionTimestamp("2018-05-03T14:32:16"),
163 "20180503T143216Z",
164 )
165 self.assertEqual(
166 Instrument.formatCollectionTimestamp("20180503T143216Z"),
167 "20180503T143216Z",
168 )
169 self.assertEqual(
170 Instrument.formatCollectionTimestamp(datetime.datetime(2018, 5, 3, 14, 32, 16)),
171 "20180503T143216Z",
172 )
173 formattedNow = Instrument.makeCollectionTimestamp()
174 self.assertIsInstance(formattedNow, str)
175 datetimeThen1 = datetime.datetime.strptime(formattedNow, "%Y%m%dT%H%M%S%z")
176 self.assertEqual(datetimeThen1.tzinfo, datetime.timezone.utc)
178 with self.assertRaises(TypeError):
179 Instrument.formatCollectionTimestamp(0)
182if __name__ == "__main__": 182 ↛ 183line 182 didn't jump to line 183, because the condition on line 182 was never true
183 unittest.main()