Code

Ticket #16770: unwrap_templatesyntaxerror-3.diff

File unwrap_templatesyntaxerror-3.diff, 17.5 KB (added by jMyles, 3 years ago)
Line 
1Index: django/views/debug.py
2===================================================================
3--- django/views/debug.py       (revision 16772)
4+++ django/views/debug.py       (working copy)
5@@ -223,8 +223,7 @@
6                     'loader': loader_name,
7                     'templates': template_list,
8                 })
9-        if (settings.TEMPLATE_DEBUG and hasattr(self.exc_value, 'source') and
10-            isinstance(self.exc_value, TemplateSyntaxError)):
11+        if (settings.TEMPLATE_DEBUG and hasattr(self.exc_value, 'django_template_source')):
12             self.get_template_exception_info()
13 
14         frames = self.get_traceback_frames()
15@@ -268,7 +267,7 @@
16         return t.render(c)
17 
18     def get_template_exception_info(self):
19-        origin, (start, end) = self.exc_value.source
20+        origin, (start, end) = self.exc_value.django_template_source
21         template_source = origin.reload()
22         context_lines = 10
23         line = 0
24@@ -626,7 +625,7 @@
25 {% endif %}
26 {% if template_info %}
27 <div id="template">
28-   <h2>Template error</h2>
29+   <h2>Error occured during template rendering</h2>
30    <p>In template <code>{{ template_info.name }}</code>, error at line <strong>{{ template_info.line }}</strong></p>
31    <h3>{{ template_info.message }}</h3>
32    <table class="source{% if template_info.top %} cut-top{% endif %}{% ifnotequal template_info.bottom template_info.total %} cut-bottom{% endifnotequal %}">
33Index: django/template/debug.py
34===================================================================
35--- django/template/debug.py    (revision 16772)
36+++ django/template/debug.py    (working copy)
37@@ -3,7 +3,9 @@
38 from django.utils.html import escape
39 from django.utils.safestring import SafeData, EscapeData
40 from django.utils.formats import localize
41
42 class DebugLexer(Lexer):
43     def __init__(self, template_string, origin):
44         super(DebugLexer, self).__init__(template_string, origin)
45@@ -42,9 +44,9 @@
46     def error(self, token, msg):
47         return self.source_error(token.source, msg)
48 
49-    def source_error(self, source,msg):
50+    def source_error(self, source, msg):
51         e = TemplateSyntaxError(msg)
52-        e.source = source
53+        e.source_template_node = source #Identify the template node that was being rendered when the error occurred.
54         return e
55 
56     def create_nodelist(self):
57@@ -67,21 +69,17 @@
58             e.source = token.source
59 
60 class DebugNodeList(NodeList):
61+    '''
62+    A list of nodes that is instantiated when debug is True - this is the nerve center of exceptions that occur during template rendering.
63+    '''
64     def render_node(self, node, context):
65-        try:
66-            result = node.render(context)
67-        except TemplateSyntaxError, e:
68-            if not hasattr(e, 'source'):
69-                e.source = node.source
70-            raise
71+        try:           
72+            return node.render(context)
73         except Exception, e:
74-            from sys import exc_info
75-            wrapped = TemplateSyntaxError(u'Caught %s while rendering: %s' %
76-                (e.__class__.__name__, force_unicode(e, errors='replace')))
77-            wrapped.source = getattr(e, 'template_node_source', node.source)
78-            wrapped.exc_info = exc_info()
79-            raise wrapped, None, wrapped.exc_info[2]
80-        return result
81+            if not hasattr(e, 'source_template_node'): #Have we already identified the node where the problem occured?
82+                e.django_template_source = node.source #...if not, let's annotate the exception with that - the template will use this to show information about the template just before the traceback on the exception page.
83+            raise e
84+       
85 
86 class DebugVariableNode(VariableNode):
87     def render(self, context):
88Index: tests/regressiontests/templates/tests.py
89===================================================================
90--- tests/regressiontests/templates/tests.py    (revision 16772)
91+++ tests/regressiontests/templates/tests.py    (working copy)
92@@ -1,5 +1,6 @@
93 # -*- coding: utf-8 -*-
94 from django.conf import settings
95+from django.core.urlresolvers import NoReverseMatch
96 
97 if __name__ == '__main__':
98     # When running this file in isolation, we need to set up the configuration
99@@ -20,7 +21,7 @@
100 from django.template import loader
101 from django.template.loaders import app_directories, filesystem, cached
102 from django.test.utils import (get_warnings_state, restore_warnings_state,
103-    setup_test_template_loader, restore_template_loaders)
104+    setup_test_template_loader, restore_template_loaders, override_settings)
105 from django.utils import unittest
106 from django.utils.formats import date_format
107 from django.utils.translation import activate, deactivate, ugettext as _
108@@ -309,9 +310,9 @@
109             r = None
110             try:
111                 r = tmpl.render(template.Context({}))
112-            except template.TemplateSyntaxError, e:
113+            except template.TemplateDoesNotExist, e:
114                 settings.TEMPLATE_DEBUG = old_td
115-                self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
116+                self.assertEqual(e.args[0], 'missing.html')
117             self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
118         finally:
119             loader.template_source_loaders = old_loaders
120@@ -336,8 +337,8 @@
121             r = None
122             try:
123                 r = tmpl.render(template.Context({}))
124-            except template.TemplateSyntaxError, e:
125-                self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
126+            except template.TemplateDoesNotExist, e:
127+                self.assertEqual(e.args[0], 'missing.html')
128             self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
129 
130             # For the cached loader, repeat the test, to ensure the first attempt did not cache a
131@@ -345,8 +346,8 @@
132             tmpl = loader.get_template(load_name)
133             try:
134                 tmpl.render(template.Context({}))
135-            except template.TemplateSyntaxError, e:
136-                self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
137+            except template.TemplateDoesNotExist, e:
138+                self.assertEqual(e.args[0], 'missing.html')
139             self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
140         finally:
141             loader.template_source_loaders = old_loaders
142@@ -370,15 +371,26 @@
143 
144         t = Template('{% url will_not_match %}')
145         c = Context()
146-        try:
147-            rendered = t.render(c)
148-        except TemplateSyntaxError, e:
149-            # Assert that we are getting the template syntax error and not the
150-            # string encoding error.
151-            self.assertEqual(e.args[0], "Caught NoReverseMatch while rendering: Reverse for 'will_not_match' with arguments '()' and keyword arguments '{}' not found.")
152+        self.assertRaises(NoReverseMatch, t.render, c)
153 
154         settings.SETTINGS_MODULE = old_settings_module
155         settings.TEMPLATE_DEBUG = old_template_debug
156+       
157+    @override_settings(DEBUG=True, TEMPLATE_DEBUG = True)
158+    def test_no_wrapped_exception(self):
159+        """
160+        Previously exceptions were wrapped by TemplateSyntaxError.  See #16770
161+        """
162+        from django.template import Template, TemplateSyntaxError
163+        c = Context({'coconuts': lambda: 42 / 0})
164+        t = Template("{{coconuts}}")       
165+        self.assertRaises(ZeroDivisionError, t.render, c) #Dividing by zero ought to cause ZeroDivisionError; we'll instead get TemplateSyntaxError here iff it's been wrapped.
166+       
167+        #Let's also confirm that the exception has the attribute we need to show the template information on the exception page.
168+        try:
169+            t.render(c)
170+        except ZeroDivisionError, e:
171+            self.assertTrue(hasattr(e, 'django_template_source'))
172 
173     def test_invalid_block_suggestion(self):
174         # See #7876
175@@ -666,7 +678,7 @@
176 
177             # In methods that raise an exception without a
178             # "silent_variable_attribute" set to True, the exception propagates
179-            'filter-syntax14': (r'1{{ var.method4 }}2', {"var": SomeClass()}, (SomeOtherException, SomeOtherException, template.TemplateSyntaxError)),
180+            'filter-syntax14': (r'1{{ var.method4 }}2', {"var": SomeClass()}, (SomeOtherException, SomeOtherException)),
181 
182             # Escaped backslash in argument
183             'filter-syntax15': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'),
184@@ -695,8 +707,8 @@
185             # In attribute and dict lookups that raise an unexpected exception
186             # without a "silent_variable_attribute" set to True, the exception
187             # propagates
188-            'filter-syntax23': (r'1{{ var.noisy_fail_key }}2', {"var": SomeClass()}, (SomeOtherException, SomeOtherException, template.TemplateSyntaxError)),
189-            'filter-syntax24': (r'1{{ var.noisy_fail_attribute }}2', {"var": SomeClass()}, (SomeOtherException, SomeOtherException, template.TemplateSyntaxError)),
190+            'filter-syntax23': (r'1{{ var.noisy_fail_key }}2', {"var": SomeClass()}, (SomeOtherException, SomeOtherException)),
191+            'filter-syntax24': (r'1{{ var.noisy_fail_attribute }}2', {"var": SomeClass()}, (SomeOtherException, SomeOtherException)),
192 
193             ### COMMENT SYNTAX ########################################################
194             'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
195@@ -753,7 +765,7 @@
196             ### EXCEPTIONS ############################################################
197 
198             # Raise exception for invalid template name
199-            'exception01': ("{% extends 'nonexistent' %}", {}, (template.TemplateDoesNotExist, template.TemplateDoesNotExist, template.TemplateSyntaxError)),
200+            'exception01': ("{% extends 'nonexistent' %}", {}, (template.TemplateDoesNotExist, template.TemplateDoesNotExist)),
201 
202             # Raise exception for invalid template name (in variable)
203             'exception02': ("{% extends nonexistent %}", {}, (template.TemplateSyntaxError, template.TemplateDoesNotExist)),
204@@ -1050,7 +1062,7 @@
205             'include-fail2': ('{% load broken_tag %}', {}, template.TemplateSyntaxError),
206             'include-error07': ('{% include "include-fail1" %}', {}, ('', '', RuntimeError)),
207             'include-error08': ('{% include "include-fail2" %}', {}, ('', '', template.TemplateSyntaxError)),
208-            'include-error09': ('{% include failed_include %}', {'failed_include': 'include-fail1'}, ('', '', template.TemplateSyntaxError)),
209+            'include-error09': ('{% include failed_include %}', {'failed_include': 'include-fail1'}, ('', '', RuntimeError)),
210             'include-error10': ('{% include failed_include %}', {'failed_include': 'include-fail2'}, ('', '', template.TemplateSyntaxError)),
211 
212 
213@@ -1481,8 +1493,8 @@
214 
215             # Failures
216             'old-url-fail01': ('{% url %}', {}, template.TemplateSyntaxError),
217-            'old-url-fail02': ('{% url no_such_view %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch, template.TemplateSyntaxError)),
218-            'old-url-fail03': ('{% url regressiontests.templates.views.client %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch, template.TemplateSyntaxError)),
219+            'old-url-fail02': ('{% url no_such_view %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch)),
220+            'old-url-fail03': ('{% url regressiontests.templates.views.client %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch)),
221             'old-url-fail04': ('{% url view id, %}', {}, template.TemplateSyntaxError),
222             'old-url-fail05': ('{% url view id= %}', {}, template.TemplateSyntaxError),
223             'old-url-fail06': ('{% url view a.id=id %}', {}, template.TemplateSyntaxError),
224@@ -1522,8 +1534,8 @@
225 
226             # Failures
227             'url-fail01': ('{% load url from future %}{% url %}', {}, template.TemplateSyntaxError),
228-            'url-fail02': ('{% load url from future %}{% url "no_such_view" %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch, template.TemplateSyntaxError)),
229-            'url-fail03': ('{% load url from future %}{% url "regressiontests.templates.views.client" %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch, template.TemplateSyntaxError)),
230+            'url-fail02': ('{% load url from future %}{% url "no_such_view" %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch)),
231+            'url-fail03': ('{% load url from future %}{% url "regressiontests.templates.views.client" %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch)),
232             'url-fail04': ('{% load url from future %}{% url "view" id, %}', {}, template.TemplateSyntaxError),
233             'url-fail05': ('{% load url from future %}{% url "view" id= %}', {}, template.TemplateSyntaxError),
234             'url-fail06': ('{% load url from future %}{% url "view" a.id=id %}', {}, template.TemplateSyntaxError),
235@@ -1531,9 +1543,9 @@
236             'url-fail08': ('{% load url from future %}{% url "view" id="unterminatedstring %}', {}, template.TemplateSyntaxError),
237             'url-fail09': ('{% load url from future %}{% url "view" id=", %}', {}, template.TemplateSyntaxError),
238 
239-            'url-fail11': ('{% load url from future %}{% url named_url %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch, template.TemplateSyntaxError)),
240-            'url-fail12': ('{% load url from future %}{% url named_url %}', {'named_url': 'no_such_view'}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch, template.TemplateSyntaxError)),
241-            'url-fail13': ('{% load url from future %}{% url named_url %}', {'named_url': 'regressiontests.templates.views.client'}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch, template.TemplateSyntaxError)),
242+            'url-fail11': ('{% load url from future %}{% url named_url %}', {}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch)),
243+            'url-fail12': ('{% load url from future %}{% url named_url %}', {'named_url': 'no_such_view'}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch)),
244+            'url-fail13': ('{% load url from future %}{% url named_url %}', {'named_url': 'regressiontests.templates.views.client'}, (urlresolvers.NoReverseMatch, urlresolvers.NoReverseMatch)),
245             'url-fail14': ('{% load url from future %}{% url named_url id, %}', {'named_url': 'view'}, template.TemplateSyntaxError),
246             'url-fail15': ('{% load url from future %}{% url named_url id= %}', {'named_url': 'view'}, template.TemplateSyntaxError),
247             'url-fail16': ('{% load url from future %}{% url named_url a.id=id %}', {'named_url': 'view'}, template.TemplateSyntaxError),
248Index: tests/regressiontests/templates/nodelist.py
249===================================================================
250--- tests/regressiontests/templates/nodelist.py (revision 16772)
251+++ tests/regressiontests/templates/nodelist.py (working copy)
252@@ -2,6 +2,7 @@
253 from django.template import VariableNode, Context, TemplateSyntaxError
254 from django.template.loader import get_template_from_string
255 from django.utils.unittest import TestCase
256+from django.test.utils import override_settings
257 
258 class NodelistTest(TestCase):
259 
260@@ -35,19 +36,16 @@
261     Checks whether index of error is calculated correctly in
262     template debugger in for loops. Refs ticket #5831
263     """
264-    def setUp(self):
265-        self.old_template_debug = settings.TEMPLATE_DEBUG
266-        settings.TEMPLATE_DEBUG = True
267-
268-    def tearDown(self):
269-        settings.TEMPLATE_DEBUG = self.old_template_debug
270-
271+    @override_settings(DEBUG=True, TEMPLATE_DEBUG = True)
272     def test_correct_exception_index(self):
273-        tests = [
274-            ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% endfor %}', (38, 56)),
275-            ('{% load bad_tag %}{% for i in range %}{% for j in range %}{% badsimpletag %}{% endfor %}{% endfor %}', (58, 76)),
276-            ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% for j in range %}Hello{% endfor %}{% endfor %}', (38, 56)),
277-            ('{% load bad_tag %}{% for i in range %}{% for j in five %}{% badsimpletag %}{% endfor %}{% endfor %}', (38, 57)),
278+        '''
279+        Looks at an exception page and confirms that the information about the source of an error that occurs during template rendering appears in the appropriate location.
280+        '''
281+        tests = [ #In each case, we have template contents and the lines at which we expect the template error information to occur.
282+            ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% endfor %}', (18, 38)),
283+            ('{% load bad_tag %}{% for i in range %}{% for j in range %}{% badsimpletag %}{% endfor %}{% endfor %}', (18, 38)),
284+            ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% for j in range %}Hello{% endfor %}{% endfor %}', (18, 38)),
285+            ('{% load bad_tag %}{% for i in range %}{% for j in five %}{% badsimpletag %}{% endfor %}{% endfor %}', (18, 38)),
286             ('{% load bad_tag %}{% for j in five %}{% badsimpletag %}{% endfor %}', (18, 37)),
287         ]
288         context = Context({
289@@ -58,7 +56,7 @@
290             template = get_template_from_string(source)
291             try:
292                 template.render(context)
293-            except TemplateSyntaxError, e:
294-                error_source_index = e.source[1]
295+            except (RuntimeError, TypeError), e:
296+                error_source_index = e.django_template_source[1]
297                 self.assertEqual(error_source_index,
298                                  expected_error_source_index)