Package gavo :: Package svcs :: Module core
[frames] | no frames]

Source Code for Module gavo.svcs.core

  1  """ 
  2  Cores are the standard object for computing things in the DC. 
  3   
  4  This module also contains the registry for cores.  If you want to 
  5  be able to refer to cores from within an RD, you need to enter your 
  6  core here. 
  7   
  8  Cores return pairs of a type and a payload.  Renderers should normally 
  9  be prepared to receive (None, OutputTable) and (mime/str, data/str), 
 10  though individual cores might return other stuff (and then only 
 11  work with select renderers). 
 12   
 13  In general, the input table definition is mandatory, i.e., you have 
 14  to come up with it.  Services do this either ad-hoc from input from 
 15  the web or using an inputDD. 
 16   
 17  The output table, on the other hand, is "advisory", mainly for registry 
 18  and documentation purposes ("I *could* return this").  In particular 
 19  DBBasedCores will usually adapt to the service's wishes when it comes 
 20  to the output table structure, not to mention the ADQL core.  This doesn't 
 21  hurt since whatever is returned comes with structure documentation of 
 22  its own. 
 23   
 24  Cores may also want to adapt to renderers.  This is a bit of a hack to 
 25  support, e.g., form and scs within a single service, which avoids 
 26  two different VOResource records just because of slightly differning 
 27  input definitions. 
 28   
 29  The interface here is the adaptForRenderer method.  It takes a single 
 30  argument, the renderer, either as a simple name resolvable in the renderer 
 31  registry, or as a renderer instance or class.  It must return a new 
 32  core instance. 
 33   
 34  Currently, two mechanisms for core adaptation are in place: 
 35   
 36  (1) generically, inputKeys can have properties onlyForRenderer and  
 37  notForRenderer with the obvious semantics. 
 38   
 39  (2) cores that have condDescs may adapt by virtue of condDesc's  
 40  adaptForRenderer method. 
 41  """ 
 42   
 43  #c Copyright 2008-2019, the GAVO project 
 44  #c 
 45  #c This program is free software, covered by the GNU GPL.  See the 
 46  #c COPYING file in the source distribution. 
 47   
 48   
 49  from gavo import base 
 50  from gavo import rsc 
 51  from gavo import rscdef 
 52  from gavo import utils 
 53  from gavo.svcs import inputdef 
 54  from gavo.svcs import outputdef 
 55   
 56   
 57  CORE_REGISTRY = { 
 58  #       elementName -> module (without gavo.), class name 
 59          "adqlCore": ("protocols.adqlglue", "ADQLCore"), 
 60          "customCore": ("svcs.customcore", "CustomCore"), 
 61          "datalinkCore": ("protocols.datalink", "DatalinkCore"), 
 62          "dbCore": ("svcs.standardcores", "DBCore"), 
 63          "debugCore": ("svcs.core", "DebugCore"), 
 64          "fancyQueryCore": ("svcs.standardcores", "FancyQueryCore"), 
 65          "fixedQueryCore": ("svcs.standardcores", "FixedQueryCore"), 
 66          "nullCore": ("svcs.standardcores", "NullCore"), 
 67          "productCore": ("protocols.products", "ProductCore"), 
 68          "pythonCore": ("svcs.customcore", "PythonCore"), 
 69          "registryCore": ("registry.oaiinter", "RegistryCore"), 
 70          "scsCore": ("protocols.scs", "SCSCore"), 
 71          "siapCutoutCore": ("protocols.siap", "SIAPCutoutCore"), 
 72          "ssapCore": ("protocols.ssap", "SSAPCore"), 
 73          "tapCore": ("protocols.tap", "TAPCore"), 
 74          "uploadCore": ("svcs.uploadcores", "UploadCore"), 
 75  } 
 76   
 77   
78 -def getCore(name):
79 if name not in CORE_REGISTRY: 80 raise base.NotFoundError(name, "core", "registred cores") 81 cls = utils.loadInternalObject(*CORE_REGISTRY[name]) 82 if cls.name_!=name: 83 raise base.ReportableError("Internal Error: Core %s is registred" 84 " under the wrong name."%name, 85 hint="This is probably a typo in svcs.core; it needs" 86 " to be fixed there") 87 return cls
88 89
90 -class _OutputTableFactory(object):
91 """The childFactory for a core's outputTable. 92 93 On call, it will return a slightly amended copy of the 94 queried table. 95 96 This means that you must set the queried table before mentioning the 97 outputs. 98 """ 99 name_ = "outputTable" 100
101 - def __call__(self, parent):
107 108
109 -class Core(base.Structure):
110 """A definition of the "active" part of a service. 111 112 A core will receive input from a renderer in the form of a ``svcs.CoreArgs`` 113 (see `Core Args`_). A core will return a table or perhaps directly 114 data as discussed in `DaCHS' Service Interface`_ . 115 116 The abstract core element will never occur in resource descriptors. See 117 `Cores Available`_ for concrete cores. Use the names of the concrete 118 cores in RDs. 119 """ 120 name_ = "core" 121 122 inputTableXML = None 123 outputTableXML = None 124 125 # the cached prototype of the output table, filled in by 126 # _OutputTableFactory 127 _ot_prototype = None 128 129 _rd = rscdef.RDAttribute() 130 _inputTable = base.StructAttribute("inputTable", 131 default=base.NotGiven, 132 childFactory=inputdef.InputTD, 133 description="Description of the input data", 134 copyable=True) 135 136 _outputTable = base.StructAttribute("outputTable", 137 default=base.NotGiven, 138 childFactory=_OutputTableFactory(), 139 description="Table describing what fields are available from this core", 140 copyable=True) 141 142 _original = base.OriginalAttribute() 143 144 _properties = base.PropertyAttribute(copyable=True) 145
146 - def __init__(self, parent, **kwargs):
147 if self.inputTableXML is not None: 148 if "inputTable" not in kwargs: 149 kwargs["inputTable"] = base.parseFromString( 150 inputdef.InputTD, self.inputTableXML) 151 152 base.Structure.__init__(self, parent, **kwargs)
153
154 - def __repr__(self):
155 return "<%s at %s>"%(self.__class__.__name__, id(self))
156
157 - def __str__(self):
158 return repr(self)
159
160 - def completeElement(self, ctx):
161 self._completeElementNext(Core, ctx) 162 self.initialize() 163 if self.inputTable is base.NotGiven: 164 self.inputTable = base.makeStruct(inputdef.InputTD) 165 if self.outputTable is base.NotGiven: 166 self.outputTable = self._outputTable.childFactory(self)
167
168 - def initialize(self):
169 """override to configure the custom core before use. 170 171 This is typically where you pull input or output tables 172 from the RD in customCores. Actual DaCHS code should use 173 completeElement as usual. 174 """
175
176 - def adaptForRenderer(self, renderer):
177 """returns a core object tailored for renderer. 178 """ 179 newIT = self.inputTable.adaptForRenderer(renderer) 180 if newIT is self.inputTable: 181 return self 182 else: 183 return self.change(inputTable=newIT)
184
185 - def run(self, service, inputData, queryMeta):
186 raise NotImplementedError("%s cores are missing the run method"% 187 self.__class__.__name__)
188
189 - def makeUserDoc(self):
190 return ("Polymorphous core element. May contain any of the cores" 191 " mentioned in `Cores Available`_ .")
192 193
194 -class DebugCore(Core):
195 """a core that returns its arguments stringified in a table. 196 197 You need to provide an external input tables for these. 198 """ 199 name_ = "debugCore" 200 201 outputTableXML = """ 202 <outputTable> 203 <outputField name="arg_key" type="text" 204 description="Name of an input parameter"/> 205 <outputField name="arg_value" type="text" 206 description="(First) value passed (or None)"/> 207 </outputTable>""" 208
209 - def run(self, service, inputTable, queryMeta):
210 rows = [] 211 for par in inputTable.inputTD: 212 if par.type=="file": 213 value = inputTable.args[par.name][1].read() 214 else: 215 value = inputTable.args[par.name] 216 rows.append({"arg_key": par.name, "arg_value": utils.safe_str(value)}) 217 return rsc.TableForDef(self.outputTable, rows=rows)
218