def test_check_works_for_zipped(input_file):
    filename, expected = input_file
    filename += '.gz'  # extra zip extension

    filetype = check(filename)

    assert filetype == expected
Example #2
0
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
Example #6
0
def test_non_seekable_object():
    with pytest.raises(ValueError):
        check(object())
Example #7
0
def test_unsupported_filename(filename):
    with pytest.raises(ValueError):
        check(filename)
Example #8
0
def test_supported_filename(filename, expected_filetype):
    assert check(filename) == expected_filetype
Example #9
0
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