1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
"""A simple Python template renderer, for a nano-subset of Django syntax."""
# Started from http://blog.ianbicking.org/templating-via-dict-wrappers.html
# and http://jtauber.com/2006/05/templates.html
# and http://code.activestate.com/recipes/496730/
import re
class Templite(object):
"""A simple template renderer, for a nano-subset of Django syntax.
"""
def __init__(self, text, *contexts):
self.loops = []
self.text = self._prepare(text)
self.context = {}
for context in contexts:
self.context.update(context)
def render(self, context=None):
# Make the complete context we'll use.
ctx = dict(self.context)
if context:
ctx.update(context)
ctxaccess = ContextAccess(ctx)
# Render the loops.
for iloop, (loopvar, listvar, loopbody) in enumerate(self.loops):
result = ""
for listval in ctxaccess[listvar]:
ctx[loopvar] = listval
result += loopbody % ctxaccess
ctx["loop:%d" % iloop] = result
# Render the final template.
return self.text % ctxaccess
def _prepare(self, text):
"""Convert Django-style data references into Python-native ones."""
# Pull out loops.
text = re.sub(
r"{% for ([a-z0-9_]+) in ([a-z0-9_.|]+) %}(.*){% endfor %}",
self._loop_repl, text
)
# Protect actual percent signs in the text.
text = text.replace("%", "%%")
# Convert {{foo}} into %(foo)s
text = re.sub(r"{{([^}]+)}}", r"%(\1)s", text)
return text
def _loop_repl(self, match):
nloop = len(self.loops)
# Append (loopvar, listvar, loopbody) to self.loops
loopvar, listvar, loopbody = match.groups()
loopbody = self._prepare(loopbody)
self.loops.append((loopvar, listvar, loopbody))
return "{{loop:%d}}" % nloop
class ContextAccess(object):
def __init__(self, context):
self.context = context
def __getitem__(self, key):
if "|" in key:
pipes = key.split("|")
value = self[pipes[0]]
for func in pipes[1:]:
value = self[func](value)
elif "." in key:
dots = key.split('.')
value = self[dots[0]]
for dot in dots[1:]:
value = getattr(value, dot)
if callable(value):
value = value()
else:
value = self.context[key]
return value
|