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
26
27
28
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
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
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 """
57 type.__init__(cls, name, bases, dict)
58 cls._createHandlesMethods(dict.values())
59
61 for item in items:
62 for name in getattr(item, "handles", ()):
63 setattr(cls, "_gener_"+name, item)
64
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
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
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
100 yield prefix, child[0]
101
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
121
133
140
160
163 rootType = "AstroCoordSystem.RedshiftFrame"
164
166 for pair in _CoordFrameMaker.iterUtypes(self, node, prefix):
167 yield pair
168
171 rootType = "AstroCoordSystem.SpectralFrame"
172
175 @handles(["ISOTime", "JDTime", "MJDTime"])
181
184 rootType = "AstroCoords.Time.TimeInstant"
185
187 rootType = "AstroCoordArea.TimeInterval.StartTime"
188
190 rootType = "AstroCoordArea.TimeInterval.StopTime"
191
196 return ".".join(u for u in utypes if u)
197
198
199
200
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