Skip to content

Instantly share code, notes, and snippets.

@mgd020
Last active September 16, 2016 00:03
Show Gist options
  • Save mgd020/5bee377a8ea6d4833ddf7162ee581074 to your computer and use it in GitHub Desktop.
Save mgd020/5bee377a8ea6d4833ddf7162ee581074 to your computer and use it in GitHub Desktop.
Django template tag that allows inline code.
"""
Add {% code %}{% endcode %} tags to template.
Note: it will only run if it is in a block that is rendered.
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import re
import sys
import traceback
from django import template
from django.template.base import TemplateSyntaxError, Token
register = template.Library()
indent_re = re.compile('^\n*([ \t]*)[^ \t]')
line_re = re.compile('^.*$', re.MULTILINE)
@register.tag
def code(parser, token):
# read source
nodelist = parser.parse('endpython')
if nodelist.contains_nontext:
raise TemplateSyntaxError('Python block must only contain text.')
parser.delete_first_token()
source = nodelist.render(None)
# get indent
try:
indent = len(indent_re.match(source).group(1))
except AttributeError: # No match
indent = 0
# fix indent, compile and return node
source = '\n'.join(line.group()[indent:] for line in line_re.finditer(source))
code = compile(source, parser.origin.name, 'exec')
return CodeNode(code)
class CodeNode(template.Node):
def __init__(self, code):
self.code = code
def render(self, context):
exec self.code
def render_annotated(self, context):
try:
return self.render(context)
except Exception as e:
if context.template.engine.debug and not hasattr(e, 'template_debug'):
e.template_debug = self.get_exception_info(context, e)
raise
def get_exception_info(self, context, e):
tb = sys.exc_info()[2]
print(traceback.extract_tb(tb)[-1])
lineno = traceback.extract_tb(tb)[-1][1] - 1
del tb
code_start = self.token.position[1]
for i, line in enumerate(line_re.finditer(context.template.source[code_start:])):
if i == lineno:
start, end = line.span()
start += code_start
end += code_start
break
return context.template.get_exception_info(e, Token(None, None, position=(start, end)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment