--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DebugClients/Python3/coverage/templite.py Mon Dec 28 16:03:33 2009 +0000 @@ -0,0 +1,112 @@ +"""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. + + Supported constructs are extended variable access:: + + {{var.modifer.modifier|filter|filter}} + + and loops:: + + {% for var in list %}...{% endfor %} + + Construct a Templite with the template text, then use `render` against a + dictionary context to create a finished string. + + """ + def __init__(self, text, *contexts): + """Construct a Templite with the given `text`. + + `contexts` are dictionaries of values to use for future renderings. + These are good for filters and global values. + + """ + self.loops = [] + self.text = self._prepare(text) + self.context = {} + for context in contexts: + self.context.update(context) + + def render(self, context=None): + """Render this template by applying it to `context`. + + `context` is a dictionary of values to use in this rendering. + + """ + # 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"(?s){% for ([a-z0-9_]+) in ([a-z0-9_.|]+) %}(.*?){% endfor %}", + self._loop_prepare, 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_prepare(self, match): + """Prepare a loop body for `_prepare`.""" + 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): + """A mediator for a context. + + Implements __getitem__ on a context for Templite, so that string formatting + references can pull data from the context. + + """ + 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:]: + try: + value = getattr(value, dot) + except AttributeError: + value = value[dot] + if hasattr(value, '__call__'): + value = value() + else: + value = self.context[key] + return value