Skip to content

Commit db6da31

Browse files
Fix FITS bug for list-type metadata (#748)
2 parents 78c8ee5 + df8e130 commit db6da31

3 files changed

Lines changed: 84 additions & 0 deletions

File tree

changes/748.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a bug in saving datamodels to FITS files that caused extra HDUs to be created for datamodels with list-type metadata.

src/stdatamodels/fits_support.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,12 @@ def _fits_item_recurse(fits_context, validator, items, instance, schema):
338338
return
339339

340340
if validator.is_type(items, "object"):
341+
initial_index = fits_context.sequence_index
341342
for index, item in enumerate(instance):
342343
fits_context.sequence_index = index
343344
for error in validator.descend(item, items, path=index):
344345
yield error
346+
fits_context.sequence_index = initial_index
345347
else:
346348
# We don't do the index trick on "tuple validated" sequences
347349
for (index, item), subschema in zip(enumerate(instance), items, strict=False):

tests/test_fits.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,3 +700,84 @@ def test_fitsrec_for_non_schema_data(tmp_path):
700700
)
701701
fn = tmp_path / "test.fits"
702702
m.save(fn)
703+
704+
705+
def test_simple_array(tmp_path):
706+
"""Test that list-type metadata does not generate empty output HDUs."""
707+
file_path = tmp_path / "test.fits"
708+
data_array_schema = {
709+
"allOf": [
710+
asdf.schema.load_schema(
711+
"http://example.com/schemas/core_metadata", resolve_references=True
712+
),
713+
{
714+
"type": "object",
715+
"properties": {
716+
"meta": {
717+
"type": "object",
718+
"properties": {
719+
# store a simple array in metadata
720+
"simple_array": {
721+
"type": "array",
722+
"items": {"type": "array", "items": {"type": "number"}},
723+
},
724+
# add more metadata after the list
725+
"other_metadata": {"type": "string", "fits_keyword": "TEST"},
726+
},
727+
},
728+
"data_array": {
729+
"type": "array",
730+
"items": {
731+
"type": "object",
732+
"properties": {
733+
"data": {
734+
"fits_hdu": "SCI",
735+
"default": 0.0,
736+
"ndim": 2,
737+
"datatype": "float64",
738+
},
739+
},
740+
},
741+
},
742+
},
743+
},
744+
]
745+
}
746+
747+
# Make a model with 3 data arrays, a simple array of metadata values, and one
748+
# other metadata item that comes after the simple array in the schema.
749+
rng = np.random.default_rng(42)
750+
array1 = rng.random((5, 5))
751+
array2 = rng.random((5, 5))
752+
array3 = rng.random((5, 5))
753+
list_items = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12, 13]]
754+
with DataModel(schema=data_array_schema) as x:
755+
x.meta.other_metadata = "VALUE"
756+
for array_item in [array1, array2, array3]:
757+
x.data_array.append(x.data_array.item(data=array_item))
758+
assert len(x.data_array) == 3
759+
760+
x.meta.simple_array = list_items
761+
assert len(x.meta.simple_array) == len(list_items)
762+
763+
x.validate()
764+
x.to_fits(file_path)
765+
766+
# FITS file has new extensions for the data arrays, but no extra extensions
767+
# for the simple array
768+
with fits.open(file_path) as hdulist:
769+
# one primary, 3 SCI extensions, 1 ASDF
770+
assert len(hdulist) == 5
771+
assert hdulist[0].header["TEST"] == "VALUE"
772+
for i, array_item in enumerate([array1, array2, array3]):
773+
hdu = hdulist[i + 1]
774+
assert hdu.name == "SCI"
775+
assert hdu.header["EXTVER"] == i + 1
776+
assert np.allclose(hdu.data, array_item)
777+
778+
# All data and metadata roundtrip from the FITS file
779+
with DataModel(file_path, schema=data_array_schema) as x:
780+
assert len(x.data_array) == 3
781+
assert len(x.meta.simple_array) == len(list_items)
782+
assert x.meta.simple_array == list_items
783+
assert x.meta.other_metadata == "VALUE"

0 commit comments

Comments
 (0)