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

Source Code for Module gavo.stc.utypegen

  1  """ 
  2  Generating a utype/value sequence for ASTs. 
  3   
  4  Yet another insane serialization for an insane data model.  Sigh. 
  5   
  6  The way we come up with the STC utypes here is described in an IVOA note. 
  7   
  8  Since the utypes are basically xpaths into STC-X, there is not terribly 
  9  much we need to do here.  However, due to STC-X being a nightmare, 
 10  certain rules need to be formulated what utypes to generate. 
 11   
 12  Here, we use UtypeMakers for this.  There's a default UtypeMaker 
 13  that implements the basic algorithm of the STC note (in iterUtypes, 
 14  a method that yields all utype/value pairs for an STC-X node, which 
 15  is a stanxml Element). 
 16   
 17  To customize what is being generated, define _gener_<child name> 
 18  methods, where <child name> is a key within the dictionaries 
 19  returned by stanxml.Element's getChildDict method. 
 20   
 21  To make the definition of the _gener_ methods easer, there's 
 22  the handles decorator that you can pass a list of such child names. 
 23  """ 
 24   
 25  #c Copyright 2008-2019, the GAVO project 
 26  #c 
 27  #c This program is free software, covered by the GNU GPL.  See the 
 28  #c COPYING file in the source distribution. 
 29   
 30   
 31  from gavo import utils 
 32  from gavo.stc import common 
 33  from gavo.stc import stcxgen 
 34  from gavo.stc.stcx import STC 
35 36 37 #################### utype maker definition 38 39 -def handles(seq):
40 """is a decorator for UtypeMaker methods. 41 42 It adds a "handles" attribute as evaluated by AutoUtypeMaker. 43 """ 44 def deco(meth): 45 meth.handles = seq 46 return meth
47 return deco 48
49 50 -class UtypeMaker_t(type):
51 """A metaclass to facilite easy definition of UtypeMakers. 52 53 This metaclass primarily operates on the handles hints left by the 54 decorator. 55 """
56 - def __init__(cls, name, bases, dict):
57 type.__init__(cls, name, bases, dict) 58 cls._createHandlesMethods(dict.values())
59
60 - def _createHandlesMethods(cls, items):
61 for item in items: 62 for name in getattr(item, "handles", ()): 63 setattr(cls, "_gener_"+name, item)
64
65 66 -class UtypeMaker(object):
67 """An object encapsulating information on how to turn a stanxml 68 node into a sequence of utype/value pairs. 69 70 This is an "universal" base, serving as a simple default. 71 Any class handling specific node types must fill out at least 72 the rootType attribute, giving the utype at which this UtypeMaker 73 should kick in. 74 75 By default, utype/value pairs are only returned for nonempty 76 element content. To change this, define _gener_<name>(node, 77 prefix) -> iterator methods. 78 79 The actual pairs are retrieved by calling iterUtypes(node, 80 parentPrefix). 81 """ 82 __metaclass__ = UtypeMaker_t 83 84 # attributes that don't get serialized to utypes per spec 85 bannedAttributes = set("id frame_id coord_system_id unit" 86 " pos_angle_unit pos_unit spectral_unit time_unit" 87 " vel_time_unit gen_unit xsi:type ucd xmlns:stc xmlns xmlns:xsi" 88 " xsi:schemaLocation".split()) 89 90 rootType = None 91
92 - def _generPlain(self, name, child, prefix):
93 childType = utypejoin(prefix, name) 94 maker = _getUtypeMaker(childType) 95 for item in child: 96 for pair in maker.iterUtypes(item, childType): 97 yield pair
98
99 - def _gener__colRef(self, name, child, prefix):
100 yield prefix, child[0]
101
102 - def iterUtypes(self, node, prefix):
103 children = node.getChildDict() 104 if node.text_: 105 yield prefix, node.text_ 106 for attName, name in node.iterAttNames(): 107 if name not in self.bannedAttributes: 108 val = getattr(node, attName) 109 if val is not None: 110 yield "%s.%s"%(prefix, name.split(":")[-1]), val 111 for name, child in children.iteritems(): 112 handler = getattr(self, "_gener_"+name, self._generPlain) 113 for pair in handler(name, child, prefix): 114 yield pair
115
116 117 -class _NotImplementedUtypeMaker(UtypeMaker):
118 - def _generPlain(self, name, child, prefix):
119 raise common.STCNotImplementedError("Cannot create utypes for %s yet."% 120 self.utypeFrag)
121
122 123 #################### utype specific makers 124 125 126 -class _CoordFrameMaker(UtypeMaker):
127 @handles(common.stcRefPositions)
128 - def _refPos(self, name, child, prefix):
129 if name!='UNKNOWNRefPos': 130 yield utypejoin(prefix, "ReferencePosition"), name 131 for pair in self._generPlain("ReferencePosition", child, prefix): 132 yield pair
133
134 135 -class TimeFrameMaker(_CoordFrameMaker):
136 rootType = "AstroCoordSystem.TimeFrame" 137 @handles(common.stcTimeScales)
138 - def _timeScale(self, name, child, prefix):
139 yield utypejoin(prefix, "TimeScale"), name
140
141 142 -class SpaceFrameMaker(_CoordFrameMaker):
143 rootType = "AstroCoordSystem.SpaceFrame" 144 145 @handles(common.stcSpaceRefFrames)
146 - def _coordFrame(self, name, child, prefix):
147 myPrefix = utypejoin(prefix, "CoordRefFrame") 148 yield myPrefix, name 149 for pair in self._generPlain(None, child, myPrefix): 150 yield pair
151 152 @handles(common.stcCoordFlavors)
153 - def _coordFlavor(self, name, child, prefix):
154 prefix = utypejoin(prefix, "CoordFlavor") 155 yield prefix, name 156 if child: 157 if child[0].coord_naxes!="2": 158 yield utypejoin(prefix, "coord_naxes"), child[0].coord_naxes 159 yield utypejoin(prefix, "handedness"), child[0].handedness
160
161 162 -class RedshiftFrameMaker(_CoordFrameMaker):
163 rootType = "AstroCoordSystem.RedshiftFrame" 164
165 - def iterUtypes(self, node, prefix):
166 for pair in _CoordFrameMaker.iterUtypes(self, node, prefix): 167 yield pair
168
169 170 -class SpectralFrameMaker(_CoordFrameMaker):
171 rootType = "AstroCoordSystem.SpectralFrame"
172
173 174 -class _TimeValueMaker(UtypeMaker):
175 @handles(["ISOTime", "JDTime", "MJDTime"])
176 - def _absoluteTime(self, name, child, prefix):
177 yield utypejoin(prefix, "xtype"), name 178 for item in child: 179 for pair in self.iterUtypes(item, prefix): 180 yield pair
181
182 183 -class TimeInstantMaker(_TimeValueMaker):
184 rootType = "AstroCoords.Time.TimeInstant"
185
186 -class StartTimeMaker(_TimeValueMaker):
187 rootType = "AstroCoordArea.TimeInterval.StartTime"
188
189 -class StopTimeMaker(_TimeValueMaker):
190 rootType = "AstroCoordArea.TimeInterval.StopTime"
191
192 193 #################### toplevel code 194 195 -def utypejoin(*utypes):
196 return ".".join(u for u in utypes if u)
197 198 199 # A resolver of element names to their handling classes. For most 200 # elements, this is just a plain UtypeMaker. 201 _getUtypeMaker = utils.buildClassResolver( 202 UtypeMaker, 203 globals().values(), 204 default=UtypeMaker(), 205 instances=True, 206 key=lambda obj:obj.rootType)
207 208 209 -def getUtypes(ast, includeDMURI=False, suppressXtype=True):
210 """returns a lists of utype/value pairs for an STC AST. 211 212 If you pass includeDMURI, a utype/value pair for the data model URI will 213 be generated in addition to what comes in from ast. 214 """ 215 cst = stcxgen.astToStan(ast, STC.STCSpec) 216 utypes = [] 217 for utype, val in _getUtypeMaker("").iterUtypes(cst, ""): 218 if val is None or val=='': 219 continue 220 if suppressXtype: 221 if utype.endswith("xtype"): 222 continue 223 utypes.append(("stc:"+utype, val)) 224 if includeDMURI: 225 utypes.append(("stc:DataModel.URI", common.STCNamespace)) 226 utypes.sort() 227 return utypes
228