Making Python’s string.Template useful
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>.

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
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
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