#!/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()