debug.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. from django.template.base import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError
  2. from django.utils.encoding import force_text
  3. from django.utils.html import escape
  4. from django.utils.safestring import SafeData, EscapeData
  5. from django.utils.formats import localize
  6. from django.utils.timezone import template_localtime
  7. class DebugLexer(Lexer):
  8. def __init__(self, template_string, origin):
  9. super(DebugLexer, self).__init__(template_string, origin)
  10. def tokenize(self):
  11. "Return a list of tokens from a given template_string"
  12. result, upto = [], 0
  13. for match in tag_re.finditer(self.template_string):
  14. start, end = match.span()
  15. if start > upto:
  16. result.append(self.create_token(self.template_string[upto:start], (upto, start), False))
  17. upto = start
  18. result.append(self.create_token(self.template_string[start:end], (start, end), True))
  19. upto = end
  20. last_bit = self.template_string[upto:]
  21. if last_bit:
  22. result.append(self.create_token(last_bit, (upto, upto + len(last_bit)), False))
  23. return result
  24. def create_token(self, token_string, source, in_tag):
  25. token = super(DebugLexer, self).create_token(token_string, in_tag)
  26. token.source = self.origin, source
  27. return token
  28. class DebugParser(Parser):
  29. def __init__(self, lexer):
  30. super(DebugParser, self).__init__(lexer)
  31. self.command_stack = []
  32. def enter_command(self, command, token):
  33. self.command_stack.append((command, token.source))
  34. def exit_command(self):
  35. self.command_stack.pop()
  36. def error(self, token, msg):
  37. return self.source_error(token.source, msg)
  38. def source_error(self, source, msg):
  39. e = TemplateSyntaxError(msg)
  40. e.django_template_source = source
  41. return e
  42. def create_nodelist(self):
  43. return DebugNodeList()
  44. def create_variable_node(self, contents):
  45. return DebugVariableNode(contents)
  46. def extend_nodelist(self, nodelist, node, token):
  47. node.source = token.source
  48. super(DebugParser, self).extend_nodelist(nodelist, node, token)
  49. def unclosed_block_tag(self, parse_until):
  50. command, source = self.command_stack.pop()
  51. msg = "Unclosed tag '%s'. Looking for one of: %s " % (command, ', '.join(parse_until))
  52. raise self.source_error(source, msg)
  53. def compile_filter_error(self, token, e):
  54. if not hasattr(e, 'django_template_source'):
  55. e.django_template_source = token.source
  56. def compile_function_error(self, token, e):
  57. if not hasattr(e, 'django_template_source'):
  58. e.django_template_source = token.source
  59. class DebugNodeList(NodeList):
  60. def render_node(self, node, context):
  61. try:
  62. return node.render(context)
  63. except Exception as e:
  64. if not hasattr(e, 'django_template_source'):
  65. e.django_template_source = node.source
  66. raise
  67. class DebugVariableNode(VariableNode):
  68. def render(self, context):
  69. try:
  70. output = self.filter_expression.resolve(context)
  71. output = template_localtime(output, use_tz=context.use_tz)
  72. output = localize(output, use_l10n=context.use_l10n)
  73. output = force_text(output)
  74. except UnicodeDecodeError:
  75. return ''
  76. except Exception as e:
  77. if not hasattr(e, 'django_template_source'):
  78. e.django_template_source = self.source
  79. raise
  80. if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData):
  81. return escape(output)
  82. else:
  83. return output