pyratemp.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """
4 Small, simple and powerful template-engine for Python.
5 
6 A template-engine for Python, which is very simple, easy to use, small,
7 fast, powerful, modular, extensible, well documented and pythonic.
8 
9 See documentation for a list of features, template-syntax etc.
10 
11 :Version: 0.3.0
12 :Requires: Python >=2.6 / 3.x
13 
14 :Usage:
15  see class ``Template`` and examples below.
16 
17 :Example:
18 
19  Note that the examples are in Python 2; they also work in
20  Python 3 if you replace u"..." by "...", unicode() by str()
21  and partly "..." by b"...".
22 
23  quickstart::
24  >>> t = Template("hello @!name!@")
25  >>> print(t(name="marvin"))
26  hello marvin
27 
28  quickstart with a template-file::
29  # >>> t = Template(filename="mytemplate.tmpl")
30  # >>> print(t(name="marvin"))
31  # hello marvin
32 
33  generic usage::
34  >>> t = Template(u"output is in Unicode \\xe4\\xf6\\xfc\\u20ac")
35  >>> t #doctest: +ELLIPSIS
36  <...Template instance at 0x...>
37  >>> t()
38  u'output is in Unicode \\xe4\\xf6\\xfc\\u20ac'
39  >>> unicode(t)
40  u'output is in Unicode \\xe4\\xf6\\xfc\\u20ac'
41 
42  with data::
43  >>> t = Template("hello @!name!@", data={"name":"world"})
44  >>> t()
45  u'hello world'
46  >>> t(name="worlds")
47  u'hello worlds'
48 
49  # >>> t(note="data must be Unicode or ASCII", name=u"\\xe4")
50  # u'hello \\xe4'
51 
52  escaping::
53  >>> t = Template("hello escaped: @!name!@, unescaped: $!name!$")
54  >>> t(name='''<>&'"''')
55  u'hello escaped: &lt;&gt;&amp;&#39;&quot;, unescaped: <>&\\'"'
56 
57  result-encoding::
58  # encode the unicode-object to your encoding with encode()
59  >>> t = Template(u"hello \\xe4\\xf6\\xfc\\u20ac")
60  >>> result = t()
61  >>> result
62  u'hello \\xe4\\xf6\\xfc\\u20ac'
63  >>> result.encode("utf-8")
64  'hello \\xc3\\xa4\\xc3\\xb6\\xc3\\xbc\\xe2\\x82\\xac'
65  >>> result.encode("ascii")
66  Traceback (most recent call last):
67  ...
68  UnicodeEncodeError: 'ascii' codec can't encode characters in position 6-9: ordinal not in range(128)
69  >>> result.encode("ascii", 'xmlcharrefreplace')
70  'hello &#228;&#246;&#252;&#8364;'
71 
72  Python-expressions::
73  >>> Template('formatted: @! "%8.5f" % value !@')(value=3.141592653)
74  u'formatted: 3.14159'
75  >>> Template("hello --@!name.upper().center(20)!@--")(name="world")
76  u'hello -- WORLD --'
77  >>> Template("calculate @!var*5+7!@")(var=7)
78  u'calculate 42'
79 
80  blocks (if/for/macros/...)::
81  >>> t = Template("<!--(if foo == 1)-->bar<!--(elif foo == 2)-->baz<!--(else)-->unknown(@!foo!@)<!--(end)-->")
82  >>> t(foo=2)
83  u'baz'
84  >>> t(foo=5)
85  u'unknown(5)'
86 
87  >>> t = Template("<!--(for i in mylist)-->@!i!@ <!--(else)-->(empty)<!--(end)-->")
88  >>> t(mylist=[])
89  u'(empty)'
90  >>> t(mylist=[1,2,3])
91  u'1 2 3 '
92 
93  >>> t = Template("<!--(for i,elem in enumerate(mylist))--> - @!i!@: @!elem!@<!--(end)-->")
94  >>> t(mylist=["a","b","c"])
95  u' - 0: a - 1: b - 2: c'
96 
97  >>> t = Template('<!--(macro greetings)-->hello <strong>@!name!@</strong><!--(end)--> @!greetings(name=user)!@')
98  >>> t(user="monty")
99  u' hello <strong>monty</strong>'
100 
101  exists::
102  >>> t = Template('<!--(if exists("foo"))-->YES<!--(else)-->NO<!--(end)-->')
103  >>> t()
104  u'NO'
105  >>> t(foo=1)
106  u'YES'
107  >>> t(foo=None) # note this difference to 'default()'
108  u'YES'
109 
110  default-values::
111  # non-existing variables raise an error
112  >>> Template('hi @!optional!@')()
113  Traceback (most recent call last):
114  ...
115  TemplateRenderError: Cannot eval expression 'optional'. (NameError: name 'optional' is not defined)
116 
117  >>> t = Template('hi @!default("optional","anyone")!@')
118  >>> t()
119  u'hi anyone'
120  >>> t(optional=None)
121  u'hi anyone'
122  >>> t(optional="there")
123  u'hi there'
124 
125  # the 1st parameter can be any eval-expression
126  >>> t = Template('@!default("5*var1+var2","missing variable")!@')
127  >>> t(var1=10)
128  u'missing variable'
129  >>> t(var1=10, var2=2)
130  u'52'
131 
132  # also in blocks
133  >>> t = Template('<!--(if default("opt1+opt2",0) > 0)-->yes<!--(else)-->no<!--(end)-->')
134  >>> t()
135  u'no'
136  >>> t(opt1=23, opt2=42)
137  u'yes'
138 
139  >>> t = Template('<!--(for i in default("optional_list",[]))-->@!i!@<!--(end)-->')
140  >>> t()
141  u''
142  >>> t(optional_list=[1,2,3])
143  u'123'
144 
145 
146  # but make sure to put the expression in quotation marks, otherwise:
147  >>> Template('@!default(optional,"fallback")!@')()
148  Traceback (most recent call last):
149  ...
150  TemplateRenderError: Cannot eval expression 'default(optional,"fallback")'. (NameError: name 'optional' is not defined)
151 
152  setvar::
153  >>> t = Template('$!setvar("i", "i+1")!$@!i!@')
154  >>> t(i=6)
155  u'7'
156 
157  >>> t = Template('''<!--(if isinstance(s, (list,tuple)))-->$!setvar("s", '"\\\\\\\\n".join(s)')!$<!--(end)-->@!s!@''')
158  >>> t(isinstance=isinstance, s="123")
159  u'123'
160  >>> t(isinstance=isinstance, s=["123", "456"])
161  u'123\\n456'
162 
163 :Author: Roland Koebler (rk at simple-is-better dot org)
164 :Copyright: Roland Koebler
165 :License: MIT/X11-like, see __license__
166 
167 :RCS: $Id: pyratemp.py,v 1.12 2013/04/02 20:26:06 rk Exp $
168 """
169 from __future__ import unicode_literals
170 
171 __version__ = "0.3.0"
172 __author__ = "Roland Koebler <rk at simple-is-better dot org>"
173 __license__ = """Copyright (c) Roland Koebler, 2007-2013
174 
175 Permission is hereby granted, free of charge, to any person obtaining a copy
176 of this software and associated documentation files (the "Software"), to deal
177 in the Software without restriction, including without limitation the rights
178 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
179 copies of the Software, and to permit persons to whom the Software is
180 furnished to do so, subject to the following conditions:
181 
182 The above copyright notice and this permission notice shall be included in
183 all copies or substantial portions of the Software.
184 
185 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
186 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
188 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
189 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
190 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
191 IN THE SOFTWARE."""
192 
193 #=========================================
194 
195 import os, re, sys
196 if sys.version_info[0] >= 3:
197  import builtins
198  unicode = str
199  long = int
200 else:
201  import __builtin__ as builtins
202  from codecs import open
203 
204 #=========================================
205 # some useful functions
206 
207 #----------------------
208 # string-position: i <-> row,col
209 
210 def srow(string, i):
211  """Get line numer of ``string[i]`` in `string`.
212 
213  :Returns: row, starting at 1
214  :Note: This works for text-strings with ``\\n`` or ``\\r\\n``.
215  """
216  return string.count('\n', 0, max(0, i)) + 1
217 
218 def scol(string, i):
219  """Get column number of ``string[i]`` in `string`.
220 
221  :Returns: column, starting at 1 (but may be <1 if i<0)
222  :Note: This works for text-strings with ``\\n`` or ``\\r\\n``.
223  """
224  return i - string.rfind('\n', 0, max(0, i))
225 
226 def sindex(string, row, col):
227  """Get index of the character at `row`/`col` in `string`.
228 
229  :Parameters:
230  - `row`: row number, starting at 1.
231  - `col`: column number, starting at 1.
232  :Returns: ``i``, starting at 0 (but may be <1 if row/col<0)
233  :Note: This works for text-strings with '\\n' or '\\r\\n'.
234  """
235  n = 0
236  for _ in range(row-1):
237  n = string.find('\n', n) + 1
238  return n+col-1
239 
240 #----------------------
241 
243  """Convert all keys of the dict `d` to strings.
244  """
245  new_d = {}
246  for k, v in d.items():
247  new_d[str(k)] = v
248  return new_d
249 
250 #----------------------
251 
252 def dummy(*_, **__):
253  """Dummy function, doing nothing.
254  """
255  pass
256 
257 def dummy_raise(exception, value):
258  """Create an exception-raising dummy function.
259 
260  :Returns: dummy function, raising ``exception(value)``
261  """
262  def mydummy(*_, **__):
263  raise exception(value)
264  return mydummy
265 
266 #=========================================
267 # escaping
268 
269 (NONE, HTML, LATEX, MAIL_HEADER) = range(0, 4)
270 ESCAPE_SUPPORTED = {"NONE":None, "HTML":HTML, "LATEX":LATEX, "MAIL_HEADER":MAIL_HEADER}
271 
272 def escape(s, format=HTML):
273  """Replace special characters by their escape sequence.
274 
275  :Parameters:
276  - `s`: unicode-string to escape
277  - `format`:
278 
279  - `NONE`: nothing is replaced
280  - `HTML`: replace &<>'" by &...;
281  - `LATEX`: replace \#$%&_{}~^
282  - `MAIL_HEADER`: escape non-ASCII mail-header-contents
283  :Returns:
284  the escaped string in unicode
285  :Exceptions:
286  - `ValueError`: if `format` is invalid.
287 
288  :Uses:
289  MAIL_HEADER uses module email
290  """
291  #Note: If you have to make sure that every character gets replaced
292  # only once (and if you cannot achieve this with the following code),
293  # use something like "".join([replacedict.get(c,c) for c in s])
294  # which is about 2-3 times slower (but maybe needs less memory).
295  #Note: This is one of the most time-consuming parts of the template.
296  if format is None or format == NONE:
297  pass
298  elif format == HTML:
299  s = s.replace("&", "&amp;") # must be done first!
300  s = s.replace("<", "&lt;")
301  s = s.replace(">", "&gt;")
302  s = s.replace('"', "&quot;")
303  s = s.replace("'", "&#39;")
304  elif format == LATEX:
305  s = s.replace("\\", "\\x") #must be done first!
306  s = s.replace("#", "\\#")
307  s = s.replace("$", "\\$")
308  s = s.replace("%", "\\%")
309  s = s.replace("&", "\\&")
310  s = s.replace("_", "\\_")
311  s = s.replace("{", "\\{")
312  s = s.replace("}", "\\}")
313  s = s.replace("\\x","\\textbackslash{}")
314  s = s.replace("~", "\\textasciitilde{}")
315  s = s.replace("^", "\\textasciicircum{}")
316  elif format == MAIL_HEADER:
317  import email.header
318  try:
319  s.encode("ascii")
320  return s
321  except UnicodeEncodeError:
322  return email.header.make_header([(s, "utf-8")]).encode()
323  else:
324  raise ValueError('Invalid format (only None, HTML, LATEX and MAIL_HEADER are supported).')
325  return s
326 
327 #=========================================
328 
329 #-----------------------------------------
330 # Exceptions
331 
332 class TemplateException(Exception):
333  """Base class for template-exceptions."""
334  pass
335 
336 class TemplateParseError(TemplateException):
337  """Template parsing failed."""
338  def __init__(self, err, errpos):
339  """
340  :Parameters:
341  - `err`: error-message or exception to wrap
342  - `errpos`: ``(filename,row,col)`` where the error occured.
343  """
344  self.err = err
345  self.filename, self.row, self.col = errpos
346  TemplateException.__init__(self)
347  def __str__(self):
348  if not self.filename:
349  return "line %d, col %d: %s" % (self.row, self.col, str(self.err))
350  else:
351  return "file %s, line %d, col %d: %s" % (self.filename, self.row, self.col, str(self.err))
352 
354  """Template syntax-error."""
355  pass
356 
357 class TemplateIncludeError(TemplateParseError):
358  """Template 'include' failed."""
359  pass
360 
362  """Template rendering failed."""
363  pass
364 
365 #-----------------------------------------
366 # Loader
367 
369  """Load template from a string/unicode.
370 
371  Note that 'include' is not possible in such templates.
372  """
373  def __init__(self, encoding='utf-8'):
374  self.encoding = encoding
375 
376  def load(self, s):
377  """Return template-string as unicode.
378  """
379  if isinstance(s, unicode):
380  u = s
381  else:
382  u = s.decode(self.encoding)
383  return u
384 
386  """Load template from a file.
387 
388  When loading a template from a file, it's possible to including other
389  templates (by using 'include' in the template). But for simplicity
390  and security, all included templates have to be in the same directory!
391  (see ``allowed_path``)
392  """
393  def __init__(self, allowed_path=None, encoding='utf-8'):
394  """Init the loader.
395 
396  :Parameters:
397  - `allowed_path`: path of the template-files
398  - `encoding`: encoding of the template-files
399  :Exceptions:
400  - `ValueError`: if `allowed_path` is not a directory
401  """
402  if allowed_path and not os.path.isdir(allowed_path):
403  raise ValueError("'allowed_path' has to be a directory.")
404  self.path = allowed_path
405  self.encoding = encoding
406 
407  def load(self, filename):
408  """Load a template from a file.
409 
410  Check if filename is allowed and return its contens in unicode.
411 
412  :Parameters:
413  - `filename`: filename of the template without path
414  :Returns:
415  the contents of the template-file in unicode
416  :Exceptions:
417  - `ValueError`: if `filename` contains a path
418  """
419  if filename != os.path.basename(filename):
420  raise ValueError("No path allowed in filename. (%s)" %(filename))
421  filename = os.path.join(self.path, filename)
422 
423  f = open(filename, 'r', encoding=self.encoding)
424  u = f.read()
425  f.close()
426 
427  return u
428 
429 #-----------------------------------------
430 # Parser
431 
432 class Parser(object):
433  """Parse a template into a parse-tree.
434 
435  Includes a syntax-check, an optional expression-check and verbose
436  error-messages.
437 
438  See documentation for a description of the parse-tree.
439  """
440  # template-syntax
441  _comment_start = "#!"
442  _comment_end = "!#"
443  _sub_start = "$!"
444  _sub_end = "!$"
445  _subesc_start = "@!"
446  _subesc_end = "!@"
447  _block_start = "<!--("
448  _block_end = ")-->"
449 
450  # build regexps
451  # comment
452  # single-line, until end-tag or end-of-line.
453  _strComment = r"""%s(?P<content>.*?)(?P<end>%s|\n|$)""" \
454  % (re.escape(_comment_start), re.escape(_comment_end))
455  _reComment = re.compile(_strComment, re.M)
456 
457  # escaped or unescaped substitution
458  # single-line ("|$" is needed to be able to generate good error-messges)
459  _strSubstitution = r"""
460  (
461  %s\s*(?P<sub>.*?)\s*(?P<end>%s|$) #substitution
462  |
463  %s\s*(?P<escsub>.*?)\s*(?P<escend>%s|$) #escaped substitution
464  )
465  """ % (re.escape(_sub_start), re.escape(_sub_end),
466  re.escape(_subesc_start), re.escape(_subesc_end))
467  _reSubstitution = re.compile(_strSubstitution, re.X|re.M)
468 
469  # block
470  # - single-line, no nesting.
471  # or
472  # - multi-line, nested by whitespace indentation:
473  # * start- and end-tag of a block must have exactly the same indentation.
474  # * start- and end-tags of *nested* blocks should have a greater indentation.
475  # NOTE: A single-line block must not start at beginning of the line with
476  # the same indentation as the enclosing multi-line blocks!
477  # Note that " " and "\t" are different, although they may
478  # look the same in an editor!
479  _s = re.escape(_block_start)
480  _e = re.escape(_block_end)
481  _strBlock = r"""
482  ^(?P<mEnd>[ \t]*)%send%s(?P<meIgnored>.*)\r?\n? # multi-line end (^ <!--(end)-->IGNORED_TEXT\n)
483  |
484  (?P<sEnd>)%send%s # single-line end (<!--(end)-->)
485  |
486  (?P<sSpace>[ \t]*) # single-line tag (no nesting)
487  %s(?P<sKeyw>\w+)[ \t]*(?P<sParam>.*?)%s
488  (?P<sContent>.*?)
489  (?=(?:%s.*?%s.*?)??%send%s) # (match until end or i.e. <!--(elif/else...)-->)
490  |
491  # multi-line tag, nested by whitespace indentation
492  ^(?P<indent>[ \t]*) # save indentation of start tag
493  %s(?P<mKeyw>\w+)\s*(?P<mParam>.*?)%s(?P<mIgnored>.*)\r?\n
494  (?P<mContent>(?:.*\n)*?)
495  (?=(?P=indent)%s(?:.|\s)*?%s) # match indentation
496  """ % (_s, _e,
497  _s, _e,
498  _s, _e, _s, _e, _s, _e,
499  _s, _e, _s, _e)
500  _reBlock = re.compile(_strBlock, re.X|re.M)
501 
502  # "for"-block parameters: "var(,var)* in ..."
503  _strForParam = r"""^(?P<names>\w+(?:\s*,\s*\w+)*)\s+in\s+(?P<iter>.+)$"""
504  _reForParam = re.compile(_strForParam)
505 
506  # allowed macro-names
507  _reMacroParam = re.compile(r"""^\w+$""")
508 
509 
510  def __init__(self, loadfunc=None, testexpr=None, escape=HTML):
511  """Init the parser.
512 
513  :Parameters:
514  - `loadfunc`: function to load included templates
515  (i.e. ``LoaderFile(...).load``)
516  - `testexpr`: function to test if a template-expressions is valid
517  (i.e. ``EvalPseudoSandbox().compile``)
518  - `escape`: default-escaping (may be modified by the template)
519  :Exceptions:
520  - `ValueError`: if `testexpr` or `escape` is invalid.
521  """
522  if loadfunc is None:
523  self._load = dummy_raise(NotImplementedError, "'include' not supported, since no 'loadfunc' was given.")
524  else:
525  self._load = loadfunc
526 
527  if testexpr is None:
528  self._testexprfunc = dummy
529  else:
530  try: # test if testexpr() works
531  testexpr("i==1")
532  except Exception as err:
533  raise ValueError("Invalid 'testexpr'. (%s)" %(err))
534  self._testexprfunc = testexpr
535 
536  if escape not in ESCAPE_SUPPORTED.values():
537  raise ValueError("Unsupported 'escape'. (%s)" %(escape))
538  self.escape = escape
539  self._includestack = []
540 
541  def parse(self, template):
542  """Parse a template.
543 
544  :Parameters:
545  - `template`: template-unicode-string
546  :Returns: the resulting parse-tree
547  :Exceptions:
548  - `TemplateSyntaxError`: for template-syntax-errors
549  - `TemplateIncludeError`: if template-inclusion failed
550  - `TemplateException`
551  """
552  self._includestack = [(None, template)] # for error-messages (_errpos)
553  return self._parse(template)
554 
555  def _errpos(self, fpos):
556  """Convert `fpos` to ``(filename,row,column)`` for error-messages."""
557  filename, string = self._includestack[-1]
558  return filename, srow(string, fpos), scol(string, fpos)
559 
560  def _testexpr(self, expr, fpos=0):
561  """Test a template-expression to detect errors."""
562  try:
563  self._testexprfunc(expr)
564  except SyntaxError as err:
565  raise TemplateSyntaxError(err, self._errpos(fpos))
566 
567  def _parse_sub(self, parsetree, text, fpos=0):
568  """Parse substitutions, and append them to the parse-tree.
569 
570  Additionally, remove comments.
571  """
572  curr = 0
573  for match in self._reSubstitution.finditer(text):
574  start = match.start()
575  if start > curr:
576  parsetree.append(("str", self._reComment.sub('', text[curr:start])))
577 
578  if match.group("sub") is not None:
579  if not match.group("end"):
580  raise TemplateSyntaxError("Missing closing tag '%s' for '%s'."
581  % (self._sub_end, match.group()), self._errpos(fpos+start))
582  if len(match.group("sub")) > 0:
583  self._testexpr(match.group("sub"), fpos+start)
584  parsetree.append(("sub", match.group("sub")))
585  else:
586  assert(match.group("escsub") is not None)
587  if not match.group("escend"):
588  raise TemplateSyntaxError("Missing closing tag '%s' for '%s'."
589  % (self._subesc_end, match.group()), self._errpos(fpos+start))
590  if len(match.group("escsub")) > 0:
591  self._testexpr(match.group("escsub"), fpos+start)
592  parsetree.append(("esc", self.escape, match.group("escsub")))
593 
594  curr = match.end()
595 
596  if len(text) > curr:
597  parsetree.append(("str", self._reComment.sub('', text[curr:])))
598 
599  def _parse(self, template, fpos=0):
600  """Recursive part of `parse()`.
601 
602  :Parameters:
603  - template
604  - fpos: position of ``template`` in the complete template (for error-messages)
605  """
606  # blank out comments
607  # (So that its content does not collide with other syntax, and
608  # because removing them completely would falsify the character-
609  # position ("match.start()") of error-messages)
610  template = self._reComment.sub(lambda match: self._comment_start+" "*len(match.group(1))+match.group(2), template)
611 
612  # init parser
613  parsetree = []
614  curr = 0 # current position (= end of previous block)
615  block_type = None # block type: if,for,macro,raw,...
616  block_indent = None # None: single-line, >=0: multi-line
617 
618  # find blocks
619  for match in self._reBlock.finditer(template):
620  start = match.start()
621  # process template-part before this block
622  if start > curr:
623  self._parse_sub(parsetree, template[curr:start], fpos)
624 
625  # analyze block syntax (incl. error-checking and -messages)
626  keyword = None
627  block = match.groupdict()
628  pos__ = fpos + start # shortcut
629  if block["sKeyw"] is not None: # single-line block tag
630  block_indent = None
631  keyword = block["sKeyw"]
632  param = block["sParam"]
633  content = block["sContent"]
634  if block["sSpace"]: # restore spaces before start-tag
635  if len(parsetree) > 0 and parsetree[-1][0] == "str":
636  parsetree[-1] = ("str", parsetree[-1][1] + block["sSpace"])
637  else:
638  parsetree.append(("str", block["sSpace"]))
639  pos_p = fpos + match.start("sParam") # shortcuts
640  pos_c = fpos + match.start("sContent")
641  elif block["mKeyw"] is not None: # multi-line block tag
642  block_indent = len(block["indent"])
643  keyword = block["mKeyw"]
644  param = block["mParam"]
645  content = block["mContent"]
646  pos_p = fpos + match.start("mParam")
647  pos_c = fpos + match.start("mContent")
648  ignored = block["mIgnored"].strip()
649  if ignored and ignored != self._comment_start:
650  raise TemplateSyntaxError("No code allowed after block-tag.", self._errpos(fpos+match.start("mIgnored")))
651  elif block["mEnd"] is not None: # multi-line block end
652  if block_type is None:
653  raise TemplateSyntaxError("No block to end here/invalid indent.", self._errpos(pos__) )
654  if block_indent != len(block["mEnd"]):
655  raise TemplateSyntaxError("Invalid indent for end-tag.", self._errpos(pos__) )
656  ignored = block["meIgnored"].strip()
657  if ignored and ignored != self._comment_start:
658  raise TemplateSyntaxError("No code allowed after end-tag.", self._errpos(fpos+match.start("meIgnored")))
659  block_type = None
660  elif block["sEnd"] is not None: # single-line block end
661  if block_type is None:
662  raise TemplateSyntaxError("No block to end here/invalid indent.", self._errpos(pos__))
663  if block_indent is not None:
664  raise TemplateSyntaxError("Invalid indent for end-tag.", self._errpos(pos__))
665  block_type = None
666  else:
667  raise TemplateException("FATAL: Block regexp error. Please contact the author. (%s)" % match.group())
668 
669  # analyze block content (mainly error-checking and -messages)
670  if keyword:
671  keyword = keyword.lower()
672  if 'for' == keyword:
673  if block_type is not None:
674  raise TemplateSyntaxError("Missing block-end-tag before new block at '%s'." %(match.group()), self._errpos(pos__))
675  block_type = 'for'
676  cond = self._reForParam.match(param)
677  if cond is None:
678  raise TemplateSyntaxError("Invalid 'for ...' at '%s'." %(param), self._errpos(pos_p))
679  names = tuple(n.strip() for n in cond.group("names").split(","))
680  self._testexpr(cond.group("iter"), pos_p+cond.start("iter"))
681  parsetree.append(("for", names, cond.group("iter"), self._parse(content, pos_c)))
682  elif 'if' == keyword:
683  if block_type is not None:
684  raise TemplateSyntaxError("Missing block-end-tag before new block at '%s'." %(match.group()), self._errpos(pos__))
685  if not param:
686  raise TemplateSyntaxError("Missing condition for 'if' at '%s'." %(match.group()), self._errpos(pos__))
687  block_type = 'if'
688  self._testexpr(param, pos_p)
689  parsetree.append(("if", param, self._parse(content, pos_c)))
690  elif 'elif' == keyword:
691  if block_type != 'if':
692  raise TemplateSyntaxError("'elif' may only appear after 'if' at '%s'." %(match.group()), self._errpos(pos__))
693  if not param:
694  raise TemplateSyntaxError("Missing condition for 'elif' at '%s'." %(match.group()), self._errpos(pos__))
695  self._testexpr(param, pos_p)
696  parsetree.append(("elif", param, self._parse(content, pos_c)))
697  elif 'else' == keyword:
698  if block_type not in ('if', 'for'):
699  raise TemplateSyntaxError("'else' may only appear after 'if' or 'for' at '%s'." %(match.group()), self._errpos(pos__))
700  if param:
701  raise TemplateSyntaxError("'else' may not have parameters at '%s'." %(match.group()), self._errpos(pos__))
702  parsetree.append(("else", self._parse(content, pos_c)))
703  elif 'macro' == keyword:
704  if block_type is not None:
705  raise TemplateSyntaxError("Missing block-end-tag before new block '%s'." %(match.group()), self._errpos(pos__))
706  block_type = 'macro'
707  # make sure param is "\w+" (instead of ".+")
708  if not param:
709  raise TemplateSyntaxError("Missing name for 'macro' at '%s'." %(match.group()), self._errpos(pos__))
710  if not self._reMacroParam.match(param):
711  raise TemplateSyntaxError("Invalid name for 'macro' at '%s'." %(match.group()), self._errpos(pos__))
712  #remove last newline
713  if len(content) > 0 and content[-1] == '\n':
714  content = content[:-1]
715  if len(content) > 0 and content[-1] == '\r':
716  content = content[:-1]
717  parsetree.append(("macro", param, self._parse(content, pos_c)))
718 
719  # parser-commands
720  elif 'raw' == keyword:
721  if block_type is not None:
722  raise TemplateSyntaxError("Missing block-end-tag before new block '%s'." %(match.group()), self._errpos(pos__))
723  if param:
724  raise TemplateSyntaxError("'raw' may not have parameters at '%s'." %(match.group()), self._errpos(pos__))
725  block_type = 'raw'
726  parsetree.append(("str", content))
727  elif 'include' == keyword:
728  if block_type is not None:
729  raise TemplateSyntaxError("Missing block-end-tag before new block '%s'." %(match.group()), self._errpos(pos__))
730  if param:
731  raise TemplateSyntaxError("'include' may not have parameters at '%s'." %(match.group()), self._errpos(pos__))
732  block_type = 'include'
733  try:
734  u = self._load(content.strip())
735  except Exception as err:
736  raise TemplateIncludeError(err, self._errpos(pos__))
737  self._includestack.append((content.strip(), u)) # current filename/template for error-msg.
738  p = self._parse(u)
739  self._includestack.pop()
740  parsetree.extend(p)
741  elif 'set_escape' == keyword:
742  if block_type is not None:
743  raise TemplateSyntaxError("Missing block-end-tag before new block '%s'." %(match.group()), self._errpos(pos__))
744  if param:
745  raise TemplateSyntaxError("'set_escape' may not have parameters at '%s'." %(match.group()), self._errpos(pos__))
746  block_type = 'set_escape'
747  esc = content.strip().upper()
748  if esc not in ESCAPE_SUPPORTED:
749  raise TemplateSyntaxError("Unsupported escape '%s'." %(esc), self._errpos(pos__))
750  self.escape = ESCAPE_SUPPORTED[esc]
751  else:
752  raise TemplateSyntaxError("Invalid keyword '%s'." %(keyword), self._errpos(pos__))
753  curr = match.end()
754 
755  if block_type is not None:
756  raise TemplateSyntaxError("Missing end-tag.", self._errpos(pos__))
757 
758  if len(template) > curr: # process template-part after last block
759  self._parse_sub(parsetree, template[curr:], fpos+curr)
760 
761  return parsetree
762 
763 #-----------------------------------------
764 # Evaluation
765 
766 # some checks
767 assert len(eval("dir()", {'__builtins__':{'dir':dir}})) == 1, \
768  "FATAL: 'eval' does not work as expected (%s)."
769 assert compile("0 .__class__", "<string>", "eval").co_names == ('__class__',), \
770  "FATAL: 'compile' does not work as expected."
771 
773  """An eval-pseudo-sandbox.
774 
775  The pseudo-sandbox restricts the available functions/objects, so the
776  code can only access:
777 
778  - some of the builtin Python-functions, which are considered "safe"
779  (see safe_builtins)
780  - some additional functions (exists(), default(), setvar(), escape())
781  - the passed objects incl. their methods.
782 
783  Additionally, names beginning with "_" are forbidden.
784  This is to prevent things like '0 .__class__', with which you could
785  easily break out of a "sandbox".
786 
787  Be careful to only pass "safe" objects/functions to the template,
788  because any unsafe function/method could break the sandbox!
789  For maximum security, restrict the access to as few objects/functions
790  as possible!
791 
792  :Warning:
793  Note that this is no real sandbox! (And although I don't know any
794  way to break out of the sandbox without passing-in an unsafe object,
795  I cannot guarantee that there is no such way. So use with care.)
796 
797  Take care if you want to use it for untrusted code!!
798  """
799 
800  safe_builtins = {
801  "True" : True,
802  "False" : False,
803  "None" : None,
804 
805  "abs" : builtins.abs,
806  "chr" : builtins.chr,
807  "divmod" : builtins.divmod,
808  "hash" : builtins.hash,
809  "hex" : builtins.hex,
810  "len" : builtins.len,
811  "max" : builtins.max,
812  "min" : builtins.min,
813  "oct" : builtins.oct,
814  "ord" : builtins.ord,
815  "pow" : builtins.pow,
816  "range" : builtins.range,
817  "round" : builtins.round,
818  "sorted" : builtins.sorted,
819  "sum" : builtins.sum,
820  "unichr" : builtins.chr,
821  "zip" : builtins.zip,
822 
823  "bool" : builtins.bool,
824  "bytes" : builtins.bytes,
825  "complex" : builtins.complex,
826  "dict" : builtins.dict,
827  "enumerate" : builtins.enumerate,
828  "float" : builtins.float,
829  "int" : builtins.int,
830  "list" : builtins.list,
831  "long" : long,
832  "reversed" : builtins.reversed,
833  "str" : builtins.str,
834  "tuple" : builtins.tuple,
835  "unicode" : unicode,
836  }
837  if sys.version_info[0] < 3:
838  safe_builtins["unichr"] = builtins.unichr
839 
840  def __init__(self):
841  self._compile_cache = {}
842  self.locals_ptr = None
844  self.register("__import__", self.f_import)
845  self.register("exists", self.f_exists)
846  self.register("default", self.f_default)
847  self.register("setvar", self.f_setvar)
848  self.register("escape", self.f_escape)
849 
850  def register(self, name, obj):
851  """Add an object to the "allowed eval-globals".
852 
853  Mainly useful to add user-defined functions to the pseudo-sandbox.
854  """
855  self.eval_allowed_globals[name] = obj
856 
857  def compile(self, expr):
858  """Compile a Python-eval-expression.
859 
860  - Use a compile-cache.
861  - Raise a `NameError` if `expr` contains a name beginning with ``_``.
862 
863  :Returns: the compiled `expr`
864  :Exceptions:
865  - `SyntaxError`: for compile-errors
866  - `NameError`: if expr contains a name beginning with ``_``
867  """
868  if expr not in self._compile_cache:
869  c = compile(expr, "", "eval")
870  for i in c.co_names: #prevent breakout via new-style-classes
871  if i[0] == '_':
872  raise NameError("Name '%s' is not allowed." % i)
873  self._compile_cache[expr] = c
874  return self._compile_cache[expr]
875 
876  def eval(self, expr, locals):
877  """Eval a Python-eval-expression.
878 
879  Sets ``self.locals_ptr`` to ``locales`` and compiles the code
880  before evaluating.
881  """
882  sav = self.locals_ptr
883  self.locals_ptr = locals
884  x = eval(self.compile(expr), {"__builtins__":self.eval_allowed_globals}, locals)
885  self.locals_ptr = sav
886  return x
887 
888  def f_import(self, name, *_, **__):
889  """``import``/``__import__()`` for the sandboxed code.
890 
891  Since "import" is insecure, the PseudoSandbox does not allow to
892  import other modules. But since some functions need to import
893  other modules (e.g. "datetime.datetime.strftime" imports "time"),
894  this function replaces the builtin "import" and allows to use
895  modules which are already accessible by the sandboxed code.
896 
897  :Note:
898  - This probably only works for rather simple imports.
899  - For security, it may be better to avoid such (complex) modules
900  which import other modules. (e.g. use time.localtime and
901  time.strftime instead of datetime.datetime.strftime,
902  or write a small wrapper.)
903 
904  :Example:
905 
906  >>> from datetime import datetime
907  >>> import pyratemp
908  >>> t = pyratemp.Template('@!mytime.strftime("%H:%M:%S")!@')
909 
910  # >>> print(t(mytime=datetime.now()))
911  # Traceback (most recent call last):
912  # ...
913  # ImportError: import not allowed in pseudo-sandbox; try to import 'time' yourself and pass it to the sandbox/template
914 
915  >>> import time
916  >>> print(t(mytime=datetime.strptime("13:40:54", "%H:%M:%S"), time=time))
917  13:40:54
918 
919  # >>> print(t(mytime=datetime.now(), time=time))
920  # 13:40:54
921  """
922  import types
923  if self.locals_ptr is not None and name in self.locals_ptr and isinstance(self.locals_ptr[name], types.ModuleType):
924  return self.locals_ptr[name]
925  else:
926  raise ImportError("import not allowed in pseudo-sandbox; try to import '%s' yourself (and maybe pass it to the sandbox/template)" % name)
927 
928  def f_exists(self, varname):
929  """``exists()`` for the sandboxed code.
930 
931  Test if the variable `varname` exists in the current locals-namespace.
932 
933  This only works for single variable names. If you want to test
934  complicated expressions, use i.e. `default`.
935  (i.e. `default("expr",False)`)
936 
937  :Note: the variable-name has to be quoted! (like in eval)
938  :Example: see module-docstring
939  """
940  return (varname in self.locals_ptr)
941 
942  def f_default(self, expr, default=None):
943  """``default()`` for the sandboxed code.
944 
945  Try to evaluate an expression and return the result or a
946  fallback-/default-value; the `default`-value is used
947  if `expr` does not exist/is invalid/results in None.
948 
949  This is very useful for optional data.
950 
951  :Parameter:
952  - expr: eval-expression
953  - default: fallback-falue if eval(expr) fails or is None.
954  :Returns:
955  the eval-result or the "fallback"-value.
956 
957  :Note: the eval-expression has to be quoted! (like in eval)
958  :Example: see module-docstring
959  """
960  try:
961  r = self.eval(expr, self.locals_ptr)
962  if r is None:
963  return default
964  return r
965  #TODO: which exceptions should be catched here?
966  except (NameError, LookupError, TypeError):
967  return default
968 
969  def f_setvar(self, name, expr):
970  """``setvar()`` for the sandboxed code.
971 
972  Set a variable.
973 
974  :Example: see module-docstring
975  """
976  self.locals_ptr[name] = self.eval(expr, self.locals_ptr)
977  return ""
978 
979  def f_escape(self, s, format="HTML"):
980  """``escape()`` for the sandboxed code.
981  """
982  if isinstance(format, (str, unicode)):
983  format = ESCAPE_SUPPORTED[format.upper()]
984  return escape(unicode(s), format)
985 
986 #-----------------------------------------
987 # basic template / subtemplate
988 
990  """Basic template-class.
991 
992  Used both for the template itself and for 'macro's ("subtemplates") in
993  the template.
994  """
995 
996  def __init__(self, parsetree, renderfunc, data=None):
997  """Create the Template/Subtemplate/Macro.
998 
999  :Parameters:
1000  - `parsetree`: parse-tree of the template/subtemplate/macro
1001  - `renderfunc`: render-function
1002  - `data`: data to fill into the template by default (dictionary).
1003  This data may later be overridden when rendering the template.
1004  :Exceptions:
1005  - `TypeError`: if `data` is not a dictionary
1006  """
1007  #TODO: parameter-checking?
1008  self.parsetree = parsetree
1009  if isinstance(data, dict):
1010  self.data = data
1011  elif data is None:
1012  self.data = {}
1013  else:
1014  raise TypeError('"data" must be a dict (or None).')
1015  self.current_data = data
1016  self._render = renderfunc
1017 
1018  def __call__(self, **override):
1019  """Fill out/render the template.
1020 
1021  :Parameters:
1022  - `override`: objects to add to the data-namespace, overriding
1023  the "default"-data.
1024  :Returns: the filled template (in unicode)
1025  :Note: This is also called when invoking macros
1026  (i.e. ``$!mymacro()!$``).
1027  """
1028  self.current_data = self.data.copy()
1029  self.current_data.update(override)
1030  u = "".join(self._render(self.parsetree, self.current_data))
1031  self.current_data = self.data # restore current_data
1032  return _dontescape(u) # (see class _dontescape)
1033 
1034  def __unicode__(self):
1035  """Alias for __call__()."""
1036  return self.__call__()
1037  def __str__(self):
1038  """Alias for __call__()."""
1039  return self.__call__()
1040 
1041 #-----------------------------------------
1042 # Renderer
1043 
1045  """Unicode-string which should not be escaped.
1046 
1047  If ``isinstance(object,_dontescape)``, then don't escape the object in
1048  ``@!...!@``. It's useful for not double-escaping macros, and it's
1049  automatically used for macros/subtemplates.
1050 
1051  :Note: This only works if the object is used on its own in ``@!...!@``.
1052  It i.e. does not work in ``@!object*2!@`` or ``@!object + "hi"!@``.
1053  """
1054  __slots__ = []
1055 
1056 
1057 class Renderer(object):
1058  """Render a template-parse-tree.
1059 
1060  :Uses: `TemplateBase` for macros
1061  """
1062 
1063  def __init__(self, evalfunc, escapefunc):
1064  """Init the renderer.
1065 
1066  :Parameters:
1067  - `evalfunc`: function for template-expression-evaluation
1068  (i.e. ``EvalPseudoSandbox().eval``)
1069  - `escapefunc`: function for escaping special characters
1070  (i.e. `escape`)
1071  """
1072  #TODO: test evalfunc
1073  self.evalfunc = evalfunc
1074  self.escapefunc = escapefunc
1075 
1076  def _eval(self, expr, data):
1077  """evalfunc with error-messages"""
1078  try:
1079  return self.evalfunc(expr, data)
1080  #TODO: any other errors to catch here?
1081  except (TypeError,NameError,LookupError,AttributeError, SyntaxError) as err:
1082  raise TemplateRenderError("Cannot eval expression '%s'. (%s: %s)" %(expr, err.__class__.__name__, err))
1083 
1084  def render(self, parsetree, data):
1085  """Render a parse-tree of a template.
1086 
1087  :Parameters:
1088  - `parsetree`: the parse-tree
1089  - `data`: the data to fill into the template (dictionary)
1090  :Returns: the rendered output-unicode-string
1091  :Exceptions:
1092  - `TemplateRenderError`
1093  """
1094  _eval = self._eval # shortcut
1095  output = []
1096  do_else = False # use else/elif-branch?
1097 
1098  if parsetree is None:
1099  return ""
1100  for elem in parsetree:
1101  if "str" == elem[0]:
1102  output.append(elem[1])
1103  elif "sub" == elem[0]:
1104  output.append(unicode(_eval(elem[1], data)))
1105  elif "esc" == elem[0]:
1106  obj = _eval(elem[2], data)
1107  #prevent double-escape
1108  if isinstance(obj, _dontescape) or isinstance(obj, TemplateBase):
1109  output.append(unicode(obj))
1110  else:
1111  output.append(self.escapefunc(unicode(obj), elem[1]))
1112  elif "for" == elem[0]:
1113  do_else = True
1114  (names, iterable) = elem[1:3]
1115  try:
1116  loop_iter = iter(_eval(iterable, data))
1117  except TypeError:
1118  raise TemplateRenderError("Cannot loop over '%s'." % iterable)
1119  for i in loop_iter:
1120  do_else = False
1121  if len(names) == 1:
1122  data[names[0]] = i
1123  else:
1124  data.update(zip(names, i)) #"for a,b,.. in list"
1125  output.extend(self.render(elem[3], data))
1126  elif "if" == elem[0]:
1127  do_else = True
1128  if _eval(elem[1], data):
1129  do_else = False
1130  output.extend(self.render(elem[2], data))
1131  elif "elif" == elem[0]:
1132  if do_else and _eval(elem[1], data):
1133  do_else = False
1134  output.extend(self.render(elem[2], data))
1135  elif "else" == elem[0]:
1136  if do_else:
1137  do_else = False
1138  output.extend(self.render(elem[1], data))
1139  elif "macro" == elem[0]:
1140  data[elem[1]] = TemplateBase(elem[2], self.render, data)
1141  else:
1142  raise TemplateRenderError("Invalid parse-tree (%s)." %(elem))
1143 
1144  return output
1145 
1146 #-----------------------------------------
1147 # template user-interface (putting it all together)
1148 
1150  """Template-User-Interface.
1151 
1152  :Usage:
1153  ::
1154  t = Template(...) (<- see __init__)
1155  output = t(...) (<- see TemplateBase.__call__)
1156 
1157  :Example:
1158  see module-docstring
1159  """
1160 
1161  def __init__(self, string=None,filename=None,parsetree=None, encoding='utf-8', data=None, escape=HTML,
1162  loader_class=LoaderFile,
1163  parser_class=Parser,
1164  renderer_class=Renderer,
1165  eval_class=EvalPseudoSandbox,
1166  escape_func=escape):
1167  """Load (+parse) a template.
1168 
1169  :Parameters:
1170  - `string,filename,parsetree`: a template-string,
1171  filename of a template to load,
1172  or a template-parsetree.
1173  (only one of these 3 is allowed)
1174  - `encoding`: encoding of the template-files (only used for "filename")
1175  - `data`: data to fill into the template by default (dictionary).
1176  This data may later be overridden when rendering the template.
1177  - `escape`: default-escaping for the template, may be overwritten by the template!
1178  - `loader_class`
1179  - `parser_class`
1180  - `renderer_class`
1181  - `eval_class`
1182  - `escapefunc`
1183  """
1184  if [string, filename, parsetree].count(None) != 2:
1185  raise ValueError('Exactly 1 of string,filename,parsetree is necessary.')
1186 
1187  tmpl = None
1188  # load template
1189  if filename is not None:
1190  incl_load = loader_class(os.path.dirname(filename), encoding).load
1191  tmpl = incl_load(os.path.basename(filename))
1192  if string is not None:
1193  incl_load = dummy_raise(NotImplementedError, "'include' not supported for template-strings.")
1194  tmpl = LoaderString(encoding).load(string)
1195 
1196  # eval (incl. compile-cache)
1197  templateeval = eval_class()
1198 
1199  # parse
1200  if tmpl is not None:
1201  p = parser_class(loadfunc=incl_load, testexpr=templateeval.compile, escape=escape)
1202  parsetree = p.parse(tmpl)
1203  del p
1204 
1205  # renderer
1206  renderfunc = renderer_class(templateeval.eval, escape_func).render
1207 
1208  #create template
1209  TemplateBase.__init__(self, parsetree, renderfunc, data)
1210 
1211 
1212 #=========================================
1213 #doctest
1214 
1215 def _doctest():
1216  """doctest this module."""
1217  import doctest
1218  doctest.testmod()
1219 
1220 #----------------------
1221 if __name__ == '__main__':
1222  if sys.version_info[0] <= 2:
1223  _doctest()
1224 
1225 #=========================================
1226 
libuavcan_dsdl_compiler.pyratemp.Parser._testexprfunc
_testexprfunc
Definition: pyratemp.py:528
libuavcan_dsdl_compiler.pyratemp.Parser
Definition: pyratemp.py:432
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.f_setvar
def f_setvar(self, name, expr)
Definition: pyratemp.py:969
libuavcan_dsdl_compiler.pyratemp.Parser.escape
escape
Definition: pyratemp.py:538
libuavcan_dsdl_compiler.pyratemp.Parser._subesc_end
string _subesc_end
Definition: pyratemp.py:446
libuavcan_dsdl_compiler.pyratemp.Template
Definition: pyratemp.py:1149
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.f_import
def f_import(self, name, *_, **__)
Definition: pyratemp.py:888
libuavcan_dsdl_compiler.pyratemp.Parser._reSubstitution
_reSubstitution
Definition: pyratemp.py:467
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.__init__
def __init__(self)
Definition: pyratemp.py:840
libuavcan_dsdl_compiler.pyratemp.Parser._sub_end
string _sub_end
Definition: pyratemp.py:444
libuavcan_dsdl_compiler.pyratemp.LoaderFile
Definition: pyratemp.py:385
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.locals_ptr
locals_ptr
Definition: pyratemp.py:842
libuavcan_dsdl_compiler.pyratemp.TemplateBase.__call__
def __call__(self, **override)
Definition: pyratemp.py:1018
libuavcan_dsdl_compiler.pyratemp.Parser._reForParam
_reForParam
Definition: pyratemp.py:504
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.compile
def compile(self, expr)
Definition: pyratemp.py:857
libuavcan_dsdl_compiler.pyratemp.Renderer.escapefunc
escapefunc
Definition: pyratemp.py:1074
libuavcan_dsdl_compiler.pyratemp.scol
def scol(string, i)
Definition: pyratemp.py:218
libuavcan_dsdl_compiler.pyratemp.TemplateBase.__str__
def __str__(self)
Definition: pyratemp.py:1037
libuavcan_dsdl_compiler.pyratemp.dummy_raise
def dummy_raise(exception, value)
Definition: pyratemp.py:257
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.safe_builtins
dictionary safe_builtins
Definition: pyratemp.py:800
libuavcan_dsdl_compiler.pyratemp.dictkeyclean
def dictkeyclean(d)
Definition: pyratemp.py:242
libuavcan_dsdl_compiler.pyratemp.TemplateBase.current_data
current_data
Definition: pyratemp.py:1015
match
static bool match(const uavcan::IncomingTransfer &it, const uavcan::RxFrame &frame, const uint8_t *payload, unsigned payload_len)
Definition: incoming_transfer.cpp:27
libuavcan_dsdl_compiler.str
str
Definition: libuavcan_dsdl_compiler/__init__.py:22
libuavcan_dsdl_compiler.pyratemp.Parser._testexpr
def _testexpr(self, expr, fpos=0)
Definition: pyratemp.py:560
libuavcan_dsdl_compiler.pyratemp.sindex
def sindex(string, row, col)
Definition: pyratemp.py:226
libuavcan_dsdl_compiler.pyratemp.TemplateBase.__init__
def __init__(self, parsetree, renderfunc, data=None)
Definition: pyratemp.py:996
libuavcan_dsdl_compiler.pyratemp.Parser.parse
def parse(self, template)
Definition: pyratemp.py:541
libuavcan_dsdl_compiler.pyratemp.Parser.__init__
def __init__(self, loadfunc=None, testexpr=None, escape=HTML)
Definition: pyratemp.py:510
libuavcan_dsdl_compiler.pyratemp.Renderer._eval
def _eval(self, expr, data)
Definition: pyratemp.py:1076
libuavcan_dsdl_compiler.pyratemp.TemplateBase.__unicode__
def __unicode__(self)
Definition: pyratemp.py:1034
libuavcan_dsdl_compiler.pyratemp.LoaderFile.path
path
Definition: pyratemp.py:404
libuavcan_dsdl_compiler.pyratemp.TemplateException
Definition: pyratemp.py:332
libuavcan_dsdl_compiler.pyratemp.Parser._reBlock
_reBlock
Definition: pyratemp.py:500
libuavcan_dsdl_compiler.pyratemp.Parser._parse
def _parse(self, template, fpos=0)
Definition: pyratemp.py:599
libuavcan_dsdl_compiler.pyratemp.TemplateParseError.err
err
Definition: pyratemp.py:344
uavcan::max
const UAVCAN_EXPORT T & max(const T &a, const T &b)
Definition: templates.hpp:291
libuavcan_dsdl_compiler.pyratemp.escape
def escape(s, format=HTML)
Definition: pyratemp.py:272
libuavcan_dsdl_compiler.pyratemp.Parser._reMacroParam
_reMacroParam
Definition: pyratemp.py:507
libuavcan_dsdl_compiler.pyratemp.TemplateParseError.__init__
def __init__(self, err, errpos)
Definition: pyratemp.py:338
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.eval_allowed_globals
eval_allowed_globals
Definition: pyratemp.py:843
libuavcan_dsdl_compiler.pyratemp.LoaderString.__init__
def __init__(self, encoding='utf-8')
Definition: pyratemp.py:373
libuavcan_dsdl_compiler.pyratemp.TemplateRenderError
Definition: pyratemp.py:361
libuavcan_dsdl_compiler.pyratemp.Parser._errpos
def _errpos(self, fpos)
Definition: pyratemp.py:555
libuavcan_dsdl_compiler.pyratemp._dontescape
Definition: pyratemp.py:1044
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.f_escape
def f_escape(self, s, format="HTML")
Definition: pyratemp.py:979
libuavcan_dsdl_compiler.pyratemp.TemplateBase.parsetree
parsetree
Definition: pyratemp.py:1008
libuavcan_dsdl_compiler.pyratemp.TemplateBase._render
_render
Definition: pyratemp.py:1016
libuavcan_dsdl_compiler.pyratemp.Parser._load
_load
Definition: pyratemp.py:523
libuavcan_dsdl_compiler.pyratemp.TemplateParseError
Definition: pyratemp.py:336
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.register
def register(self, name, obj)
Definition: pyratemp.py:850
libuavcan_dsdl_compiler.pyratemp.srow
def srow(string, i)
Definition: pyratemp.py:210
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox._compile_cache
_compile_cache
Definition: pyratemp.py:841
libuavcan_dsdl_compiler.pyratemp.LoaderString
Definition: pyratemp.py:368
libuavcan_dsdl_compiler.pyratemp.LoaderString.encoding
encoding
Definition: pyratemp.py:374
libuavcan_dsdl_compiler.pyratemp.dummy
def dummy(*_, **__)
Definition: pyratemp.py:252
libuavcan_dsdl_compiler.pyratemp.TemplateSyntaxError
Definition: pyratemp.py:353
libuavcan_dsdl_compiler.pyratemp.LoaderFile.load
def load(self, filename)
Definition: pyratemp.py:407
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox
Definition: pyratemp.py:772
libuavcan_dsdl_compiler.pyratemp.unicode
unicode
Definition: pyratemp.py:198
libuavcan_dsdl_compiler.pyratemp.TemplateBase
Definition: pyratemp.py:989
libuavcan_dsdl_compiler.pyratemp.TemplateBase.data
data
Definition: pyratemp.py:1010
libuavcan_dsdl_compiler.pyratemp.LoaderFile.__init__
def __init__(self, allowed_path=None, encoding='utf-8')
Definition: pyratemp.py:393
libuavcan_dsdl_compiler.pyratemp.TemplateParseError.__str__
def __str__(self)
Definition: pyratemp.py:347
libuavcan_dsdl_compiler.pyratemp._doctest
def _doctest()
Definition: pyratemp.py:1215
libuavcan_dsdl_compiler.pyratemp.Renderer
Definition: pyratemp.py:1057
libuavcan_dsdl_compiler.pyratemp.TemplateParseError.col
col
Definition: pyratemp.py:345
libuavcan_dsdl_compiler.pyratemp.Parser._parse_sub
def _parse_sub(self, parsetree, text, fpos=0)
Definition: pyratemp.py:567
libuavcan_dsdl_compiler.pyratemp.Renderer.__init__
def __init__(self, evalfunc, escapefunc)
Definition: pyratemp.py:1063
libuavcan_dsdl_compiler.pyratemp.Parser._reComment
_reComment
Definition: pyratemp.py:455
libuavcan_dsdl_compiler.pyratemp.LoaderFile.encoding
encoding
Definition: pyratemp.py:405
libuavcan_dsdl_compiler.pyratemp.Parser._comment_start
string _comment_start
Definition: pyratemp.py:441
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.f_exists
def f_exists(self, varname)
Definition: pyratemp.py:928
libuavcan_dsdl_compiler.pyratemp.LoaderString.load
def load(self, s)
Definition: pyratemp.py:376
libuavcan_dsdl_compiler.pyratemp.Renderer.render
def render(self, parsetree, data)
Definition: pyratemp.py:1084
uavcan::copy
UAVCAN_EXPORT OutputIt copy(InputIt first, InputIt last, OutputIt result)
Definition: templates.hpp:238
libuavcan_dsdl_compiler.pyratemp.TemplateIncludeError
Definition: pyratemp.py:357
libuavcan_dsdl_compiler.pyratemp.Renderer.evalfunc
evalfunc
Definition: pyratemp.py:1073
libuavcan_dsdl_compiler.pyratemp.Parser._includestack
_includestack
Definition: pyratemp.py:539
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.eval
def eval(self, expr, locals)
Definition: pyratemp.py:876
libuavcan_dsdl_compiler.pyratemp.EvalPseudoSandbox.f_default
def f_default(self, expr, default=None)
Definition: pyratemp.py:942
libuavcan_dsdl_compiler.pyratemp.Template.__init__
def __init__(self, string=None, filename=None, parsetree=None, encoding='utf-8', data=None, escape=HTML, loader_class=LoaderFile, parser_class=Parser, renderer_class=Renderer, eval_class=EvalPseudoSandbox, escape_func=escape)
Definition: pyratemp.py:1161


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02