DebugClients/Python/coverage/templite.py

changeset 0
de9c2efb9d02
child 31
744cd0b4b8cd
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 """A simple Python template renderer, for a nano-subset of Django syntax."""
2
3 # Started from http://blog.ianbicking.org/templating-via-dict-wrappers.html
4 # and http://jtauber.com/2006/05/templates.html
5 # and http://code.activestate.com/recipes/496730/
6
7 import re
8
9 class Templite(object):
10 """A simple template renderer, for a nano-subset of Django syntax.
11
12 Supported constructs are extended variable access::
13
14 {{var.modifer.modifier|filter|filter}}
15
16 and loops::
17
18 {% for var in list %}...{% endfor %}
19
20 Construct a Templite with the template text, then use `render` against a
21 dictionary context to create a finished string.
22
23 """
24 def __init__(self, text, *contexts):
25 """Construct a Templite with the given `text`.
26
27 `contexts` are dictionaries of values to use for future renderings.
28 These are good for filters and global values.
29
30 """
31 self.loops = []
32 self.text = self._prepare(text)
33 self.context = {}
34 for context in contexts:
35 self.context.update(context)
36
37 def render(self, context=None):
38 """Render this template by applying it to `context`.
39
40 `context` is a dictionary of values to use in this rendering.
41
42 """
43 # Make the complete context we'll use.
44 ctx = dict(self.context)
45 if context:
46 ctx.update(context)
47
48 ctxaccess = _ContextAccess(ctx)
49
50 # Render the loops.
51 for iloop, (loopvar, listvar, loopbody) in enumerate(self.loops):
52 result = ""
53 for listval in ctxaccess[listvar]:
54 ctx[loopvar] = listval
55 result += loopbody % ctxaccess
56 ctx["loop:%d" % iloop] = result
57
58 # Render the final template.
59 return self.text % ctxaccess
60
61 def _prepare(self, text):
62 """Convert Django-style data references into Python-native ones."""
63 # Pull out loops.
64 text = re.sub(
65 r"(?s){% for ([a-z0-9_]+) in ([a-z0-9_.|]+) %}(.*?){% endfor %}",
66 self._loop_prepare, text
67 )
68 # Protect actual percent signs in the text.
69 text = text.replace("%", "%%")
70 # Convert {{foo}} into %(foo)s
71 text = re.sub(r"{{([^}]+)}}", r"%(\1)s", text)
72 return text
73
74 def _loop_prepare(self, match):
75 """Prepare a loop body for `_prepare`."""
76 nloop = len(self.loops)
77 # Append (loopvar, listvar, loopbody) to self.loops
78 loopvar, listvar, loopbody = match.groups()
79 loopbody = self._prepare(loopbody)
80 self.loops.append((loopvar, listvar, loopbody))
81 return "{{loop:%d}}" % nloop
82
83
84 class _ContextAccess(object):
85 """A mediator for a context.
86
87 Implements __getitem__ on a context for Templite, so that string formatting
88 references can pull data from the context.
89
90 """
91 def __init__(self, context):
92 self.context = context
93
94 def __getitem__(self, key):
95 if "|" in key:
96 pipes = key.split("|")
97 value = self[pipes[0]]
98 for func in pipes[1:]:
99 value = self[func](value)
100 elif "." in key:
101 dots = key.split('.')
102 value = self[dots[0]]
103 for dot in dots[1:]:
104 try:
105 value = getattr(value, dot)
106 except AttributeError:
107 value = value[dot]
108 if callable(value):
109 value = value()
110 else:
111 value = self.context[key]
112 return value

eric ide

mercurial