from django import template from django.utils.translation import gettext_lazy as _ import re register = template.Library() r_identifers = re.compile(r'[\w.]+') class PyCallNode(template.Node): def __init__(self, expr_string, var_name): self.expr_string = expr_string self.var_name = var_name def __repr__(self): return "" def render(self, context): clist = list(context) clist.reverse() d = {} d['_'] = _ for c in clist: d.update(c) m = r_identifers.match(self.expr_string) if m: module, func = m.group().rsplit('.', 1) funcstring = self.expr_string[len(module) + 1:] mod = __import__(module, {}, {}, ['']) d[func] = getattr(mod, func) else: raise template.TemplateSyntaxError, "The arguments of %r tag should be module.function(...)" % 'pycall' if self.var_name: context[self.var_name] = eval(funcstring, d) return '' else: return str(eval(funcstring, d)) def do_pycall(parser, token): try: tag_name, arg = token.contents.split(None, 1) except ValueError: raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents[0] m = re.search(r'(.*?)\s+as\s+(\w+)', arg) if m: expr_string, var_name = m.groups() else: if not arg: raise template.TemplateSyntaxError, "The arguments of %r tag should be module.function(...)" % tag_name expr_string, var_name = arg, None return PyCallNode(expr_string, var_name) do_pycall = register.tag("pycall", do_pycall)