Package gavo :: Package protocols :: Module ssap
[frames] | no frames]

Source Code for Module gavo.protocols.ssap

  1  """ 
  2  The SSAP core and supporting code. 
  3   
  4  """ 
  5   
  6  #c Copyright 2008-2019, the GAVO project 
  7  #c 
  8  #c This program is free software, covered by the GNU GPL.  See the 
  9  #c COPYING file in the source distribution. 
 10   
 11   
 12  import itertools 
 13   
 14  from gavo import base 
 15  from gavo import rsc 
 16  from gavo import rscdef 
 17  from gavo import svcs 
 18  from gavo.protocols import datalink 
 19  from gavo.svcs import outputdef 
 20   
 21   
 22  RD_ID = "//ssap" 
 23  MS = base.makeStruct 
24 25 26 -def getRD():
27 return base.caches.getRD(RD_ID)
28
29 30 -class SSADescriptor(datalink.ProductDescriptor):
31 """SSA descriptors have ssaRow and limits attributes. 32 33 These both reference SSA results. ssaRow is the first result of 34 the query, which also provides the accref. limits is a table.Limits 35 instance for the total result set. 36 37 Warning: limits will be None if this is constructed with fromSSARow. 38 """ 39 ssaRow = None 40 41 @classmethod
42 - def fromSSARow(cls, ssaRow, paramDict):
43 """returns a descriptor from a row in an ssa table and 44 the params of that table. 45 46 Don't use this; the limits attribute will be {} for these. 47 """ 48 paramDict.update(ssaRow) 49 ssaRow = paramDict 50 res = cls.fromAccref(ssaRow["ssa_pubDID"], ssaRow['accref']) 51 res.ssaRow = ssaRow 52 res.limits = {} 53 return res
54 55 @classmethod
56 - def fromSSAResult(cls, ssaResult):
57 """returns a descriptor from an SSA query result (an InMemoryTable 58 instance). 59 """ 60 if not ssaResult.rows: 61 raise base.NotFoundError("any", "row", "ssa result for SODA block" 62 " generation") 63 res = cls.fromSSARow(ssaResult.rows[0], ssaResult.getParamDict()) 64 res.limits = ssaResult.getLimits() 65 res.pubDID = None 66 return res
67
68 69 -def _combineRowIntoOne(ssaRows):
70 """makes a "total row" from ssaRows. 71 72 In the resulting row, minima and maxima are representative of the 73 whole result set, and enumerated columns are set-valued. 74 75 This is useful when generating parameter metadata. 76 """ 77 # XXX TODO: shouldn't this be made more generic by using something like 78 # in user.info? 79 if not ssaRows: 80 raise base.ReportableError("Datalink meta needs at least one result row") 81 82 totalRow = ssaRows[0].copy() 83 totalRow["mime"] = set([totalRow["mime"]]) 84 calibs = set() 85 86 for row in ssaRows[1:]: 87 if row["ssa_specstart"]<totalRow["ssa_specstart"]: 88 totalRow["ssa_specstart"] = row["ssa_specstart"] 89 if row["ssa_specend"]>totalRow["ssa_specend"]: 90 totalRow["ssa_specend"] = row["ssa_specend"] 91 totalRow["mime"].add(row["mime"]) 92 calibs.add(row.get("ssa_fluxcalib", None)) 93 94 totalRow["collect_calibs"] = set(c for c in calibs if c is not None) 95 return totalRow
96
97 98 -def getDatalinkCore(dlSvc, ssaTable):
99 """returns a datalink core adapted for ssaTable. 100 101 dlSvc is the datalink service, ssaTable a non-empty SSA result table. 102 """ 103 allowedRendsForStealing = ["dlget"] #noflake: for stealVar downstack 104 desc = SSADescriptor.fromSSAResult(ssaTable) 105 return dlSvc.core.adaptForDescriptors(svcs.getRenderer("dlget"), [desc])
106
107 108 -class SSAPCore(svcs.DBCore):
109 """A core doing SSAP queries. 110 111 This core knows about metadata queries, version negotiation, and 112 dispatches on REQUEST. Thus, it may return formatted XML data 113 under certain circumstances. 114 115 Interpreted Properties: 116 117 * previews: If set to "auto", the core will automatically add a preview 118 column and fill it with the URL of the products-based preview. Other 119 values are not defined. 120 """ 121 name_ = "ssapCore" 122 123 outputTableXML = """ 124 <outputTable verbLevel="30"> 125 <property name="virtual">True</property> 126 <FEED source="//ssap#coreOutputAdditionals"/> 127 </outputTable>""" 128 129 previewColumn = base.parseFromString(svcs.OutputField, 130 '<outputField name="preview" type="text"' 131 ' ucd="meta.ref.url;datalink.preview" tablehead="Preview"' 132 ' description="URL of a preview for the dataset"' 133 ' select="NULL" displayHint="type=product" verbLevel="15"/>') 134 135 136 ############### Implementation of the service operations 137
138 - def onElementComplete(self):
139 self._onElementCompleteNext(SSAPCore) 140 if self.getProperty("previews", default=False)=="auto": 141 self.outputTable.columns.append(self.previewColumn)
142
143 - def _run_getTargetNames(self, service, inputTable, queryMeta):
144 with base.getTableConn() as conn: 145 table = rsc.TableForDef(self.queriedTable, create=False, 146 connection=conn) 147 destTD = base.makeStruct(outputdef.OutputTableDef, 148 parent_=self.queriedTable.parent, 149 id="result", onDisk=False, 150 columns=[self.queriedTable.getColumnByName("ssa_targname")]) 151 res = table.getTableForQuery(destTD, "", distinct=True) 152 res.noPostprocess = True 153 return res
154 159
160 - def _run_queryData(self, service, inputTable, queryMeta):
161 limitThroughTOP = inputTable.getParam("TOP") 162 if limitThroughTOP and limitThroughTOP<queryMeta["dbLimit"]: 163 queryMeta["dbLimit"] = limitThroughTOP 164 165 res = svcs.DBCore.run(self, service, inputTable, queryMeta) 166 if self.getProperty("previews", default=False)=="auto": 167 self._addPreviewLinks(res) 168 169 if service.hasProperty("datalink"): 170 # backwards compatibility: The datalink property on the service 171 # can name a datalink service. We don't want that any more, but 172 # for now copy it to the queried table (where it should be) 173 # XXX Deprecate around version 1.3 174 try: 175 res.getMeta("_associatedDatalinkService", raiseOnFail=True) 176 except base.NoMetaKey: 177 # No datalink metadata on the table yet, generate one from the property. 178 res.addMeta( 179 "_associatedDatalinkService.serviceId", 180 service.getProperty("datalink")) 181 res.addMeta( 182 "_associatedDatalinkService.idColumn", 183 "ssa_pubDID") 184 185 return res
186 187 ################ the main dispatcher 188
189 - def run(self, service, inputTable, queryMeta):
190 defaultRequest = service.getProperty("defaultRequest", "") 191 requestType = (inputTable.getParam("REQUEST") or defaultRequest).upper() 192 if requestType=="QUERYDATA": 193 return self._run_queryData(service, inputTable, queryMeta) 194 elif requestType=="GETTARGETNAMES": 195 return self._run_getTargetNames(service, inputTable, queryMeta) 196 else: 197 raise base.ValidationError("Missing or invalid value for REQUEST.", 198 "REQUEST")
199 200 201 _VIEW_COLUMNS_CACHE = []
202 203 -def iterViewColumns(context):
204 """returns a list of column objects for building the SSA view 205 mixin's columns. 206 207 The argument is the DaCHS RD parse context. 208 209 This is probably only useful for the //ssap#view mixin. The argument 210 is that mixin's context. This could go if we drop the hcd and mixc 211 mixins and instead have a normal STREAM with the columns, as it's really 212 only necessary to make columns from the stupid params and remove their 213 defaults. 214 215 This will always return the same column objects -- don't change them. 216 """ 217 if not _VIEW_COLUMNS_CACHE: 218 dontCopyAtts = frozenset(["value", "content_"]) 219 protoTable = context.getById("instance") 220 221 _VIEW_COLUMNS_CACHE.append([MS(rscdef.Column, 222 **c.getCopyableAttributes(ignoreKeys=dontCopyAtts)) 223 for c in itertools.chain( 224 protoTable.columns, protoTable.params)]) 225 226 return _VIEW_COLUMNS_CACHE[0]
227