-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathstpy.py
113 lines (94 loc) · 3.39 KB
/
stpy.py
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# -*- coding: utf-8 -*-
"""
Simple Templates for Python
~~~~~~~~~~~~~~~~~~~~~~~~~~~
A very simple Python "Template Engine". In fact it just look up
PHP like blocks and executes the code::
t = Template('<? for u in users ?><?= u['username'] ?>\n<? end ?>')
t.render(users=[{'username': 'John'},
{'username': 'Jane'}])
would result in::
John
Jane
Syntax Elements::
<? code ?>
executes code
<?= variable ?>
prints out the variable value
<?# comment ?>
is just a comment
:copyright: 2006 by Armin Ronacher.
:license: BSD License.
"""
import re
tag_re = re.compile(r'(.*?)(<\?[=\#]?\s*.*?\s*\?>)(?uism)')
class Template(object):
def __init__(self, source):
sourcelines = []
indention = 0
def write(data, offset):
sourcelines.append((' ' * (indention - offset)) + data)
for token_type, data in self.tokenize(source):
if token_type == 'TEXT':
if data:
write('__write(%r)' % data, 0)
elif token_type == 'VARIABLE':
if data:
write('__write_var(%s)' % data, 0)
elif token_type == 'BLOCK':
statement = data.split()[0]
if data == 'end':
indention -= 1
elif statement in ('else:', 'elif', 'except:'):
write(data, 1)
else:
write(data, 0)
indention += 1
source = '\n'.join(sourcelines)
self.code = compile(source, '<template>', 'exec')
def tokenize(self, source):
remove_newline = False
for match in tag_re.finditer(source):
data = match.group(1)
if remove_newline and data.startswith('\n'):
data = data[1:]
yield 'TEXT', data
remove_newline = False
tag = match.group(2)
if tag.startswith('<?='):
yield 'VARIABLE', tag[3:-2].strip()
elif tag.startswith('<?#'):
remove_newline = True
else:
token_type = 'BLOCK'
lines = tag[2:-2].strip().splitlines()
if len(lines) > 1:
new_lines = []
indent = match.start(2) - match.end(1) + 3
for line in lines[1:]:
if line[:indent].strip():
raise SyntaxError()
new_lines.append(line[indent:])
data = '\n'.join(lines[:1] + new_lines)
else:
data = lines[0]
remove_newline = True
yield token_type, data
rest = source[match.end():]
if remove_newline and rest.startswith('\n'):
rest = rest[1:]
if rest:
yield 'TEXT', rest
def get_variable(self, value):
if isinstance(value, unicode):
return value.encode('utf-8')
elif not isinstance(value, str):
return str(value)
return value
def render(self, *args, **kwargs):
lines = []
d = dict(*args, **kwargs)
d['__write'] = lines.append
d['__write_var'] = lambda x: lines.append(self.get_variable(x))
exec self.code in d
return ''.join(lines)