Fix a small typo in docs/upload_handling.txt
[django.git] / django / template / debug.py
blobc58c854858582d9c5d611cf2798f09a8137b7572
1 from django.template import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError
2 from django.utils.encoding import force_unicode
3 from django.utils.html import escape
4 from django.utils.safestring import SafeData, EscapeData
6 class DebugLexer(Lexer):
7 def __init__(self, template_string, origin):
8 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
25 def create_token(self, token_string, source, in_tag):
26 token = super(DebugLexer, self).create_token(token_string, in_tag)
27 token.source = self.origin, source
28 return token
30 class DebugParser(Parser):
31 def __init__(self, lexer):
32 super(DebugParser, self).__init__(lexer)
33 self.command_stack = []
35 def enter_command(self, command, token):
36 self.command_stack.append( (command, token.source) )
38 def exit_command(self):
39 self.command_stack.pop()
41 def error(self, token, msg):
42 return self.source_error(token.source, msg)
44 def source_error(self, source,msg):
45 e = TemplateSyntaxError(msg)
46 e.source = source
47 return e
49 def create_nodelist(self):
50 return DebugNodeList()
52 def create_variable_node(self, contents):
53 return DebugVariableNode(contents)
55 def extend_nodelist(self, nodelist, node, token):
56 node.source = token.source
57 super(DebugParser, self).extend_nodelist(nodelist, node, token)
59 def unclosed_block_tag(self, parse_until):
60 command, source = self.command_stack.pop()
61 msg = "Unclosed tag '%s'. Looking for one of: %s " % (command, ', '.join(parse_until))
62 raise self.source_error(source, msg)
64 def compile_function_error(self, token, e):
65 if not hasattr(e, 'source'):
66 e.source = token.source
68 class DebugNodeList(NodeList):
69 def render_node(self, node, context):
70 try:
71 result = node.render(context)
72 except TemplateSyntaxError, e:
73 if not hasattr(e, 'source'):
74 e.source = node.source
75 raise
76 except Exception, e:
77 from sys import exc_info
78 wrapped = TemplateSyntaxError(u'Caught an exception while rendering: %s' % force_unicode(e, errors='replace'))
79 wrapped.source = node.source
80 wrapped.exc_info = exc_info()
81 raise wrapped
82 return result
84 class DebugVariableNode(VariableNode):
85 def render(self, context):
86 try:
87 output = force_unicode(self.filter_expression.resolve(context))
88 except TemplateSyntaxError, e:
89 if not hasattr(e, 'source'):
90 e.source = self.source
91 raise
92 except UnicodeDecodeError:
93 return ''
94 if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData):
95 return escape(output)
96 else:
97 return output