Coverage for tests/test_fits_date_header.py: 100%
44 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-02 08:55 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-02 08:55 +0000
1# This file is part of lsst-images.
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# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
12from __future__ import annotations
14import os
15import tempfile
16import unittest
18import astropy.io.fits
19import astropy.time
21from lsst.images import Image
22from lsst.images.fits import ExtensionKey, FitsInputArchive
25class FitsDateHeaderTestCase(unittest.TestCase):
26 """Tests for the FITS ``DATE`` card the standard requires on every HDU."""
28 def setUp(self) -> None:
29 # Assume Image written correctly will be representative.
30 self.image = Image(0.0, shape=(4, 4), dtype="float32")
32 def test_every_hdu_has_a_fits_compliant_date(self) -> None:
33 """Each HDU carries a DATE card whose value is a valid FITS datetime
34 recording (approximately) when the file was written.
35 """
36 before = astropy.time.Time.now()
37 with tempfile.TemporaryDirectory() as tmp:
38 path = os.path.join(tmp, "x.fits")
39 self.image.write(path)
40 after = astropy.time.Time.now()
41 with astropy.io.fits.open(path) as hdul:
42 self.assertGreater(len(hdul), 1)
43 for index, hdu in enumerate(hdul):
44 extname = hdu.header.get("EXTNAME", "PRIMARY")
45 with self.subTest(hdu=index, extname=extname):
46 self.assertIn("DATE", hdu.header)
47 # The value must parse in the FITS time format.
48 date = astropy.time.Time(hdu.header["DATE"], format="fits")
49 # And it must reflect this write, not a stale value.
50 self.assertGreaterEqual(date.jd, before.jd)
51 self.assertLessEqual(date.jd, after.jd)
53 def test_update_header_cannot_set_a_stale_primary_date(self) -> None:
54 """An ``update_header`` callback must not be able to leave a stale DATE
55 in the primary header; the card always records this write.
56 """
57 before = astropy.time.Time.now()
58 with tempfile.TemporaryDirectory() as tmp:
59 path = os.path.join(tmp, "x.fits")
60 self.image.write(path, update_header=lambda h: h.set("DATE", "1999-01-01T00:00:00"))
61 after = astropy.time.Time.now()
62 with astropy.io.fits.open(path) as hdul:
63 date = astropy.time.Time(hdul[0].header["DATE"], format="fits")
64 self.assertGreaterEqual(date.jd, before.jd)
65 self.assertLessEqual(date.jd, after.jd)
67 def test_date_is_not_captured_as_opaque_metadata(self) -> None:
68 """DATE is regenerated on every write, so the value read back must not
69 be carried in opaque metadata (which would propagate a stale date to
70 the next write).
71 """
72 with tempfile.TemporaryDirectory() as tmp:
73 path = os.path.join(tmp, "x.fits")
74 self.image.write(path)
75 with FitsInputArchive.open(path) as archive:
76 opaque = archive.get_opaque_metadata()
77 primary_header = opaque.headers[ExtensionKey()]
78 self.assertNotIn("DATE", primary_header)
81if __name__ == "__main__":
82 unittest.main()