Package gavo :: Package stc :: Module utypeast
[frames] | no frames]

Source Code for Module gavo.stc.utypeast

  1  """ 
  2  Parse utype sets into ASTs. 
  3   
  4  The rough plan is to build an ElementTree from a sequence of 
  5  utype/value pairs (as returned by utypegen.getUtypes).  This 
  6  ElementTree can then be used to build an AST using stcxast.  The ElementTree 
  7  contains common.ColRefs and thus cannot be serialized to an XML string. 
  8   
  9  Most of the magic happens in utypeParseToTree, where the utypes are 
 10  dissected; it is important that the utypes sequence passed to this 
 11  is sorted such that utypes for things below an STC-X node are actually 
 12  immediately below the utype pair for their parent. 
 13  """ 
 14   
 15  #c Copyright 2008-2019, the GAVO project 
 16  #c 
 17  #c This program is free software, covered by the GNU GPL.  See the 
 18  #c COPYING file in the source distribution. 
 19   
 20   
 21  from gavo import utils 
 22  from gavo.stc import common 
 23  from gavo.stc import stcxast 
 24  from gavo.utils import ElementTree 
 25   
 26   
27 -def parseUtype(utype):
28 if utype is None: 29 return None 30 return tuple(utype.split(":")[-1].split("."))
31 32
33 -class _Attribute(object):
34 """a "value" for utypePairsToTree that causes an attribute to be set 35 on an element. 36 37 This is something a morph function would return. 38 """
39 - def __init__(self, name, value):
40 self.name, self.value = name, value
41 42
43 -class _Child(object):
44 """a "value" for utypesParisToTree that causes a child to be appended 45 46 This is for morph functions on substitution groups. 47 """
48 - def __init__(self, name, value):
49 self.name, self.value = name, value
50 51
52 -def _unifyTuples(fromTuple, toTuple):
53 """returns a pair fromTail, toTail of tuples to bring fromTuple to toTuple. 54 55 This is done such that fromTuple-fromTuple+toTail=toTuple for "appending" 56 semantics. 57 """ 58 if toTuple is None: 59 return (), () 60 prefixLen = utils.commonPrefixLength(fromTuple, toTuple) 61 return fromTuple[prefixLen:], toTuple[prefixLen:]
62 63
64 -def _replaceLastWithValue(utype, value):
65 yield ".".join(parseUtype(utype)[:-1])+"."+value, None
66
67 -def _makeCoordFlavor(utype, value):
68 # in addition to fixing syntax, we give a default for coord_naxis. 69 # User settings would overwrite that. 70 for pair in _replaceLastWithValue(utype, value): 71 yield pair 72 yield None, _Attribute("coord_naxes", "2")
73
74 -def _makeAttributeMaker(attName):
75 def makeAttribute(utype, value): 76 yield None, _Attribute(attName, value)
77 return makeAttribute 78
79 -def _makeParentAttributeMaker(attName):
80 def makeAttribute(utype, value): 81 yield ".".join(parseUtype(utype)[:-1]), _Attribute(attName, value)
82 return makeAttribute 83
84 -def _makeChildMaker(childName):
85 def makeChild(utype, value): 86 yield None, _Child(childName, value)
87 return makeChild 88 89
90 -def _replaceUtype(utype):
91 def replacer(_, value): 92 yield utype, value
93 return replacer 94
95 -def _appendFragment(frag):
96 def appender(orig, value): 97 yield "%s.%s"%(orig, frag), value
98 return appender 99
100 -def _ignore(utype, value):
101 if False: 102 yield None
103 104 105 _utypeMorphers = { 106 'AstroCoordSystem.RedshiftFrame.ReferencePosition': _replaceLastWithValue, 107 'AstroCoordSystem.RedshiftFrame.value_type': 108 _makeParentAttributeMaker("value_type"), 109 'AstroCoordSystem.SpaceFrame.CoordFlavor': _makeCoordFlavor, 110 'AstroCoordSystem.SpaceFrame.CoordFlavor.coord_naxes': 111 _makeAttributeMaker("coord_naxes"), 112 'AstroCoordSystem.SpaceFrame.CoordRefFrame': _replaceLastWithValue, 113 'AstroCoordSystem.SpaceFrame.CoordRefFrame.Equinox': 114 _replaceUtype('AstroCoordSystem.SpaceFrame.Equinox'), 115 'AstroCoordSystem.SpaceFrame.ReferencePosition': _replaceLastWithValue, 116 'AstroCoordSystem.SpectralFrame.ReferencePosition': _replaceLastWithValue, 117 'AstroCoordSystem.TimeFrame.ReferencePosition': _replaceLastWithValue, 118 'AstroCoordSystem.href': _makeParentAttributeMaker( 119 utils.ElementTree.QName(common.XlinkNamespace, "href")), 120 'AstroCoordSystem.SpaceFrame.ReferencePosition.PlanetaryEphem': 121 _makeChildMaker("PlanetaryEphem"), 122 'AstroCoordSystem.TimeFrame.ReferencePosition.PlanetaryEphem': 123 _makeChildMaker("PlanetaryEphem"), 124 'AstroCoordSystem.SpectralFrame.ReferencePosition.PlanetaryEphem': 125 _makeChildMaker("PlanetaryEphem"), 126 'AstroCoordSystem.RedshiftFrame.ReferencePosition.PlanetaryEphem': 127 _makeChildMaker("PlanetaryEphem"), 128 'AstroCoords.Time.TimeInstant': _appendFragment('ISOTime'), 129 'AstroCoords.TimeInterval.StartTime': _appendFragment('ISOTime'), 130 'AstroCoords.TimeInterval.EndTime': _appendFragment('ISOTime'), 131 'AstroCoords.Position1D.Epoch.yearDef': _makeParentAttributeMaker("yearDef"), 132 'AstroCoords.Position2D.Epoch.yearDef': _makeParentAttributeMaker("yearDef"), 133 'AstroCoords.Position3D.Epoch.yearDef': _makeParentAttributeMaker("yearDef"), 134 'DataModel.Uri': _ignore, 135 'DataModel.Name': _ignore, 136 'DataModel.Version': _ignore, 137 } 138
139 -def utypePairsToTree(utypes, nameQualifier=stcxast.STCElement):
140 """returns an ElementTree from a sequence of (utype, value) pairs. 141 142 nameQualifier(str) -> anything is a function producing element names. 143 144 The utypes are processed as they come in. In practice this means 145 you should sort them (or similar). 146 147 The utype can be none, meaning "Use last node". 148 """ 149 utypes = list(utypes) 150 root = ElementTree.Element(nameQualifier("STCSpec")) 151 curParts, elementStack = (), [root] 152 for parts, val in ((parseUtype(u), v) for u, v in utypes): 153 toClose, toOpen = _unifyTuples(curParts, parts) 154 if toClose or toOpen: # move in utype tree 155 curParts = parts 156 157 for elName in toClose: 158 elementStack.pop() 159 for elName in toOpen: 160 elementStack.append( 161 ElementTree.SubElement(elementStack[-1], nameQualifier(elName))) 162 163 # _Attributes get special handling 164 if isinstance(val, _Attribute): 165 elementStack[-1].attrib[val.name] = val.value 166 elif isinstance(val, _Child): 167 ElementTree.SubElement(elementStack[-1], 168 nameQualifier(val.name)).text = val.value 169 170 171 # All other values go to the element content; if nothing was 172 # opened or closed, add another node rather than clobber the 173 # last one. 174 else: 175 if not toClose and not toOpen: 176 elementStack.pop() 177 elementStack.append(ElementTree.SubElement( 178 elementStack[-1], nameQualifier(curParts[-1]))) 179 elementStack[-1].text = val 180 return root
181 182
183 -def morphUtypes(morphers, utypeSeq):
184 """returns a morphed sequence of utype/value pairs. 185 186 morphers is a dictionary of utypes to handling generators. Each of 187 those most take a utype and a value and generate utype/value pairs. 188 189 This is used here to fix the abominations where system elements become 190 values in utype representation. 191 """ 192 for index, (k, v) in enumerate(utypeSeq): 193 if k in morphers: 194 for pair in morphers[k](k, v): 195 yield pair 196 else: 197 yield (k, v)
198 199
200 -def _iterSortedUtypes(utypeSeq):
201 """returns a sorted sequence of utype, value pairs from utypeSeq 202 203 The result also has the abominable "stc:" cut off. 204 """ 205 return sorted((key.split(":")[-1], value) 206 for key, value in utypeSeq)
207 208
209 -def parseFromUtypes(utypeSeq):
210 """returns an STC AST for a sequence of utype-value pairs. 211 """ 212 eTree = utypePairsToTree( 213 morphUtypes(_utypeMorphers, 214 _iterSortedUtypes(utypeSeq))) 215 res = stcxast.parseFromETree(eTree)[0][1] 216 return res
217