Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions autofit/database/model/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,22 @@ def header(self):
def header(self, header):
self._header = header.tostring()

@property
def has_data(self):
"""
Whether this HDU carries an array payload. A data-less HDU stores no
shape, which is how it is distinguished from one holding an array.
"""
return self._shape is not None

@property
def hdu(self):
from astropy.io import fits

type_ = fits.PrimaryHDU if self.is_primary else fits.ImageHDU

return type_(
self.array,
self.array if self.has_data else None,
self.header,
)

Expand All @@ -185,7 +193,18 @@ def hdu(self, hdu):
from astropy.io import fits

self.is_primary = isinstance(hdu, fits.PrimaryHDU)
self.array = hdu.data

# A data-less HDU is legitimate and routine: the first HDU of a
# multi-extension FITS is conventionally an empty PrimaryHDU, and
# `AggregateFITS` emits exactly that. Leave the array columns null
# rather than dereferencing `hdu.data.dtype` on None.
if hdu.data is None:
self._dtype = None
self._shape = None
self.bytes = None
else:
self.array = hdu.data

self.header = hdu.header

@property
Expand Down
31 changes: 31 additions & 0 deletions test_autofit/database/test_file_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,34 @@ def test_hdu(hdu, hdu_array):
loaded = db_hdu.hdu
assert (loaded.data == hdu_array).all()
assert loaded.header == hdu.header


def test_hdu_without_data():
"""
A data-less HDU must round-trip. The first HDU of a multi-extension FITS is
conventionally an empty `PrimaryHDU` — `AggregateFITS` emits exactly that —
so dereferencing `hdu.data.dtype` here broke every such scrape.
"""
db_hdu = db.HDU(name="test", hdu=fits.PrimaryHDU())

assert not db_hdu.has_data

loaded = db_hdu.hdu
assert isinstance(loaded, fits.PrimaryHDU)
assert loaded.data is None


def test_set_fits_with_empty_primary_hdu(fit, hdu_array):
"""
The shape the database scrape actually meets: an empty `PrimaryHDU`
followed by named image extensions.
"""
image_hdu = fits.ImageHDU(hdu_array)
image_hdu.header["EXTNAME"] = "MODEL_IMAGE"

fit.set_fits("test", fits.HDUList([fits.PrimaryHDU(), image_hdu]))

loaded = fit.get_fits("test")
assert len(loaded) == 2
assert loaded[0].data is None
assert (loaded[1].data == hdu_array).all()
Loading