Coverage for tests/test_fits.py: 20%
81 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-22 02:38 -0700
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-22 02:38 -0700
1#
2# LSST Data Management System
3# Copyright 2017 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
23import os
24import unittest
26from lsst.daf.base import PropertyList
28import lsst.afw.fits
29import lsst.utils.tests
31testPath = os.path.abspath(os.path.dirname(__file__))
34class FitsTestCase(lsst.utils.tests.TestCase):
36 def setUp(self):
37 # May appear only once in the FITS file (because cfitsio will insist on putting them there)
38 self.single = ["SIMPLE", "BITPIX", "EXTEND", "NAXIS"]
40 def writeAndRead(self, header):
41 """Write the supplied header and read it back again.
42 """
43 fitsFile = lsst.afw.fits.MemFileManager()
44 with lsst.afw.fits.Fits(fitsFile, "w") as fits:
45 fits.createEmpty()
46 fits.writeMetadata(header)
47 with lsst.afw.fits.Fits(fitsFile, "r") as fits:
48 metadata = fits.readMetadata()
49 return metadata
51 def testSimpleIO(self):
52 """Check that a simple header can be written and read back."""
54 expected = {
55 "ASTRING": "Test String",
56 "ANUNDEF": None,
57 "AFLOAT": 3.1415,
58 "ANINT": 42,
59 }
61 header = PropertyList()
62 for k, v in expected.items():
63 header[k] = v
65 output = self.writeAndRead(header)
67 # Remove keys added by cfitsio
68 for k in self.single:
69 if k in output:
70 del output[k]
71 if "COMMENT" in output:
72 del output["COMMENT"]
74 self.assertEqual(output.toDict(), header.toDict())
76 def testReadUndefined(self):
77 """Read a header with some undefined values that might override."""
78 testFile = os.path.join(testPath, "data", "ticket18864.fits")
79 metadata = lsst.afw.fits.readMetadata(testFile)
81 # Neither of these should be arrays despite having doubled keywords
82 # The first value for ADC-STR should override the second undef value
83 self.assertAlmostEqual(metadata.getScalar("ADC-STR"), 22.01)
85 # The value for DOM-WND should be the second value since the first
86 # was undefined
87 self.assertAlmostEqual(metadata.getScalar("DOM-WND"), 4.8)
89 def testReadBlankKeywordComment(self):
90 """Read a header that uses blank keyword comments."""
91 testFile = os.path.join(testPath, "data", "ticket20143.fits")
92 metadata = lsst.afw.fits.readMetadata(testFile)
94 self.assertEqual("---- Checksums ----", metadata["COMMENT"])
95 self.assertNotIn("", metadata, "Check empty strings as keys")
97 def testIgnoreKeywords(self):
98 """Check that certain keywords are ignored in read/write of headers"""
99 # May not appear at all in the FITS file (cfitsio doesn't write these by default)
100 notAtAll = [
101 # FITS core keywords
102 "GCOUNT", "PCOUNT", "XTENSION", "BSCALE", "BZERO", "TZERO", "TSCAL",
103 # FITS compression keywords
104 "ZBITPIX", "ZIMAGE", "ZCMPTYPE", "ZSIMPLE", "ZEXTEND", "ZBLANK", "ZDATASUM", "ZHECKSUM",
105 "ZNAXIS", "ZTILE", "ZNAME", "ZVAL", "ZQUANTIZ",
106 # Not essential these be excluded, but will prevent fitsverify warnings
107 "DATASUM", "CHECKSUM",
108 ]
109 # Additional keywords to check; these should go straight through
110 # Some of these are longer/shorter versions of strings above,
111 # to test that the checks for just the start of strings is working.
112 others = ["FOOBAR", "SIMPLETN", "DATASUMX", "NAX", "SIM"]
114 header = PropertyList()
115 for ii, key in enumerate(self.single + notAtAll + others):
116 header.add(key, ii)
117 metadata = self.writeAndRead(header)
118 for key in self.single:
119 self.assertEqual(metadata.valueCount(key), 1, key)
120 for key in notAtAll:
121 self.assertEqual(metadata.valueCount(key), 0, key)
122 for key in others:
123 self.assertEqual(metadata.valueCount(key), 1, key)
125 def testUndefinedVector(self):
126 header = PropertyList()
127 header.set("FOO", [None, None])
128 metadata = self.writeAndRead(header)
129 self.assertEqual(metadata.getArray("FOO"), [None, None])
131 def test_ticket_dm_36207(self):
132 # test whether moving to invalid HDU and then moving back throws or not
133 testfile = os.path.join(testPath, "data", "parent.fits")
134 fts = lsst.afw.fits.Fits(testfile, "r")
136 # parent.fits has 2 HDUs.
137 with self.assertRaises(lsst.afw.fits.FitsError):
138 fts.setHdu(5)
140 # check that we can move back to primary HDU and pull out a header
141 fts.setHdu(0)
142 mdattest = fts.readMetadata()["COMMENT"]
143 self.assertIn("and Astrophysics', volume 376, page 359;", mdattest)
145 def testNamedHeaderNavigate(self):
146 testfile = os.path.join(testPath, "data", "multi_extension_metadata.fits")
148 # load metadata from the extra table header
149 md_extra_tab = lsst.afw.fits.readMetadata(testfile, hduName="EXTRA_TAB")
150 # assert the value we put in is in the read metadata
151 self.assertTrue("FVALUE" in md_extra_tab)
153 # load metadata from the extra image header, do same test
154 md_extra_im = lsst.afw.fits.readMetadata(testfile, hduName="EXTRA_IM")
155 self.assertTrue("BLORP" in md_extra_im)
157 # now try to load a non-existent named HDU and check that we throw
158 with self.assertRaises(lsst.afw.fits.FitsError):
159 lsst.afw.fits.readMetadata(testfile, hduName="CORDON_BLEAU")
162class TestMemory(lsst.utils.tests.MemoryTestCase):
163 pass
166def setup_module(module):
167 lsst.utils.tests.init()
170if __name__ == "__main__": 170 ↛ 171line 170 didn't jump to line 171, because the condition on line 170 was never true
171 import sys
172 setup_module(sys.modules[__name__])
173 unittest.main()