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 | e4b9257e5684b20cc65bbd8752347e0ef7e2ec26 (patch) | |
tree | 2b8faf06360c163f9252c32011e14cf740ff7187 /coverage/templite.py | |
parent | 9f8fc4e8f9bf1da99728c87ce3118168085b76a1 (diff) | |
download | python-coveragepy-e4b9257e5684b20cc65bbd8752347e0ef7e2ec26.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 0000000..ec84507 --- /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 |