-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safely convert fitsrec in tree before serializing with asdf #205
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ | |
from . import properties | ||
from . import schema as mschema | ||
from . import validate | ||
from .util import get_envar_as_boolean, remove_none_from_tree | ||
from .util import convert_fitsrec_to_array_in_tree, get_envar_as_boolean, remove_none_from_tree | ||
|
||
from .history import HistoryList | ||
|
||
|
@@ -585,10 +585,15 @@ def to_asdf(self, init, *args, **kwargs): | |
`~asdf.AsdfFile.write_to`. | ||
""" | ||
self.on_save(init) | ||
self.validate() | ||
asdffile = self.open_asdf(self._instance, **kwargs) | ||
self.validate() # required to trigger ValidationWarning | ||
tree = convert_fitsrec_to_array_in_tree(self._instance) | ||
# don't open_asdf(tree) as this will cause a second validation of the tree | ||
# instead open an empty tree, then assign to the hidden '_tree' | ||
asdffile = self.open_asdf(None, **kwargs) | ||
asdffile._tree = tree | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The assignment to |
||
asdffile.write_to(init, *args, **kwargs) | ||
|
||
|
||
@classmethod | ||
def from_fits(cls, init, schema=None, **kwargs): | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -318,6 +318,15 @@ def _remove_none(node): | |
return treeutil.walk_and_modify(tree, _remove_none) | ||
|
||
|
||
def convert_fitsrec_to_array_in_tree(tree): | ||
def _convert_fitsrec(node): | ||
if isinstance(node, fits.FITS_rec): | ||
return _fits_rec_to_array(node) | ||
else: | ||
return node | ||
return treeutil.walk_and_modify(tree, _convert_fitsrec) | ||
|
||
|
||
def rebuild_fits_rec_dtype(fits_rec): | ||
dtype = fits_rec.dtype | ||
new_dtype = [] | ||
|
@@ -329,3 +338,14 @@ def rebuild_fits_rec_dtype(fits_rec): | |
else: | ||
new_dtype.append((field_name, table_dtype)) | ||
return np.dtype((np.record, new_dtype)) | ||
|
||
|
||
def _fits_rec_to_array(fits_rec): | ||
bad_columns = [n for n in fits_rec.dtype.fields if np.issubdtype(fits_rec[n].dtype, np.unsignedinteger)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In table_dtype = dtype[field_name]
field_dtype = fits_rec.field(field_name).dtype
if np.issubdtype(table_dtype, np.signedinteger) and np.issubdtype(field_dtype, np.unsignedinteger): Is that first check unnecessary? Since unsigned integers in FITS are always "pseudo unsigned"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think so. To put it another way, the lack of unsigned integer support in FITS means that all unsigned integers in the fitsrec (so I'm happy to remove the first part of the check in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I opened an issue to track optimizing the comparison. That way this PR can rely on the previously run regtests and a follow-up PR (after the next jwst release) can look into optimizing the comparison. |
||
if not len(bad_columns): | ||
return fits_rec.view(np.ndarray) | ||
new_dtype = rebuild_fits_rec_dtype(fits_rec) | ||
arr = np.asarray(fits_rec, new_dtype).copy() | ||
for name in bad_columns: | ||
arr[name] = fits_rec[name] | ||
return arr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing this assignment has 2 benefits.
walk_and_modify
containsFITS_rec
instances (this function,_map_hdulist_to_arrays
is responsible for replacing the arrays referenced in the tree with the data from the hdus which might come back asFITS_rec
instances). Ifaf.tree
was assigned, asdf would attempt to validate the assigned tree which would result in warnings (in asdf 3.0) if the tree containedFITS_rec
instancesaf.tree
results in validation of the tree. This is unnecessary as this function (_map_hdulist_to_arrays
) is called right after a call toasdf.open
(see from_fits_asdf in the same file) which by default will validate the tree on read. Assigning toaf._tree
avoids this duplicate validation.