From 958e049d4d90fb5e0fe582eb4339af3c58dd5c07 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Fri, 12 Aug 2011 14:15:17 +0000 Subject: [PATCH] Fixed #5831 -- Made sure the ForNode reports the correct source of an exception happening in one of the loops. Thanks, Charmless and vladmos. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16605 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/template/debug.py | 2 +- django/template/defaulttags.py | 17 ++++++++- tests/regressiontests/templates/nodelist.py | 38 ++++++++++++++++++- .../templates/templatetags/bad_tag.py | 4 ++ tests/regressiontests/templates/tests.py | 2 +- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/django/template/debug.py b/django/template/debug.py index bf2a53b90b..b0f48a844e 100644 --- a/django/template/debug.py +++ b/django/template/debug.py @@ -78,7 +78,7 @@ class DebugNodeList(NodeList): from sys import exc_info wrapped = TemplateSyntaxError(u'Caught %s while rendering: %s' % (e.__class__.__name__, force_unicode(e, errors='replace'))) - wrapped.source = node.source + wrapped.source = getattr(e, 'template_node_source', node.source) wrapped.exc_info = exc_info() raise wrapped, None, wrapped.exc_info[2] return result diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 41c9abe21e..e7cfae430e 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -227,8 +227,21 @@ class ForNode(Node): context.update(unpacked_vars) else: context[self.loopvars[0]] = item - for node in self.nodelist_loop: - nodelist.append(node.render(context)) + # In TEMPLATE_DEBUG mode providing source of the node which + # actually raised an exception to DefaultNodeList.render_node + if settings.TEMPLATE_DEBUG: + for node in self.nodelist_loop: + try: + nodelist.append(node.render(context)) + except Exception, e: + if not hasattr(e, 'template_node_source'): + from sys import exc_info + e.template_node_source = node.source + raise e, None, exc_info()[2] + raise + else: + for node in self.nodelist_loop: + nodelist.append(node.render(context)) if pop_context: # The loop variables were pushed on to the context so pop them # off again. This is necessary because the tag lets the length diff --git a/tests/regressiontests/templates/nodelist.py b/tests/regressiontests/templates/nodelist.py index 48775397ae..3568424222 100644 --- a/tests/regressiontests/templates/nodelist.py +++ b/tests/regressiontests/templates/nodelist.py @@ -1,8 +1,8 @@ +from django.conf import settings +from django.template import VariableNode, Context, TemplateSyntaxError from django.template.loader import get_template_from_string -from django.template import VariableNode from django.utils.unittest import TestCase - class NodelistTest(TestCase): def test_for(self): @@ -28,3 +28,37 @@ class NodelistTest(TestCase): template = get_template_from_string(source) vars = template.nodelist.get_nodes_by_type(VariableNode) self.assertEqual(len(vars), 1) + + +class ErrorIndexTest(TestCase): + """ + Checks whether index of error is calculated correctly in + template debugger in for loops. Refs ticket #5831 + """ + def setUp(self): + self.old_template_debug = settings.TEMPLATE_DEBUG + settings.TEMPLATE_DEBUG = True + + def tearDown(self): + settings.TEMPLATE_DEBUG = self.old_template_debug + + def test_correct_exception_index(self): + tests = [ + ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% endfor %}', (38, 56)), + ('{% load bad_tag %}{% for i in range %}{% for j in range %}{% badsimpletag %}{% endfor %}{% endfor %}', (58, 76)), + ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% for j in range %}Hello{% endfor %}{% endfor %}', (38, 56)), + ('{% load bad_tag %}{% for i in range %}{% for j in five %}{% badsimpletag %}{% endfor %}{% endfor %}', (38, 57)), + ('{% load bad_tag %}{% for j in five %}{% badsimpletag %}{% endfor %}', (18, 37)), + ] + context = Context({ + 'range': range(5), + 'five': 5, + }) + for source, expected_error_source_index in tests: + template = get_template_from_string(source) + try: + template.render(context) + except TemplateSyntaxError, e: + error_source_index = e.source[1] + self.assertEqual(error_source_index, + expected_error_source_index) diff --git a/tests/regressiontests/templates/templatetags/bad_tag.py b/tests/regressiontests/templates/templatetags/bad_tag.py index 86c275bb05..2274395a11 100644 --- a/tests/regressiontests/templates/templatetags/bad_tag.py +++ b/tests/regressiontests/templates/templatetags/bad_tag.py @@ -5,3 +5,7 @@ register = template.Library() @register.tag def badtag(parser, token): raise RuntimeError("I am a bad tag") + +@register.simple_tag +def badsimpletag(): + raise RuntimeError("I am a bad simpletag") diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index 2481792db9..1d1efe52c7 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -32,7 +32,7 @@ from context import ContextTests from custom import CustomTagTests, CustomFilterTests from parser import ParserTests from unicode import UnicodeTests -from nodelist import NodelistTest +from nodelist import NodelistTest, ErrorIndexTest from smartif import * from response import *