def test_check_works_for_zipped(input_file): filename, expected = input_file filename += '.gz' # extra zip extension filetype = check(filename) assert filetype == expected
def test_seekable_file_object(): buff = io.BytesIO() with asdf.AsdfFile() as af: af.write_to(buff) buff.seek(0) assert check(buff) == "asdf" buff = io.BytesIO() hdul = fits.HDUList(fits.PrimaryHDU()) hdul.writeto(buff) buff.seek(0) assert check(buff) == "fits" buff = io.BytesIO() buff.write(json.dumps({"foo": "bar"}).encode("utf-8")) buff.seek(0) assert check(buff) == "asn" # Too short buff = io.BytesIO(b"FOO") with pytest.raises(ValueError): check(buff)
def test_check_works_for_pipeline_patters(pipeline_file): assert check(pipeline_file) == 'fits'
def test_check_fails_on_unsupported_ext(): with pytest.raises(ValueError): check('test_file')
def test_check_on_str_init(input_file): filename, expected = input_file filetype = check(filename) assert filetype == expected
def test_non_seekable_object(): with pytest.raises(ValueError): check(object())
def test_unsupported_filename(filename): with pytest.raises(ValueError): check(filename)
def test_supported_filename(filename, expected_filetype): assert check(filename) == expected_filetype
def open(init=None, memmap=False, **kwargs): """ Creates a DataModel from a number of different types Parameters ---------- init : shape tuple, file path, file object, astropy.io.fits.HDUList, numpy array, dict, None - None: A default data model with no shape - shape tuple: Initialize with empty data of the given shape - file path: Initialize from the given file (FITS , JSON or ASDF) - readable file object: Initialize from the given file object - astropy.io.fits.HDUList: Initialize from the given `~astropy.io.fits.HDUList` - A numpy array: A new model with the data array initialized to what was passed in. - dict: The object model tree for the data model memmap : bool Turn memmap of FITS file on or off. (default: False). Ignored for ASDF files. kwargs : dict Additional keyword arguments passed to lower level functions. These arguments are generally file format-specific. Arguments of note are: - FITS skip_fits_update - bool or None `True` to skip updating the ASDF tree from the FITS headers, if possible. If `None`, value will be taken from the environmental SKIP_FITS_UPDATE. Otherwise, the default value is `True`. Returns ------- model : DataModel instance """ from . import model_base # Initialize variables used to select model class hdulist = {} shape = () file_name = None file_to_close = None # Get special cases for opening a model out of the way # all special cases return a model if they match if init is None: return model_base.JwstDataModel(None) elif isinstance(init, model_base.JwstDataModel): # Copy the object so it knows not to close here return init.__class__(init) elif isinstance(init, (str, bytes)) or hasattr(init, "read"): # If given a string, presume its a file path. # if it has a read method, assume a file descriptor if isinstance(init, bytes): init = init.decode(sys.getfilesystemencoding()) file_name = basename(init) file_type = filetype.check(init) if file_type == "fits": if s3_utils.is_s3_uri(init): hdulist = fits.open(s3_utils.get_object(init)) else: hdulist = fits.open(init, memmap=memmap) file_to_close = hdulist elif file_type == "asn": # Read the file as an association / model container from . import container return container.ModelContainer(init, **kwargs) elif file_type == "asdf": if s3_utils.is_s3_uri(init): asdffile = asdf.open(s3_utils.get_object(init), **kwargs) else: asdffile = asdf.open(init, **kwargs) # Detect model type, then get defined model, and call it. new_class = _class_from_model_type(asdffile) if new_class is None: # No model class found, so return generic DataModel. return model_base.JwstDataModel(asdffile, **kwargs) return new_class(asdffile) elif isinstance(init, tuple): for item in init: if not isinstance(item, int): raise ValueError("shape must be a tuple of ints") shape = init elif isinstance(init, np.ndarray): shape = init.shape elif isinstance(init, fits.HDUList): hdulist = init elif is_association(init) or isinstance(init, list): from . import container return container.ModelContainer(init, **kwargs) # If we have it, determine the shape from the science hdu if hdulist: # So we don't need to open the image twice init = hdulist info = init.fileinfo(0) if info is not None: file_name = info.get('filename') try: hdu = hdulist[('SCI', 1)] except (KeyError, NameError): shape = () else: if hasattr(hdu, 'shape'): shape = hdu.shape else: shape = () # First try to get the class name from the primary header new_class = _class_from_model_type(hdulist) has_model_type = new_class is not None # Special handling for ramp files for backwards compatibility if new_class is None: new_class = _class_from_ramp_type(hdulist, shape) # Or get the class from the reference file type and other header keywords if new_class is None: new_class = _class_from_reftype(hdulist, shape) # Or Get the class from the shape if new_class is None: new_class = _class_from_shape(hdulist, shape) # Throw an error if these attempts were unsuccessful if new_class is None: raise TypeError("Can't determine datamodel class from argument to open") # Log a message about how the model was opened if file_name: log.debug(f'Opening {file_name} as {new_class}') else: log.debug(f'Opening as {new_class}') # Actually open the model model = new_class(init, **kwargs) # Close the hdulist if we opened it if file_to_close is not None: # TODO: We need a better solution than messing with DataModel # internals. model._file_references.append(_FileReference(file_to_close)) if not has_model_type: class_name = new_class.__name__.split('.')[-1] if file_name: warnings.warn(f"model_type not found. Opening {file_name} as a {class_name}", NoTypeWarning) try: delattr(model.meta, 'model_type') except AttributeError: pass return model