Coverage for tests/test_ndf_model.py: 94%

63 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-07-16 15:24 -0700

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 

14from pathlib import Path 

15 

16import numpy as np 

17import pytest 

18 

19try: 

20 import h5py 

21 

22 from lsst.images.ndf import _hds 

23 from lsst.images.ndf._model import HdsPrimitive, Ndf, NdfArray, NdfDocument, NdfQuality, NdfWcs 

24 

25 HAVE_H5PY = True 

26except ImportError: 

27 HAVE_H5PY = False 

28 

29skip_no_h5py = pytest.mark.skipif(not HAVE_H5PY, reason="h5py is not installed") 

30 

31 

32def _attr_str(value: object) -> str: 

33 """Return value decoded to str, handling bytes from HDF5 attributes.""" 

34 if isinstance(value, bytes): 34 ↛ 36line 34 didn't jump to line 36 because the condition on line 34 was always true

35 return value.decode("ascii") 

36 return str(value) 

37 

38 

39@skip_no_h5py 

40def test_ndf_document_writes_standard_components(tmp_path: Path) -> None: 

41 """Verify NdfDocument writes all standard NDF components to HDF5 

42 correctly. 

43 """ 

44 image = np.arange(6, dtype=np.float32).reshape(2, 3) 

45 quality = np.array([[0, 1, 0], [1, 0, 0]], dtype=np.uint8) 

46 wcs_lines = [" Begin FrameSet", " End FrameSet"] 

47 document = NdfDocument(root=Ndf(), root_name="TEST") 

48 document.root.set_array_component("DATA_ARRAY", image, origin=(20, 10)) 

49 document.root.set_quality( 

50 NdfQuality( 

51 NdfArray( 

52 quality, 

53 origin=np.array([20, 10], dtype=np.int32), 

54 bad_pixel=False, 

55 ) 

56 ) 

57 ) 

58 document.root.set_wcs(NdfWcs(wcs_lines)) 

59 document.root.set_units("adu") 

60 lsst = document.root.ensure_lsst_extension() 

61 lsst.children["JSON"] = HdsPrimitive.char_array(['{"kind":"image"}'], width=80) 

62 

63 path = str(tmp_path / "test.sdf") 

64 with h5py.File(path, "w") as f: 

65 document.write_to_hdf5(f) 

66 with h5py.File(path, "r") as f: 

67 assert _attr_str(f["/"].attrs[_hds.ATTR_CLASS]) == "NDF" 

68 assert _attr_str(f["/"].attrs[_hds.ATTR_ROOT_NAME]) == "TEST" 

69 assert _attr_str(f["/DATA_ARRAY"].attrs[_hds.ATTR_CLASS]) == "ARRAY" 

70 np.testing.assert_array_equal(f["/DATA_ARRAY/DATA"][()], image) 

71 np.testing.assert_array_equal(f["/DATA_ARRAY/ORIGIN"][()], np.array([20, 10])) 

72 assert _attr_str(f["/QUALITY"].attrs[_hds.ATTR_CLASS]) == "QUALITY" 

73 assert f["/QUALITY/BADBITS"][()] == 255 

74 np.testing.assert_array_equal(f["/QUALITY/QUALITY/DATA"][()], quality) 

75 assert f["/QUALITY/QUALITY/BAD_PIXEL"].id.get_type().get_class() == h5py.h5t.BITFIELD 

76 assert _attr_str(f["/WCS"].attrs[_hds.ATTR_CLASS]) == "WCS" 

77 assert _hds.read_char_array(f["/WCS/DATA"]) == wcs_lines 

78 assert f["/UNITS"].shape == () 

79 assert f["/UNITS"][()].decode("ascii").rstrip(" ") == "adu" 

80 assert _hds.read_char_array(f["/MORE/LSST/JSON"]) == ['{"kind":"image"}'] 

81 

82 

83@skip_no_h5py 

84def test_document_read_preserves_typed_ndf_components(tmp_path: Path) -> None: 

85 """Verify NdfDocument.from_hdf5 recovers typed NDF components after 

86 a round-trip. 

87 """ 

88 image = np.arange(4, dtype=np.int16).reshape(2, 2) 

89 path = str(tmp_path / "test.sdf") 

90 with h5py.File(path, "w") as f: 

91 document = NdfDocument(root=Ndf(), root_name="READ") 

92 document.root.set_array_component("DATA_ARRAY", image, origin=(5, 6)) 

93 document.root.set_units("count") 

94 document.write_to_hdf5(f) 

95 with h5py.File(path, "r") as f: 

96 recovered = NdfDocument.from_hdf5(f) 

97 assert isinstance(recovered.root, Ndf) 

98 assert recovered.root_name == "READ" 

99 assert recovered.root.get_units() == "count" 

100 data = recovered.get("/DATA_ARRAY/DATA") 

101 assert isinstance(data, HdsPrimitive) 

102 np.testing.assert_array_equal(data.read_array(), image)