Ma0
Ma0

Reputation: 15204

Subclassing Template to provide default arguments

I am subclassing Template from string to give it some extra defaulting capabilities. The idea is for its look-up to extend beyond the passed dict to the locals() first, then to the globals() and finally default (e.g., to '-'). So this is what I wrote:

class MyTemplate(Template):
    def substitute_default(*args, **kws):
        if not args:
            raise TypeError("descriptor 'substitute' of 'Template' object needs an argument")
        self, *args = args  # allow the "self" keyword be passed
        if len(args) > 1:
            raise TypeError('Too many positional arguments')
        if not args:
            mapping = kws
        elif kws:
            mapping = ChainMap(kws, args[0])
        else:
            mapping = args[0]

        def convert(mo):
            named = mo.group('named') or mo.group('braced')
            if named is not None:
                val = mapping.get(named, locals().get(named, globals().get(named, '-')))
                return '%s' % (val,)
            if mo.group('escaped') is not None:
                return self.delimiter
            if mo.group('invalid') is not None:
                self._invalid(mo)
            raise ValueError('Unrecognized named group in pattern', self.pattern)

        return self.pattern.sub(convert, self.template)

The line with the juice is this:

val = mapping.get(named, locals().get(named, globals().get(named, '-')))

I am testing it like so:

a = 'global_foo'

def f():
    b = 'local_foo'
    t = MyTemplate('''a=$a, b=$b, c=$c, d=$d''')
    text = t.substitute_default({'c': 'foo', 'd': 'bar'})
    print(text)

f()  # -> a=global_foo, b=-, c=foo, d=bar

As you can see, the globals() look-up works but the locals() one does not..

Upvotes: 0

Views: 36

Answers (1)

Jean-François Fabre
Jean-François Fabre

Reputation: 140188

The problem is that locals() is local to your convert function when you'd want it to refer to f locals.

You have to pass the locals() dictionary somehow, either in constructor or somewhere else for it to work.

Upvotes: 1

Related Questions