Jesper Noehr

Pythonista, RESTafarian, Binary Poet & Proud Bucketeer

Making Python’s string.Template useful

with 3 comments

You know how Python has string.Template? It’s kinda useful, as it allows you to do stuff like:

from string import Template
s = Template('$who likes $what')
print s.substitute(who='tim', what='kung pao')
'tim likes kung pao'

That’s neat. But more often than not, you may want to use nested dicts, so you can write something like ‘person.name’. string.Template won’t allow you to do this, but it’s pretty easy to get around:

class TraversingDict(dict):
    def __getitem__(self, item):
        if '.' in item:
            source, path = item.split('.', 1)
            return TraversingDict(self[source])[path]
        return super(TraversingDict, self).__getitem__(item)

class InterpolTemplate(string.Template):
    idpattern = r'[_a-z][_a-z0-9\.]*'

    def render(self, dct):
        return self.safe_substitute(TraversingDict(dct))

How does it work? It uses a custom class, which subclasses ‘dict’. It’ll behave just like a normal built-in dictionary, but we’ve overriden __getitem__ to look for periods in the key name. If one is found, it splits up the key, and instantiates itself recursively. This essentially means that you can nest to any level, like ‘person.information.personal.name.first_name’.

The ‘render’ method on InterpolTemplate is not really needed, but it turns your dict into a TraversingDict, so you don’t need to mess with those at all:

Here’s the unittest I use:

def run_template_test():
    tmpl = "repository: ${repo.name}, owner: ${repo.owner}, size: ${size}"
    t = InterpolTemplate(tmpl)
    d = { 'repo': { 'name': 'foo', 'owner': 'bar' }, 'size': 42 }
    r = t.render(d)

    assert r == 'repository: foo, owner: bar, size: 42', r

Neat, eh? Makes for a nice simple substitute when you don’t want to rely on <insert template library here>.

Written by jespern

July 15th, 2009 at 9:50 am

Posted in python

3 Responses to 'Making Python’s string.Template useful'

Subscribe to comments with RSS or TrackBack to 'Making Python’s string.Template useful'.

  1. Have you seen the str.format function in python 3?

    http://docs.python.org/3.1/library/string.html#format-string-syntax

    - Paddy.

    Paddy3118

    16 Jul 09 at 4:16 pm

  2. Paddy: I was just about to post that.

    Also, it supports nested dictionaries now too, not just in Python 3.

    Alec Henriksen

    31 Jul 09 at 8:27 pm

  3. This is brilliant. Wrapping an input dict with TraversingDict superclass so you can reuse existing code is super elegant.

    Samuel Wan

    31 Oct 09 at 7:43 am

Leave a Reply