Package gavo :: Package grammars :: Module fitsprodgrammar
[frames] | no frames]

Source Code for Module gavo.grammars.fitsprodgrammar

  1  """ 
  2  A grammar to parse from primary FITS headers. 
  3   
  4  This grammar will return exactly one row per source. 
  5  """ 
  6   
  7  #c Copyright 2008-2019, the GAVO project 
  8  #c 
  9  #c This program is free software, covered by the GNU GPL.  See the 
 10  #c COPYING file in the source distribution. 
 11   
 12   
 13  import gzip 
 14  import re 
 15   
 16  from gavo import base 
 17  from gavo.grammars.common import Grammar, RowIterator, MapKeys 
 18  from gavo.utils import fitstools 
 19  from gavo.utils import pyfits 
 20   
 21   
 22   
23 -class FITSProdIterator(RowIterator):
24 - def _iterRows(self):
25 if self.grammar.qnd: 26 return self._parseFast() 27 else: 28 return self._parseSlow()
29
30 - def _hackBotchedCard(self, card, res):
31 """tries to make *anything* from a card pyfits doesn't want to parse. 32 33 In reality, I'm just trying to cope with oversized keywords. 34 """ 35 mat = re.match(r"([^\s=]*)\s*=\s*([^/]+)", card.image) 36 if mat: 37 res[mat.group(1)] = mat.group(2).strip() 38 else: # Card beyond recognition, ignore 39 pass
40
41 - def _buildDictFromHeader(self, header):
42 res = {} 43 for card in header.cards: 44 try: 45 res[card.keyword.replace("-", "_")] = card.value 46 except (ValueError, pyfits.VerifyError): 47 self._hackBotchedCard(card, res) 48 49 res["header_"] = header 50 51 if self.grammar.hdusField: 52 res[self.grammar.hdusField] = fitstools.openFits(self.sourceToken) 53 return self.grammar.mapKeys.doMap(res)
54
55 - def _parseFast(self):
56 fName = self.sourceToken 57 if fName.endswith(".gz"): 58 f = gzip.open(fName) 59 else: 60 f = open(fName) 61 header = fitstools.readPrimaryHeaderQuick(f, 62 maxHeaderBlocks=self.grammar.maxHeaderBlocks) 63 f.close() 64 yield self._buildDictFromHeader(header)
65
66 - def _parseSlow(self):
67 fName = self.sourceToken 68 hdus = fitstools.openFits(fName) 69 hduIndex = int(self.grammar.hdu) 70 71 # fix extind to handle compressed FITSes transparently 72 header = hdus[fitstools.fixImageExtind(hdus, hduIndex)].header 73 hdus.close() 74 yield self._buildDictFromHeader(header)
75
76 - def getLocator(self):
77 return self.sourceToken
78 79
80 -class FITSProdGrammar(Grammar):
81 r"""A grammar that returns FITS-headers as dictionaries. 82 83 This is the grammar you want when one FITS file corresponds to one 84 row in the destination table. 85 86 The keywords of the grammar record are the cards in the primary 87 header (or some other hdu using the same-named attribute). "-" in 88 keywords is replaced with an underscore for easier @-referencing. 89 You can use a mapKeys element to effect further name cosmetics. 90 91 This grammar should handle compressed FITS images transparently if 92 set qnd="False". This means that you will essentially get the headers 93 from the second extension for those even if you left hdu="0". 94 95 The original header is preserved as the value of the header\_ key. This 96 is mainly intended for use WCS use, as in ``wcs.WCS(@header_)``. 97 98 If you have more complex structures in your FITS files, you can get access 99 to the pyfits HDU using the hdusField attribute. With 100 ``hdusField="_H"``, you could say things like ``@_H[1].data[10][0]`` 101 to get the first data item in the tenth row in the second HDU. 102 """ 103 name_ = "fitsProdGrammar" 104 105 _qnd = base.BooleanAttribute("qnd", default=True, description= 106 "Use a hack to read the FITS header more quickly. This only" 107 " works for the primary HDU", copyable=True) 108 _hduIndex = base.IntAttribute("hdu", default=0, 109 description="Take the header from this HDU. You must say qnd='False'" 110 " for this to take effect.", copyable=True) 111 _mapKeys = base.StructAttribute("mapKeys", childFactory=MapKeys, 112 default=None, copyable=True, description="Prescription for how to" 113 " map header keys to grammar dictionary keys") 114 _hdusAttr = base.UnicodeAttribute("hdusField", default=None, 115 description="If set, the complete pyfits HDU list for the FITS" 116 " file is returned in this grammar field.", copyable=True) 117 _maxHeaderBlocks = base.IntAttribute("maxHeaderBlocks", 118 default=40, copyable=True, description="Stop looking for" 119 " FITS END cards and raise an error after this many blocks." 120 " You may need to raise this for people dumping obscene amounts" 121 " of data or history into headers.") 122 123 rowIterator = FITSProdIterator 124
125 - def onElementComplete(self):
126 if self.mapKeys is None: 127 self.mapKeys = base.makeStruct(MapKeys) 128 self._onElementCompleteNext(FITSProdGrammar)
129