#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # # Very simple templating for HTML # # (FLAGS:NAME) # # FLAGS: # i: ignore if empty # e: HTML escape < > & " # class=... --> value # NAME: # obj.attr.key ... Example: (:os.environ.PATH) # # Usage: # from DictTemplate import dt # foo="foo&bar" # dt(""" # Path = (:os.environ.PATH) # foo = (e:foo) # """) # # The local namespace is available via (magick) introspection # Python Imports import os import re import cgi import sys import inspect def usage(): print """Usage: %s .... """ % ( os.path.basename(sys.argv[0])) class DictTemplateError(Exception): pass class DictTemplateFlags: escape=0 # HTML-Escape &, <, >, " cgi.escape(mystr, 1) ignore=0 # Ignore if missing vars={"class": None} def __init__(self, flags, place): items=flags.split(",") for item in items: equalidx=item.find("=") if equalidx!=-1: var=item[:equalidx] value=item[equalidx+1:] if not var in self.vars.keys(): raise DictTemplateError("Flags: var=%s unkown %s" % ( var, place)) self.vars[var]=value continue for char in item: if char=="i": self.ignore=True elif char=="e": self.escape=True else: raise DictTemplateError("Unkown Flag: %s %s" % ( char, place)) class DictTemplate: def __call__(self, template): stack=inspect.stack() caller=stack[1][0] obj={} obj.update(caller.f_globals) obj.update(caller.f_locals) def sub(match): flags=match.group(1) vars=match.group(2).split(".") place=match.group(0) (lastobj, value) = resolve(obj, vars, place) flags=DictTemplateFlags(flags, place) if value==None: if flags.ignore: return "" raise DictTemplateError("%s is empty. Last obj: %s" % (place, lastobj)) if flags.escape: value=cgi.escape(value, 1) if flags.vars.get("class"): value='%s' % ( flags.vars.get("class"), value) return value def resolve(obj, vars, place): vars_orig=vars vars=list(vars) while vars: item=vars.pop(0) if hasattr(obj, "__getitem__") and hasattr(obj, "get"): # This is a dict value=obj.get(item) else: value=getattr(obj, item) if value==None: if not vars: return (obj, None) raise DictTemplateError( "Reached None: %s remaining: %s" % ( place, vars)) if isinstance(value, basestring): if not vars: return (obj, value) raise DictTemplateError( "Reached String. %s remaining: %s" % place, vars) obj=value return re.sub(r'\(([^:\s]*):(.*?)\)', sub, template) dt=DictTemplate() def main(): test() foo="global overwritten by local" foog="GLOBAL" def test(): foo="LOCAL" # overwrites global variable with same name esc='& < > "' # HTML escape: & < > " class Test: myclassatt="Magick Scripting" t=Test() t.myatt="magick2" for s in ["(:t.myclassatt)", "(:t.myatt)", "(:foo)", "(:foog)", "(:os.environ.PATH)", "(:__file__)", "(i:empty)", "(e:esc)"]: print dt(s) test="abc" print dt("(class=error:test)") # abc print dt("(i,class=error:empty)") # Empty String (No ... print dt("(abc)") # no replace for s in [ "(:empty)", # Unkown variable "(i:empty.b)" # Try to access "b" of None (empty var) ]: try: dt(s) except DictTemplateError: continue raise AssertionError("%s should raise an exception" % ( s)) print "All tests successfull" if __name__=="__main__": main()