Source code for msumastro.header_processing.fitskeyword
import logging
from astropy.io.fits import Header
from astropy.io.fits import PrimaryHDU
logger = logging.getLogger(__name__)
__all__ = ['FITSKeyword']
[docs]class FITSKeyword(object):
"""
Represents a FITS keyword, which may have several synonyms.
Parameters
----------
name : str, optional
Name of the keyword; case insensitive
value : str or numeric type, optional
Value of the keyword; this class imposes no constraints on the type of
the keyword but if you intend to save the value in a FITS header you
should be aware of the restrictions the FITS standard places on keyword
values.
comment : str, optional
Description of the keyword.
synonyms : str or list of str, optional
Synonyms for this keyword. Synonyms are to look for a value in a FITS
header and to set multiple keywords to the same value in a FITS header.
"""
def __init__(self, name=None, value=None, comment=None, synonyms=None):
self._hdr = Header()
self.name = name
self.value = value
self.comment = comment
if synonyms is None:
self.synonyms = []
else:
self.synonyms = synonyms
def __str__(self):
if self.value is None:
value_string = ''
else:
value_string = str(self.value)
return ("%s = %s / %s \n with synonyms: %s" %
(self.name.upper(), value_string, self.comment,
",".join([str(syn).upper() for syn in self.synonyms])))
def _set_keyword_case(self, keyword):
return keyword.upper()
@property
def name(self):
"""
Primary name of the keyword.
"""
return self._name
@name.setter
def name(self, keyword_name):
self._name = self._set_keyword_case(keyword_name)
# set synonyms again in case the new name matches one the synonyms
self.synonyms = self.synonyms
@property
def synonyms(self):
"""
List of synonyms for the keyword.
"""
try:
return self._synonyms
except AttributeError:
return None
@synonyms.setter
def synonyms(self, inp_synonyms):
if not inp_synonyms:
self._synonyms = []
return
if isinstance(inp_synonyms, str):
synonym_list = [inp_synonyms]
elif isinstance(inp_synonyms, list):
synonym_list = set(inp_synonyms)
else:
raise ValueError(
'Synonyms must either be a string or a list of strings')
synonym_list = [self._set_keyword_case(syn) for syn in synonym_list]
self._synonyms = [synonym for synonym in synonym_list
if synonym != self.name]
return
@property
def names(self):
"""
All names, including synonyms, for this keyword, as a list.
"""
all_names = [self.name]
if self.synonyms:
all_names.extend(self.synonyms)
return all_names
[docs] def history_comment(self, with_name=None):
"""
Produce a string describing changes to the keyword value.
Parameters
----------
with_name : str, optional
Name to use for the keyword in the history comment. Default is the
`name` attribute of the `Keyword`.
"""
if with_name is None:
with_name = self.name
return "Updated keyword %s to value %s" % (with_name.upper(),
self.value)
[docs] def add_to_header(self, hdu_or_header, with_synonyms=True, history=False):
"""
Add keyword to FITS header.
Parameters
----------
hdu_or_header : astropy.io.fits.Header or astropy.io.fits.PrimaryHDU
Header/HDU to which the keyword is to be added.
with_synonyms : bool, optional
Control whether a keyword is added for each of the synonyms for the
keyword. Default is True.
history : bool, optional
Control whether a history comment is added to the header; if True
a history comment is added for *each* of the keyword names added
to the header, including synonyms.
"""
if isinstance(hdu_or_header, PrimaryHDU):
header = hdu_or_header.header
elif isinstance(hdu_or_header, Header):
header = hdu_or_header
else:
raise ValueError('argument must be a fits Primary HDU or header')
header[self.name] = (self.value, self.comment)
if history:
header.add_history(self.history_comment())
if with_synonyms and self.synonyms:
for synonym in self.synonyms:
header[synonym] = (self.value, self.comment)
if history:
header.add_history(self.history_comment(with_name=synonym))
[docs] def set_value_from_header(self, hdu_or_header):
"""
Set value of keyword from FITS header.
Values are obtained from the header by looking for the keyword by its
primary name and any synonyms. If multiple values are found they are
checked for consistency.
Parameters
----------
hdu_or_header: astropy.io.fits.Header or astrop.io.fits.PrimaryHDU
Header from which the keyword value should be taken.
Raises
------
ValueError
If `hdu_or_header` is of the wrong type, or the keyword
(or synonyms) are not found in the header, or multiple
non-identical values are found.
"""
if isinstance(hdu_or_header, PrimaryHDU):
header = hdu_or_header.header
elif isinstance(hdu_or_header, Header):
header = hdu_or_header
else:
raise ValueError('argument must be a fits Primary HDU or header')
values = []
for name in self.names:
try:
values.append(header[name])
except KeyError:
continue
if values:
if len(set(values)) > 1:
error_msg = 'Found multiple values for keyword %s:\nValues: %s'
raise ValueError(error_msg %
(','.join(self.names),
','.join([str(v) for v in values])))
self.value = values[0]
else:
raise ValueError('Keyword not found in header: %s' % self)