Home | Trees | Indices | Help |
|
---|
|
1 """ 2 "Output drivers" for various formats, for the use of form-like renderers. 3 4 TODO: Tar and the output format widget should go somewhere else; the 5 rest should be done by RESPONSEFORMAT and formats. Then this module 6 should die. 7 """ 8 9 #c Copyright 2008-2019, the GAVO project 10 #c 11 #c This program is free software, covered by the GNU GPL. See the 12 #c COPYING file in the source distribution. 13 14 15 import os 16 17 from nevow import inevow 18 from nevow import static 19 from nevow import tags as T 20 from twisted.internet import threads 21 22 from gavo import base 23 from gavo import formats 24 from gavo import utils 25 from gavo.formats import csvtable #noflake: format registration 26 from gavo.formats import jsontable #noflake: format registration 27 from gavo.formats import fitstable #noflake: format registration 28 from gavo.formats import texttable #noflake: format registration 29 from gavo.formats import geojson #noflake: format registration 30 from gavo.imp.formal import types as formaltypes 31 from gavo.imp.formal.util import render_cssid 32 from gavo.protocols import products 33 from gavo.svcs import customwidgets 34 from gavo.svcs import streaming 35 from gavo.web import producttar 36 37 __docformat__ = "restructuredtext en"41 """A base class for objects producing formatted output. 42 43 ServiceResults are constructed with a context and the service. 44 On renderHTTP, they will spawn a thread to compute the service 45 result (usually, an rsc.Data instance) and hand that over 46 to _formatOutput. 47 48 All methods on these objects are class methods -- they are never 49 instanciated. 50 51 Deriving classes can override 52 53 - _formatOutput(result, ctx) -- receives the service result and 54 has to format it. 55 - canWrite(colSeq) -- a that returns true when a seq of columns 56 can be serialized by this service result. 57 - code -- an identifier used in HTTP query strings to select the format 58 - label (optional) -- a string that is used in HTML forms to select 59 the format (defaults to label). 60 - compute -- if False, at least the form renderer will not run 61 the service (this is when you just return a container). 62 """ 63 64 compute = True 65 code = None 66 label = None 67 68 @classmethod 71 72 @classmethod 77 78 @classmethod8184 """A ResultFormatter for VOTables. 85 86 The VOTables come as attachments, i.e., if all goes well the form 87 will just stand as it is. 88 """ 89 code = "VOTable" 90 91 @classmethod10393 request = inevow.IRequest(ctx) 94 if base.getMetaText(data.original.getPrimaryTable(), "_queryStatus" 95 )=="OVERFLOW": 96 fName = "truncated_votable.xml" 97 else: 98 fName = "votable.xml" 99 request.setHeader("content-type", base.votableType) 100 request.setHeader('content-disposition', 101 'attachment; filename=%s'%fName) 102 return streaming.streamVOTable(request, data)106 """returns data as a FITS binary table. 107 """ 108 code = "FITS" 109 label = "FITS table" 110 111 @classmethod135113 if base.getMetaText(data.original.getPrimaryTable(), "_queryStatus" 114 )=="OVERFLOW": 115 return "truncated_data.fits", "application/x-fits" 116 else: 117 return "data.fits", "application/x-fits"118 119 @classmethod121 return threads.deferToThread(fitstable.makeFITSTableFile, data.original 122 ).addCallback(cls._serveFile, data, ctx)123 124 @classmethod126 request = inevow.IRequest(ctx) 127 name, mime = cls.getTargetName(data) 128 request.setHeader("content-type", mime) 129 request.setHeader('content-disposition', 130 'attachment; filename=%s'%name) 131 static.FileTransfer(open(filePath), os.path.getsize(filePath), 132 request) 133 os.unlink(filePath) 134 return request.deferred138 code = "TSV" 139 label = "Text (with Tabs)" 140 141 @classmethod151143 request = inevow.IRequest(ctx) 144 content = texttable.getAsText(data.original) 145 request.setHeader('content-disposition', 146 'attachment; filename=table.tsv') 147 request.setHeader("content-type", "text/tab-separated-values") 148 request.setHeader("content-length", len(content)) 149 request.write(content) 150 return ""154 code = "txt" 155 label = "Text (fixed columns)" 156 157 @classmethod167159 request = inevow.IRequest(ctx) 160 request.setHeader("content-type", "text/plain") 161 162 def produceData(destFile): 163 formats.formatData("txt", data.original, 164 request, acquireSamples=False)165 166 return streaming.streamOut(produceData, request)171 code = "CSV" 172 label = "CSV" 173 174 @classmethod186176 request = inevow.IRequest(ctx) 177 request.setHeader('content-disposition', 178 'attachment; filename=table.csv') 179 request.setHeader("content-type", "text/csv;header=present") 180 181 def produceData(destFile): 182 formats.formatData("csv_header", data.original, 183 request, acquireSamples=False)184 185 return streaming.streamOut(produceData, request)189 code = "JSON" 190 label = "JSON" 191 192 @classmethod204194 request = inevow.IRequest(ctx) 195 request.setHeader('content-disposition', 196 'attachment; filename=table.json') 197 request.setHeader("content-type", "application/json") 198 199 def produceData(destFile): 200 formats.formatData("json", data.original, 201 request, acquireSamples=False)202 203 return streaming.streamOut(produceData, request)207 """delivers a tar of products requested. 208 """ 209 code = "tar" 210 211 @classmethod223 224 225 ################# Helpers 226 227 228 _getFormat = utils.buildClassResolver(ServiceResult, 229 globals().values(), key=lambda obj: obj.code)213 queryMeta = data.queryMeta 214 request = inevow.IRequest(ctx) 215 return producttar.getTarMaker().deliverProductTar( 216 data, request, queryMeta)217 218 @classmethod233 try: 234 return _getFormat(formatName) 235 except KeyError: 236 raise base.ValidationError("Unknown format '%s'."%formatName, 237 "_OUTPUT")238241 """A widget that offers various output options in close cooperation 242 with gavo.js and QueryMeta. 243 244 The javascript provides options for customizing output that non-javascript 245 users will not see. Also, formal doesn't see any of these. See gavo.js 246 for details. 247 248 This widget probably only makes sense in the Form renderer and thus 249 should probably go there. 250 """333252 self.service = service 253 self.typeOb = typeOb 254 self._computeAvailableFields(queryMeta) 255 self._computeAvailableFormats(queryMeta)256258 """sets the availableFormats property. 259 260 This is a helper for the constructor, inspecting serviceresults' globals(). 261 """ 262 outputFields = self.service.getCurOutputFields( 263 queryMeta, 264 raiseOnUnknown=False) 265 self.availableFormats = [ 266 (code, format.getLabel()) 267 for code, format in _getFormat.registry.iteritems() 268 if format.canWrite(outputFields)]269271 """computes the fields a Core provides but are not output by 272 the service by default. 273 274 This of course only works if the core defines its output table. 275 Otherwise, availableFields is an empty list. 276 """ 277 self.availableFields = [] 278 core = self.service.core 279 if (not core.outputTable 280 or self.service.getProperty("noAdditionals", False)): 281 return 282 coreNames = set(f.name for f in core.outputTable) 283 defaultNames = set([f.name 284 for f in self.service.getHTMLOutputFields( 285 queryMeta, 286 ignoreAdditionals=True, 287 raiseOnUnknown=False)]) 288 289 for key in coreNames-defaultNames: 290 try: 291 self.availableFields.append((core.outputTable.getColumnByName(key), 292 key in queryMeta["additionalFields"])) 293 except KeyError: # Core returns fields not in its table, 294 # probably computes them 295 pass296298 """returns an ul element containing form material for additional output 299 columns. 300 """ 301 checkLiterals = {True: "checked", False: None} 302 fields = [] 303 for column, checked in sorted( 304 self.availableFields, key=lambda p:p[0].name): 305 fields.append(T.tr[ 306 T.td[ 307 T.input(type="checkbox", name="_ADDITEM", value=column.key, 308 style="width:auto", 309 checked=checkLiterals[checked])], 310 T.td(style="vertical-align:middle")[ 311 " %s -- %s"%(column.name, column.description)]]) 312 return T.table(id="addSelection")[fields]313315 res = T.div(id=render_cssid("_OUTPUT"), style="position:relative")[ 316 customwidgets.SelectChoice(formaltypes.String(), 317 options=self.availableFormats, 318 noneOption=("HTML", "HTML")).render(ctx, "_FORMAT", args, errors)( 319 onchange="output_broadcast(this.value)")] 320 321 if self.availableFields: 322 res[ 323 T.div(title="Additional output column selector", 324 id=render_cssid("_ADDITEMS"), 325 style="visibility:hidden;position:absolute;")[ 326 self._makeAdditionalSelector()]] 327 return res328 329 renderImmutable = render # This is a lost case 330332 return args.get("_FORMAT", ["HTML"])[0]
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Thu May 2 07:29:09 2019 | http://epydoc.sourceforge.net |