Last active
September 16, 2016 00:03
-
-
Save mgd020/5bee377a8ea6d4833ddf7162ee581074 to your computer and use it in GitHub Desktop.
Django template tag that allows inline code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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