Coverage for tests/test_fits_date_header.py: 100%

44 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-06-24 08:46 +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. 

11 

12from __future__ import annotations 

13 

14import os 

15import tempfile 

16import unittest 

17 

18import astropy.io.fits 

19import astropy.time 

20 

21from lsst.images import Image 

22from lsst.images.fits import ExtensionKey, FitsInputArchive 

23 

24 

25class FitsDateHeaderTestCase(unittest.TestCase): 

26 """Tests for the FITS ``DATE`` card the standard requires on every HDU.""" 

27 

28 def setUp(self) -> None: 

29 # Assume Image written correctly will be representative. 

30 self.image = Image(0.0, shape=(4, 4), dtype="float32") 

31 

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) 

52 

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) 

66 

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) 

79 

80 

81if __name__ == "__main__": 

82 unittest.main()