# Yet Another Python Templating Utility, Version 1.2 # Taken from http://code.activestate.com/recipes/52305/ import sys # utility stuff to avoid tests in the mainline code class _nevermatch: "Polymorphic with a regex that never matches" def match(self, line): return None _never = _nevermatch() # one reusable instance of it suffices def identity(string, why): "A do-nothing-special-to-the-input, just-return-it function" return string def nohandle(string): "A do-nothing handler that just re-raises the exception" raise # and now the real thing class copier: "Smart-copier (YAPTU) class" def copyblock(self, i=0, last=None): "Main copy method: process lines [i,last) of block" def repl(match, self=self): "return the eval of a found expression, for replacement" # uncomment for debug: print '!!! replacing',match.group(1) expr = self.preproc(match.group(1), 'eval') try: return str(eval(expr, self.globals, self.locals)) except: return str(self.handle(expr)) block = self.locals['_bl'] if last is None: last = len(block) while i Executing: {"+stat+"}" exec stat in self.globals,self.locals i=j+1 else: # normal line, just copy with substitution self.ouf.write(self.regex.sub(repl,line)) i=i+1 def __init__(self, regex=_never, dict={}, restat=_never, restend=_never, recont=_never, preproc=identity, handle=nohandle, ouf=sys.stdout): "Initialize self's attributes" self.regex = regex self.globals = dict self.locals = { '_cb':self.copyblock } self.restat = restat self.restend = restend self.recont = recont self.preproc = preproc self.handle = handle self.ouf = ouf def copy(self, block=None, inf=sys.stdin): "Entry point: copy-with-processing a file, or a block of lines" if block is None: block = inf.readlines() self.locals['_bl'] = block self.copyblock() class Template: def __init__(self, template): import re rex=re.compile('@{([^}]+)}') rbe=re.compile('{{') ren=re.compile('}}') rco=re.compile('_ ') self.copier = copier(rex, {}, rbe, ren, rco) self.template = [line + '\n' for line in template.split('\n')] def render(self, dict): self.copier.globals = dict self.copier.copy(self.template) if __name__=='__main__': t = Template(''' A first, plain line -- it just gets copied. A second line, with @{x} substitutions. {{ x+=1 # non-block statements MUST end with comments }} Now the substitutions are @{x}. {{ if x>23: After all, @{x} is rather large! _ else: After all, @{x} is rather small! }} {{ for i in range(3): Also, @{i} times @{x} is @{i*x}. }} One last, plain line at the end.''') t.render({ 'x': 23 }) # "Test: copy a block of lines, with full processing" # import re # rex=re.compile('@{([^}]+)}') # rbe=re.compile('{{') # ren=re.compile('}}') # rco=re.compile('_ ') # x=23 # just a variable to try substitution # cop = copier(rex, globals(), rbe, ren, rco) # lines_block = [line+'\n' for line in ''' # A first, plain line -- it just gets copied. # A second line, with @{x} substitutions. # {{ x+=1 # non-block statements MUST end with comments # }} # Now the substitutions are @{x}. # {{ if x>23: # After all, @{x} is rather large! # _ else: # After all, @{x} is rather small! # }} # {{ for i in range(3): # Also, @{i} times @{x} is @{i*x}. # }} # One last, plain line at the end.'''.split('\n')] # print "*** input:" # print ''.join(lines_block) # print "*** output:" # cop.copy(lines_block)