Package gavo :: Package web :: Module examplesrender
[frames] | no frames]

Source Code for Module gavo.web.examplesrender

  1  """ 
  2  The renderer for VOSI examples, plus the docutils extensions provided for 
  3  them. 
  4   
  5  If you have a renderer that needs custom text roles or directives, read the 
  6  docstring of misctricks.RSTExtensions and add whatever roles you need below, 
  7  more or less like this:: 
  8   
  9          misctricks.RSTExtensions.makeTextRole("niceRole") 
 10   
 11  Only go through RSTExtensions, as these will make sure HTML postprocessing 
 12  happens as required. 
 13   
 14  The reason we keep the roles here and not in the renderer modules where they'd 
 15  logically belong (and where they should be documented in the renderer 
 16  docstrings) is that we don't want docutils imports all over the place. 
 17  """ 
 18   
 19  #c Copyright 2008-2019, the GAVO project 
 20  #c 
 21  #c This program is free software, covered by the GNU GPL.  See the 
 22  #c COPYING file in the source distribution. 
 23   
 24   
 25  import re 
 26   
 27  from docutils import nodes 
 28  from docutils import utils as rstutils 
 29  from docutils.parsers import rst 
 30   
 31  from lxml import etree 
 32   
 33  from nevow import rend 
 34   
 35  from gavo import utils 
 36  from gavo.utils import misctricks 
 37  from .. import base 
 38  from .. import svcs 
 39  from . import grend 
40 41 42 -class _Example(rend.DataFactory, base.MetaMixin):
43 """A formatted example. 44 45 These get constructed with example meta items and glue these 46 together with the nevow rendering system. 47 48 An important role of this is the translation from the HTML class 49 attribute values we use in ReStructuredText to the RDFa properties 50 in the output. The first class that has a matching property wins. 51 52 There's the special exmeta render function that works like metahtml, 53 except it's using the example's meta. 54 """
55 - def __init__(self, exMeta):
56 base.MetaMixin.__init__(self) 57 self.setMetaParent(exMeta) 58 self.original = exMeta 59 self.title = base.getMetaText(self.original, "title", propagate=False) 60 self.htmlId = re.sub("\W", "", self.title)
61
62 - def data_id(self, ctx, data):
63 return self.htmlId
64
65 - def _getTranslatedHTML(self):
66 rawHTML = self.original.getContent("html") 67 parsed = etree.fromstring( 68 '<div typeof="example" id="%s" resource="#%s">\n' 69 '<h2 property="name">%s</h2>\n' 70 '%s\n</div>'%( 71 self.htmlId, 72 self.htmlId, 73 utils.escapePCDATA(self.title), 74 rawHTML)) 75 actOnClasses = set(misctricks.RSTExtensions.classToProperty) 76 77 for node in parsed.iterfind(".//*[@class]"): 78 nodeClasses = set(node.attrib["class"].split()) 79 properties = " ".join(misctricks.RSTExtensions.classToProperty[c] 80 for c in actOnClasses & nodeClasses) 81 if properties: 82 node.set("property", properties) 83 84 # For now, I assume element content always is intended to 85 # be the relation object (rather than a href that might 86 # be present and would take predence by RDFa 87 if "href" in node.attrib or "src" in node.attrib: 88 node.set("content", node.text) 89 90 return etree.tostring(parsed, encoding="utf-8").decode("utf-8")
91
92 - def data_rendered(self, ctx, data):
93 if not hasattr(self.original, "renderedDescription"): 94 self.original.renderedDescription = self._getTranslatedHTML() 95 return self.original.renderedDescription
96
97 98 -class Examples(grend.CustomTemplateMixin, grend.ServiceBasedPage):
99 r"""A renderer for examples for service usage. 100 101 This renderer formats _example meta items in its service. Its output 102 is XHTML compliant to VOSI examples; clients can parse it to, 103 for instance, fill forms for service operation or display examples 104 to users. 105 106 The examples make use of RDFa to convey semantic markup. To see 107 what kind of semantics is contained, try 108 http://www.w3.org/2012/pyRdfa/Overview.html and feed it the 109 example URL of your service. 110 111 The default content of _example is ReStructuredText, and really, not much 112 else makes sense. An example for such a meta item can be viewed by 113 executing ``gavo admin dumpDF //userconfig``, in the tapexamples STREAM. 114 115 To support annotation of things within the example text, DaCHS 116 defines several RST extensions, both interpreted text roles (used like 117 ``:role-name:`content with blanks```) and custom directives (used 118 to mark up blocks introduced by a single line like 119 ``.. directive-name ::`` (the blanks before and after the 120 directive name are significant). 121 122 Here's the custom interpreted text roles: 123 124 * *dl-id*: An publisher DID a service returns data for (used in 125 datalink examples) 126 * *taptable*: A (fully qualified) table name a TAP example query is 127 (particularly) relevant for; in HTML, this is also a link 128 to the table description. 129 * *genparam*: A "generic parameter" as defined by DALI. The values 130 of these have the form param(value), e.g., :genparam:\`POS(32,4)\`. 131 Right now, not parantheses are allowed in the value. Complain 132 if this bites you. 133 134 These are the custom directives: 135 136 * *tapquery*: The query discussed in a TAP example. 137 138 Examples for how to write TAP examples are in the userconfig.rd 139 distributed with DaCHS. Examples for Datalink examples can 140 be found in the GAVO RDs feros/q and califa/q3. 141 """ 142 name = "examples" 143 checkedRenderer = False 144 customTemplate = svcs.loadSystemTemplate("examples.html") 145 146 @classmethod
147 - def isCacheable(self, segments, request):
148 return True
149
150 - def render_title(self, ctx, data):
151 return ctx.tag["Examples for %s"%base.getMetaText( 152 self.service, "title")]
153
154 - def data_examples(self, ctx, data):
155 """returns _Example instances from the service metadata. 156 """ 157 for ex in self.service.iterMeta("_example"): 158 yield _Example(ex)
159
160 161 ################## RST extensions 162 # When you add anything here, be sure to update the Examples docstring 163 # above. 164 165 166 ### ...for TAP 167 168 -def _taptableRoleFunc(name, rawText, text, lineno, inliner, 169 options={}, content=[]):
170 tablename = nodes.emphasis(rawText, text) 171 tablename["classes"] = ["dachs-ex-taptable"] 172 descr = nodes.reference(u"\u2197", u"\u2197", 173 refuri="/tableinfo/%s"%text) 174 descr["classes"] = ["taptable-link"] 175 return [descr, tablename], []
176 177 misctricks.RSTExtensions.makeTextRole("taptable", _taptableRoleFunc, 178 propertyName="table") 179 del _taptableRoleFunc
180 181 -class _TAPQuery(rst.Directive):
182 has_content = True 183
184 - def run(self):
185 body = "\n".join(self.content) 186 res = nodes.literal_block(body, body) 187 res["classes"] = ["dachs-ex-tapquery"] 188 return [res]
189 190 misctricks.RSTExtensions.addDirective("tapquery", _TAPQuery, 191 propertyName="query") 192 del _TAPQuery 193 194 195 ### ...for datalink 196 197 misctricks.RSTExtensions.makeTextRole("dl-id")
198 199 ### ...for DALI-style generic parameters 200 201 -def _genparamRoleFunc(name, rawText, text, lineno, inliner, 202 options={}, content=[]):
203 mat = re.match(r"([^(]+)\(([^)]*)\)$", text) 204 if not mat: 205 msg = inliner.reporter.error( 206 "genparam content must have the form key(value); %s does not."%text) 207 return [inliner.problematic(rawText, rawText, msg)], [msg] 208 209 key, value = mat.groups() 210 211 formatted = """<span property="generic-parameter" typeof="keyval" 212 class="generic-parameter"> 213 <span property="key" class="genparam-key">%s</span> = 214 <span property="value" class="genparam-value">%s</span> 215 </span>"""%( 216 utils.escapePCDATA(rstutils.unescape(key, 1)), 217 utils.escapePCDATA(rstutils.unescape(value, 1))) 218 res = nodes.raw( 219 rawsource=rawText, 220 text=formatted, 221 format='html') 222 return [res], []
223 224 misctricks.RSTExtensions.makeTextRole("genparam", _genparamRoleFunc) 225 del _genparamRoleFunc 226