Source code for subpixal.utils

# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
This module provides utility functions for use by :py:mod:`subpixal` module.

:Author: Mihai Cara (for help, contact `HST Help Desk <https://hsthelp.stsci.edu>`_)

:License: :doc:`LICENSE`

"""
import tempfile

import numpy as np
from astropy.io import fits

from . import __version__, __version_date__


__all__ = ['parse_file_name', 'py2round', 'get_ext_list']


[docs]def parse_file_name(image_name): """ Parse image file names including possible extensions. Parameters ---------- image_name : str An image file name and (optionally) extension specification, e.g.: ``'j1234567q_flt.fits[1]'``, ``'j1234568q_flt.fits[sci,2]'``, etc. Returns ------- file_name : str File name itself **without** extension specification. ext : tuple, int, None A tuple of two elements: *extension name* (a string) and *extension version* (an integer number), e.g., ``('SCI', 2)``. Alternatively, an extention can be specified using an integer *extension number*. When no extension was specified, ``ext`` returns `None`. Examples -------- >>> import subpixal >>> subpixal.utils.parse_file_name('j1234568q_flt.fits[sci,2]') ('j1234568q_flt.fits', ('sci', 2)) """ numbra = image_name.count('[') numket = image_name.count(']') if numbra + numket > 0: image_name = image_name.rstrip() if ((numbra == 1 and ']' != image_name[-1]) or numbra != numket or numbra > 1): raise ValueError("Misplaced, unbalanced, or nested " "brackets have been detected.") if numbra == 0: return image_name, None idx_bra = image_name.find('[') if idx_bra == 0: raise ValueError("No valid file name provided.") # separate file name from FITS extension specification: file_name = image_name[:idx_bra] extcomp = image_name[idx_bra + 1:-1].split(',') if len(extcomp) == 1: # extension specification is an integer extension number: try: extnum = int(extcomp[0]) except ValueError: raise ValueError("Invalid extension specification.") return file_name, extnum elif len(extcomp) == 2: # extension specification is a tuple of extension name and version: try: extnum = int(extcomp[1]) except ValueError: raise ValueError("Invalid extension specification.") extname = extcomp[0].strip() return file_name, (extname, extnum) else: raise ValueError("Invalid extension specification.")
[docs]def get_ext_list(image, extname='SCI'): """ Return a list of all extension versions of `extname` extensions. `image` can be either a file name or a `astropy.io.fits.HDUList` object. This function returns a list of fully qualified extensions: a list of tuples of the form (``'extname'``, ``'extver'``). Examples -------- >>> get_ext_list('j9irw1rqq_flt.fits') [('SCI', 1), ('SCI', 2)] """ if not isinstance(extname, str): raise TypeError("Argument 'extname' must be either a string " "indicating the value of the 'EXTNAME' keyword of the " "extensions whose versions are to be returned.") extname = extname.upper() close = False try: if isinstance(img, (str, bytes)): image = fits.open(image, mode='update') close = True elif not isinstance(image, fits.HDUList): raise TypeError("Argument 'imgage' must be either a file name, " "or an astropy.io.fits.HDUList object.") ext = [] for e in hdulist: hdr = e.header if 'EXTNAME' in hdr and hdr['EXTNAME'].upper() == extname: ext.append((extname, hdr['EXTVER'] if 'EXTVER' in hdr else 1)) except: raise finally: if close: image.close() return ext
[docs]def py2round(x): """ This function returns a rounded up value of the argument, similar to Python 2. """ if hasattr(x, '__iter__'): rx = np.empty_like(x) m = x >= 0.0 rx[m] = np.floor(x[m] + 0.5) m = np.logical_not(m) rx[m] = np.ceil(x[m] - 0.5) return rx else: if x >= 0.0: return np.floor(x + 0.5) else: return np.ceil(x - 0.5)
def _create_tmp_fits_file(image, prefix='tmp_'): tmpf = None close_image = False try: if isinstance(image, np.ndarray): image = fits.PrimaryHDU(image) elif not isinstance(image, fits.HDUList): image = fits.open(image) close_image = True tmpf = tempfile.NamedTemporaryFile( mode='wb', suffix='.fits', prefix=prefix, dir='./', delete=True, ) image.writeto(tmpf) tmpf.file.flush() tmpf.file.seek(0) except: if tmpf is not None: tmpf.close() raise finally: if close_image: image.close() return tmpf