I'm not sure how you got this to work. On linux, in python 3.4.3 (I thought I got this working with some version of 2.7) I needed to make tpl a string
tpl = '''
"unaltered": "{{foo}}",
"replaced": "{{test}}"
'''
to avoid getting a TypeError
>>> tpl = '''
... "unaltered": "{{foo}}",
... "replaced": "{{test}}"
... '''
>>> a = CustomTemplate(tpl)
>>> a.template
'\n "unaltered": "{{foo}}",\n "replaced": "{{test}}"\n'
>>> b = a.safe_substitute(replacement_dict)
>>> b
'\n "unaltered": "{{foo}}",\n "replaced": "hello"\n'
When I do this, {{foo}} is unaltered.
I tried the above code, and it looks like the code does not actually work with python 2.7.6. I'll see if I can find a way to make it work with 2.7.6, since that seems to be a common version with recent linux distros.
update:
Looks like this was a known bug as of 2007. http://bugs.python.org/issue1686 Far as I can tell, it was applied to python 3.2 in 2010, and python 2.7 in 2014. As far as getting this to work, you can either apply the patch for issue 1686, or you can override safe_substitute() in your class with the actual source code from this patch https://hg.python.org/cpython/file/8a98ee6baa1e/Lib/string.py.
This code works in 2.7.6, and 3.4.3
from string import Template
class CustomTemplate(Template):
delimiter = '{{'
pattern = r'''
\{\{(?:
(?P<escaped>\{\{)|
(?P<named>[_a-z][_a-z0-9]*)\}\}|
(?P<braced>[_a-z][_a-z0-9]*)\}\}|
(?P<invalid>)
)
'''
def safe_substitute(self, *args, **kws):
if len(args) > 1:
raise TypeError('Too many positional arguments')
if not args:
mapping = kws
elif kws:
mapping = _multimap(kws, args[0])
else:
mapping = args[0]
# Helper function for .sub()
def convert(mo):
named = mo.group('named') or mo.group('braced')
if named is not None:
try:
# We use this idiom instead of str() because the latter
# will fail if val is a Unicode containing non-ASCII
return '%s' % (mapping[named],)
except KeyError:
return mo.group()
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
return mo.group()
raise ValueError('Unrecognized named group in pattern',
self.pattern)
return self.pattern.sub(convert, self.template)
replacement_dict = {
"test": "hello"
}
tpl = '''{
"escaped": "{{{{",
"unaltered": "{{foo}}",
"replaced": "{{test}}",
"invalid": "{{az"
}'''
a = CustomTemplate(tpl)
b = a.safe_substitute(replacement_dict)
print (b)
results:
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import template
{
"escaped": "{{",
"unaltered": "{{foo}}",
"replaced": "hello",
"invalid": "{{az"
}
>>>
escaped
andinvalid
groups. It looks like{{foo}}
matches{{
and invalid (which is empty). So whatever it does when it matches could be the problem. – Richardson