Coverage for python/lsst/obs/lsst/testHelper.py: 33%
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 obs_lsst.
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#
23"""Test support classes for obs_lsst"""
24__all__ = ("ObsLsstButlerTests", "ObsLsstObsBaseOverrides")
26import os.path
27import unittest
28import lsst.utils.tests
29import lsst.obs.base.tests
30from lsst.utils import getPackageDir
32# Define the data location relative to this package
33DATAROOT = os.path.join(getPackageDir("obs_lsst"), "data", "input")
36class ObsLsstButlerTests(lsst.utils.tests.TestCase):
37 """Base class shared by all tests of the butler and mapper.
39 This class can not inherit from `~lsst.obs.base.tests.ObsTests` since
40 that will trigger tests in this class directly that will fail.
42 This class defines a butler and a mapper for each test subclass.
43 They are stored in the ``_mapper`` and ``_butler`` class attributes
44 to distinguish them from the ``mapper`` and ``butler`` instance
45 attributes used by `~lsst.obs.base.tests.ObsTests`.
46 """
48 instrumentDir = "TBD" # Override in subclass
49 """Name of instrument directory within data/input."""
51 _mapper = None
52 _butler = None
54 @classmethod
55 def tearDownClass(cls):
56 del cls._mapper
57 del cls._butler
59 @classmethod
60 def setUpClass(cls):
61 cls.data_dir = os.path.normpath(os.path.join(DATAROOT, cls.instrumentDir))
62 # Protection against the base class values being used
63 if not os.path.exists(cls.data_dir):
64 raise unittest.SkipTest(f"Data directory {cls.data_dir} does not exist.")
66 cls._butler = lsst.daf.persistence.Butler(root=cls.data_dir)
67 mapper_class = cls._butler.getMapperClass(root=cls.data_dir)
68 cls._mapper = mapper_class(root=cls.data_dir)
71class ObsLsstObsBaseOverrides(lsst.obs.base.tests.ObsTests):
72 """Specialist butler tests for obs_lsst."""
74 def testRawVisitInfo(self):
75 visitInfo = self.butler.get("raw_visitInfo", self.dataIds["raw"])
76 self.assertIsInstance(visitInfo, lsst.afw.image.VisitInfo)
77 # We should always get a valid date and exposure time
78 self.assertIsInstance(visitInfo.getDate(), lsst.daf.base.DateTime)
79 self.assertTrue(visitInfo.getDate().isValid())
80 self.assertEqual(visitInfo.getExposureTime(), self.butler_get_data.exptimes["raw"])
82 def testRawFilename(self):
83 filepath = self.butler.get("raw_filename", self.dataIds["raw"])[0]
84 if "[" in filepath: # Remove trailing HDU specifier
85 filepath = filepath[:filepath.find("[")]
86 filename = os.path.split(filepath)[1]
87 self.assertEqual(filename, self.mapper_data.raw_filename)
89 def testQueryRawAmp(self):
90 # Base the tests on the first reference metadata query
91 formats = self.mapper_data.query_format.copy()
92 query, expect = self.mapper_data.queryMetadata[0]
93 result = self.mapper.queryMetadata("raw_amp", formats, query)
94 self.assertEqual(sorted(result), sorted(expect))
96 # Listing all channels -- we expect the result to be the expected
97 # result copied for each channel
98 formats = formats.copy()
99 formats.insert(0, "channel")
100 expectall = [(i+1, *expect[0]) for i in range(16)]
101 result = self.mapper.queryMetadata("raw_amp", formats, query)
102 self.assertEqual(sorted(result), sorted(expectall))
104 # Now fix a channel
105 query = query.copy()
106 query["channel"] = 3
107 result = self.mapper.queryMetadata("raw_amp", formats, query)
108 expect = [(query["channel"], *expect[0])]
109 self.assertEqual(sorted(result), sorted(expect))
111 # Fix a channel out of range
112 query["channel"] = 20
113 with self.assertRaises(ValueError):
114 self.mapper.queryMetadata("raw_amp", formats, query)
116 def _testCoaddId(self, idName):
117 coaddId = self.butler.get(idName, dataId={"tract": 9813, "patch": "3,4",
118 "filter": self.butler_get_data.filters["raw"]})
119 self.assertIsInstance(coaddId, int)
120 maxbits = self.butler.get(f"{idName}_bits")
121 self.assertLess(maxbits, 64)
122 self.assertLess(coaddId.bit_length(), maxbits, f"compare bit length for {idName}")
124 # Check failure modes
125 with self.assertRaises(RuntimeError):
126 self.butler.get(idName, dataId={"tract": 9813, "patch": "-3,4"})
127 with self.assertRaises(RuntimeError):
128 self.butler.get(idName, dataId={"tract": -9813, "patch": "3,4"})
129 with self.assertRaises(RuntimeError):
130 self.butler.get(idName, dataId={"tract": 2**self.mapper._nbit_tract+1, "patch": "3,4"})
131 with self.assertRaises(RuntimeError):
132 self.butler.get(idName, dataId={"tract": 2, "patch": f"3,{2**self.mapper._nbit_patch+1}"})
134 def testDeepCoaddId(self):
135 self._testCoaddId("deepCoaddId")
137 def testDcrCoaddId(self):
138 self._testCoaddId("dcrCoaddId")
140 def testDeepMergedCoaddId(self):
141 self._testCoaddId("deepMergedCoaddId")
143 def testDcrMergedCoaddId(self):
144 self._testCoaddId("dcrMergedCoaddId")
146 def testCcdExposureIdBits(self):
147 """Check that we have enough bits for the exposure ID"""
148 bits = self.butler.get('ccdExposureId_bits')
149 ccdExposureId = self.butler_get_data.exposureIds["raw"]
150 self.assertLessEqual(ccdExposureId.bit_length(), bits,
151 f"Can detector_exposure_id {ccdExposureId} fit in {bits} bits")