diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-04-19 18:43:37 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-04-19 18:43:37 -0400 |
commit | 7089554c7d18bddd638138856fb96c012e4120c8 (patch) | |
tree | 5dad5eb1b3f8dece8c2b01de35128eb28475df92 /coverage/templite.py | |
parent | 28d93fedc34059dfc09db9912841ae7b13f508a9 (diff) | |
download | python-coveragepy-git-7089554c7d18bddd638138856fb96c012e4120c8.tar.gz |
Templite: a lightweight template class to use when making HTML reports.
Diffstat (limited to 'coverage/templite.py')
-rw-r--r-- | coverage/templite.py | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/coverage/templite.py b/coverage/templite.py new file mode 100644 index 00000000..ec845076 --- /dev/null +++ b/coverage/templite.py @@ -0,0 +1,81 @@ +"""A simple Python template renderer, for a nano-subset of Django syntax.""" + +# Started from http://blog.ianbicking.org/templating-via-dict-wrappers.html +# and http://jtauber.com/2006/05/templates.html +# and http://code.activestate.com/recipes/496730/ + +import re + +class Templite(object): + """A simple template renderer, for a nano-subset of Django syntax. + + """ + def __init__(self, text, *contexts): + self.loops = [] + self.text = self._prepare(text) + self.context = {} + for context in contexts: + self.context.update(context) + + def render(self, context=None): + # Make the complete context we'll use. + ctx = dict(self.context) + if context: + ctx.update(context) + + ctxaccess = ContextAccess(ctx) + + # Render the loops. + for iloop, (loopvar, listvar, loopbody) in enumerate(self.loops): + result = "" + for listval in ctxaccess[listvar]: + ctx[loopvar] = listval + result += loopbody % ctxaccess + ctx["loop:%d" % iloop] = result + + # Render the final template. + return self.text % ctxaccess + + def _prepare(self, text): + """Convert Django-style data references into Python-native ones.""" + # Pull out loops. + text = re.sub( + r"{% for ([a-z0-9_]+) in ([a-z0-9_.|]+) %}(.*){% endfor %}", + self._loop_repl, text + ) + # Protect actual percent signs in the text. + text = text.replace("%", "%%") + # Convert {{foo}} into %(foo)s + text = re.sub(r"{{([^}]+)}}", r"%(\1)s", text) + return text + + def _loop_repl(self, match): + nloop = len(self.loops) + # Append (loopvar, listvar, loopbody) to self.loops + loopvar, listvar, loopbody = match.groups() + loopbody = self._prepare(loopbody) + self.loops.append((loopvar, listvar, loopbody)) + return "{{loop:%d}}" % nloop + + +class ContextAccess(object): + + def __init__(self, context): + self.context = context + + def __getitem__(self, key): + if "|" in key: + pipes = key.split("|") + value = self[pipes[0]] + for func in pipes[1:]: + value = self[func](value) + elif "." in key: + dots = key.split('.') + value = self[dots[0]] + for dot in dots[1:]: + value = getattr(value, dot) + if callable(value): + value = value() + else: + value = self.context[key] + return value |