2

I am making a program that searches the computer for .fts and .fits files in which it opens the file and retrieves info that corresponds to a specific keyword in the header and renames the file to that keyword.

I am having a problem where i keep receiving a KeyError becasue a header keyword I am searching for is not found in the file. Is there a way around this? I want to be able to search various keywords and do something even if that key word does not exist in the file.

Here is code:

from astropy.io import fits
import os

for i in os.listdir(os.getcwd()):
if i.endswith(".fits") or i.endswith(".fts"): 

    hdulist = fits.open(i)

    DATEOBS_header = hdulist[0].header['DATE-OBS'] 
    EXPTIME_header = int(round(hdulist[0].header['EXPTIME']))
    CCDTEMP_header = int(round(hdulist[0].header['CCD-TEMP']))
    XBINNING_header = hdulist[0].header['XBINNING']
    FILTER_header = hdulist[0].header['FILTER']
    IMAGETYP_header = hdulist[0].header['IMAGETYP']
    OBJECT_header = hdulist[0].header['OBJECT']

    DATEandTIME = DATEOBS_header[0:]
    YEAR = DATEandTIME[0:4]
    MONTH = DATEandTIME[5:7]
    DAY = DATEandTIME[8:10]

    #TIME = DATEOBS_header[11:] 
    HOUR = DATEandTIME[11:13]
    MINUTE = DATEandTIME[14:16]
    SECONDS = DATEandTIME[17:]

    DATE = str(YEAR) + str(MONTH) + str(DAY) + 'at' + str(HOUR) + str(MINUTE) + str(SECONDS) 

    if IMAGETYP_header == 'Light Frame':
        newname = str(OBJECT_header) + '_' + str(DATE) + '_' + str(CCDTEMP_header) + 'temp_' + str(XBINNING_header) + 'bin_' + str(EXPTIME_header) + 'exptime_' + str(FILTER_header) + '.fits'

    if IMAGETYP_header == 'Dark Frame':
        newname = 'Dark_' + str(DATE) + 'at' + str(TIME) + '_' + str(CCDTEMP_header) + 'temp_' + str(XBINNING_header) + 'bin_' + str(EXPTIME_header) + 'exptime' + '.fits'

    if IMAGETYP_header == 'Flat Field':
        newname = 'Flat_' + str(DATE) + 'at' + str(TIME) + '_' + str(CCDTEMP_header) + 'temp_' + str(XBINNING_header) + 'bin_' + str(EXPTIME_header) + 'exptime_' + str(FILTER_header) + '.fits'

    prevname = i
    os.rename(prevname, newname)

    hdulist.close()

    continue
else:
    continue

This is the Error I get:

Traceback (most recent call last):
  File "glo1.py", line 9, in <module>
    DATEOBS_header = hdulist[0].header['DATE-OBS'] 
  File "/home/luisgeesb/.local/lib/python2.7/site-packages/astropy/io/fits/header.py", line 151, in __getitem__
card = self._cards[self._cardindex(key)]
  File "/home/luisgeesb/.local/lib/python2.7/site-packages/astropy/io/fits/header.py", line 1723, in _cardindex
raise KeyError("Keyword %r not found." % keyword)
KeyError: "Keyword 'DATE-OBS' not found."
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
  • 1
    It sounds like you need to perform some exception handling – Dillon Benson Mar 25 '16 at 06:36
  • 3
    https://docs.python.org/3.5/tutorial/errors.html#handling-exceptions –  Mar 25 '16 at 06:43
  • You can also use a default value using something like `DATEOBS_header = hdulist[0].header.get('DATE-OBS', some_default_value)`. –  Mar 25 '16 at 06:44
  • Possible duplicate of [Check if a given key already exists in a dictionary](http://stackoverflow.com/questions/1602934/check-if-a-given-key-already-exists-in-a-dictionary) – Mp0int Mar 25 '16 at 06:53
  • Also similar: http://stackoverflow.com/questions/11041405/why-dict-getkey-instead-of-dictkey – Mp0int Mar 25 '16 at 06:57
  • 2
    Technically dict-related questions are not duplicates of this question, because the FITS `Header` object is not a `dict` (see http://docs.astropy.org/en/stable/io/fits/api/headers.html#header). Behavior-wise it is as close to `dict` as possible so most answers related to `dict` would apply, but this isn't necessarily obvious. – Iguananaut Mar 25 '16 at 09:26

2 Answers2

4

To prevent these kinds of exceptions from stopping your program, you can either catch them, like this:

try:
    DATEOBS_header = hdulist[0].header['DATE-OBS']
except KeyError:
    DATEOBS_header = None

Or, use the .get() method of dictionaries, which checks if a key exists and if it doesn't returns a default value, instead of raising an exception. The default value returned is None.

If you do this, you will also need to set some sensible defaults, or catch those cases where you are casting the values (since you cannot cast None).

Finally, whenever you are reading from files - you should always assume the data is malformed/junk and do a bit of defensive programming. In your code, you are assuming that the values returned for CCDTEMP is a number, but what if the file is corrupted or has a blank? Your application doesn't handle this case.

Here is some code that attempts to catch as many errors as possible:

DATEOBS_header = hdulist[0].header.get('DATE-OBS') 
XBINNING_header = hdulist[0].header.get('XBINNING')
FILTER_header = hdulist[0].header.get('FILTER')
IMAGETYP_header = hdulist[0].header.get('IMAGETYP')
OBJECT_header = hdulist[0].header.get('OBJECT')

# For these two, you need to either set a default
# Here I am setting the default to 0,           ------------v
EXPTIME_header = int(round(hdulist[0].header.get('EXPTIME', 0)))


# Or you need to check for a value :
ccdtemp_value = hdulist[0].header.get('CCD-TEMP')
try:
   ccdtemp_value = int(round(ccdtemp_value))
except ValueError:
   # This means, the value was either None (header does not exist)
   # or it was something that can't be converted to a number
   # since it cannot be converted to a number, we do not know
   # if the value is None or something like an empty string,
   # so we explicitly set the value to None
   ccdtemp_value = None
CCDTEMP_header = ccdtemp_value
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
  • when setting a default value, will it return the default value if the keyword is not found ? For example, in the code above where it says 'ccdtemp_value = hdulist[0].header.get('CCD-TEMP')' if CCD-TEMP is not found it will return 0 ? – Luis Garcia Mar 28 '16 at 05:05
  • The default return value if the key is not found is `None`, so if you want it to be zero, you need to pass it in, like this: `ccdtemp_value = hdulist[0].header.get('CCD-TEMP', 0)` – Burhan Khalid Mar 28 '16 at 05:33
0

Assuming hdulist[0].header gives you a dict instance, you can do something like

DATEOBS_header = hdulist[0].header.get('DATE-OBS')

Which would return a None if the key 'DATE-OBS' does not exist.

See https://docs.python.org/2/library/stdtypes.html#dict.get for more details.

woozyking
  • 4,880
  • 1
  • 23
  • 29
  • 1
    `hdulist[0].header` is not a dict or dict subclass, but it acts similar. –  Mar 25 '16 at 06:45