diff --git a/changes/724.feature.rst b/changes/724.feature.rst new file mode 100644 index 000000000..2cd5f52ba --- /dev/null +++ b/changes/724.feature.rst @@ -0,0 +1 @@ +Allow model.update to accept ObjectNode as input. diff --git a/src/stdatamodels/jwst/datamodels/model_base.py b/src/stdatamodels/jwst/datamodels/model_base.py index 850d55302..5c5d52ea3 100644 --- a/src/stdatamodels/jwst/datamodels/model_base.py +++ b/src/stdatamodels/jwst/datamodels/model_base.py @@ -3,6 +3,7 @@ from astropy.time import Time from stdatamodels import DataModel as _DataModel +from stdatamodels import properties from stdatamodels.dynamicdq import dynamic_mask from .dqflags import pixel @@ -79,7 +80,8 @@ def update(self, d, only=None, extra_fits=False, cal_logs=True): ---------- d : `~stdatamodels.jwst.datamodels.JwstDataModel` or dictionary-like object The model to copy the metadata elements from. Can also be a - dictionary or dictionary of dictionaries or lists. + dictionary or dictionary of dictionaries or lists, or an + `~stdatamodels.properties.ObjectNode`. only : str, list of str, or None Update only the named hdu, e.g. ``only='PRIMARY'``. Can either be a string or list of hdu names. If None, all hdus will be updated. @@ -89,7 +91,7 @@ def update(self, d, only=None, extra_fits=False, cal_logs=True): Update from ``cal_logs`` as well as ``meta``. """ # Get the cal logs first - if isinstance(d, _DataModel): + if isinstance(d, properties.Node): # Get cal logs if present if d.hasattr("cal_logs"): logs = copy.deepcopy(d.cal_logs._instance) diff --git a/src/stdatamodels/model_base.py b/src/stdatamodels/model_base.py index 8fb41a05c..763c1e5e4 100644 --- a/src/stdatamodels/model_base.py +++ b/src/stdatamodels/model_base.py @@ -880,7 +880,8 @@ def update(self, d, only=None, extra_fits=False): ---------- d : `~jwst.datamodels.DataModel` or dictionary-like object The model to copy the metadata elements from. Can also be a - dictionary or dictionary of dictionaries or lists. + dictionary or dictionary of dictionaries or lists, or an + `~stdatamodels.properties.ObjectNode`. only : str, None Update only the named hdu, e.g. ``only='PRIMARY'``. Can either be a string or list of hdu names. Default is to update all the hdus. @@ -907,7 +908,7 @@ def hdu_names_from_schema(subschema, path, combiner, ctx, recurse): # Resolve the source dict and, for DataModel input, the set of # schema-approved leaf paths (those with a fits_keyword in the # appropriate HDU). - if isinstance(d, DataModel): + if isinstance(d, properties.Node): hdu_keywords = set() def hdu_keywords_from_schema(subschema, path, combiner, ctx, recurse): diff --git a/tests/jwst/datamodels/test_multislit.py b/tests/jwst/datamodels/test_multislit.py index 82b86bf97..d66fe78a3 100644 --- a/tests/jwst/datamodels/test_multislit.py +++ b/tests/jwst/datamodels/test_multislit.py @@ -6,6 +6,7 @@ from numpy.testing import assert_array_equal from stdatamodels.jwst.datamodels import ImageModel, MultiSlitModel, SlitModel +from stdatamodels.properties import ObjectNode def test_multislit_model(): @@ -168,3 +169,23 @@ def test_slit_from_multislit(): slit.int_times = slit.get_default("int_times") model.slits.append(slit) slit = SlitModel(model.slits[0].instance) + + +def test_slit_update_from_multislit(): + """Cover a bug where JwstDataModel.update() would raise for ObjectNode input.""" + multislit = MultiSlitModel() + slit = SlitModel() + # name is in both SlitModel and MultiSlitModel slitdata schema + slit.name = "foo" + # telescope is not in MultiSlitModel slitdata schema + slit.meta.telescope = "bar" + multislit.slits.append(slit) + slit_objnode = multislit.slits[0] + assert isinstance(slit_objnode, ObjectNode) + + slit2 = SlitModel() + slit2.update(slit_objnode) + # schema-defined in both -> updated + assert slit2.name == "foo" + # schema-undefined in source -> not updated + assert slit2.meta.telescope is None