2
# -*- coding: utf-8 -*-
3
# (c) 2007 Jürgen Riegel
8
def ensureDir(path,mode=0777):
10
os.makedirs(path,mode)
12
# raise an error unless it's about a alredy existing directory
14
#if errno != 17 or not os.path.isdir(path):
17
def convertMultilineString(str):
18
str = str.replace('\n','\\n')
19
str = str.replace('"','\\"')
22
"Yet Another Python Templating Utility, Version 1.2"
26
# utility stuff to avoid tests in the mainline code
28
"Polymorphic with a regex that never matches"
29
def match(self, line):
31
_never = _nevermatch() # one reusable instance of it suffices
32
def identity(string, why):
33
"A do-nothing-special-to-the-input, just-return-it function"
36
"A do-nothing handler that just re-raises the exception"
39
# and now the real thing
41
"Smart-copier (YAPTU) class"
42
def copyblock(self, i=0, last=None):
43
"Main copy method: process lines [i,last) of block"
44
def repl(match, self=self):
45
"return the eval of a found expression, for replacement"
46
# uncomment for debug: print '!!! replacing',match.group(1)
47
expr = self.preproc(match.group(1), 'eval')
48
try: return str(eval(expr, self.globals, self.locals))
49
except: return str(self.handle(expr))
50
block = self.locals['_bl']
51
if last is None: last = len(block)
54
match = self.restat.match(line)
55
if match: # a statement starts "here" (at line block[i])
56
# i is the last line to _not_ process
57
stat = match.string[match.end(0):].strip()
58
j=i+1 # look for 'finish' from here onwards
59
nest=1 # count nesting levels of statements
62
# first look for nested statements or 'finish' lines
63
if self.restend.match(line): # found a statement-end
64
nest = nest - 1 # update (decrease) nesting
65
if nest==0: break # j is first line to _not_ process
66
elif self.restat.match(line): # found a nested statement
67
nest = nest + 1 # update (increase) nesting
68
elif nest==1: # look for continuation only at this nesting
69
match = self.recont.match(line)
70
if match: # found a contin.-statement
71
nestat = match.string[match.end(0):].strip()
72
stat = '%s _cb(%s,%s)\n%s' % (stat,i+1,j,nestat)
73
i=j # again, i is the last line to _not_ process
75
stat = self.preproc(stat, 'exec')
76
stat = '%s _cb(%s,%s)' % (stat,i+1,j)
77
# for debugging, uncomment...: print "-> Executing: {"+stat+"}"
78
exec stat in self.globals,self.locals
80
else: # normal line, just copy with substitution
81
self.ouf.write(self.regex.sub(repl,line))
83
def __init__(self, regex=_never, dict={},
84
restat=_never, restend=_never, recont=_never,
85
preproc=identity, handle=nohandle, ouf=sys.stdout):
86
"Initialize self's attributes"
89
self.locals = { '_cb':self.copyblock }
91
self.restend = restend
93
self.preproc = preproc
96
def copy(self, block=None, inf=sys.stdin):
97
"Entry point: copy-with-processing a file, or a block of lines"
98
if block is None: block = inf.readlines()
99
self.locals['_bl'] = block
102
def replace(template,dict,file):
103
"Test: copy a block of lines, with full processing"
105
rex=re.compile('@([^@]+)@')
109
x=23 # just a variable to try substitution
110
cop = copier(rex, dict, rbe, ren, rco)
111
lines_block = [line+'\n' for line in template.split('\n')]
113
cop.copy(lines_block)
115
if __name__=='__main__':
116
"Test: copy a block of lines, with full processing"
118
rex=re.compile('@([^@]+)@')
122
x=23 # just a variable to try substitution
123
cop = copier(rex, globals(), rbe, ren, rco)
124
lines_block = [line+'\n' for line in """
125
A first, plain line -- it just gets copied.
126
A second line, with @x@ substitutions.
127
+ x+=1 # non-block statements MUST end with comments
129
Now the substitutions are @x@.
131
After all, @x@ is rather large!
133
After all, @x@ is rather small!
136
Also, @i@ times @x@ is @i*x@.
138
One last, plain line at the end.""".split('\n')]
140
print ''.join(lines_block)
142
cop.copy(lines_block)