Fixed #11461: Ensured complete traceback is available on the debug page when an exception is encountered during template rendering, even when running on Python 2.6 or higher. Thanks Glenn.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12725 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Karen Tracey 2010-03-08 17:01:21 +00:00
parent 5a35619b5b
commit 50e46c017e
8 changed files with 37 additions and 17 deletions

View File

@ -104,20 +104,7 @@ builtins = []
invalid_var_format_string = None invalid_var_format_string = None
class TemplateSyntaxError(Exception): class TemplateSyntaxError(Exception):
def __str__(self): pass
try:
import cStringIO as StringIO
except ImportError:
import StringIO
output = StringIO.StringIO()
output.write(Exception.__str__(self))
# Check if we wrapped an exception and print that too.
if hasattr(self, 'exc_info'):
import traceback
output.write('\n\nOriginal ')
e = self.exc_info
traceback.print_exception(e[0], e[1], e[2], 500, output)
return output.getvalue()
class TemplateDoesNotExist(Exception): class TemplateDoesNotExist(Exception):
pass pass

View File

@ -76,10 +76,11 @@ class DebugNodeList(NodeList):
raise raise
except Exception, e: except Exception, e:
from sys import exc_info from sys import exc_info
wrapped = TemplateSyntaxError(u'Caught an exception while rendering: %s' % force_unicode(e, errors='replace')) wrapped = TemplateSyntaxError(u'Caught %s while rendering: %s' %
(e.__class__.__name__, force_unicode(e, errors='replace')))
wrapped.source = node.source wrapped.source = node.source
wrapped.exc_info = exc_info() wrapped.exc_info = exc_info()
raise wrapped raise wrapped, None, wrapped.exc_info[2]
return result return result
class DebugVariableNode(VariableNode): class DebugVariableNode(VariableNode):

View File

@ -216,7 +216,7 @@ class Templates(unittest.TestCase):
except TemplateSyntaxError, e: except TemplateSyntaxError, e:
# Assert that we are getting the template syntax error and not the # Assert that we are getting the template syntax error and not the
# string encoding error. # string encoding error.
self.assertEquals(e.args[0], "Caught an exception while rendering: Reverse for 'will_not_match' with arguments '()' and keyword arguments '{}' not found.") self.assertEquals(e.args[0], "Caught NoReverseMatch while rendering: Reverse for 'will_not_match' with arguments '()' and keyword arguments '{}' not found.")
settings.SETTINGS_MODULE = old_settings_module settings.SETTINGS_MODULE = old_settings_module
settings.TEMPLATE_DEBUG = old_template_debug settings.TEMPLATE_DEBUG = old_template_debug

View File

@ -0,0 +1,10 @@
from django import template
from regressiontests.views import BrokenException
register = template.Library()
@register.simple_tag
def go_boom(arg):
raise BrokenException(arg)

View File

@ -1,7 +1,10 @@
import inspect
from django.conf import settings from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase from django.test import TestCase
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template import TemplateSyntaxError
from regressiontests.views import BrokenException, except_args from regressiontests.views import BrokenException, except_args
@ -9,9 +12,12 @@ class DebugViewTests(TestCase):
def setUp(self): def setUp(self):
self.old_debug = settings.DEBUG self.old_debug = settings.DEBUG
settings.DEBUG = True settings.DEBUG = True
self.old_template_debug = settings.TEMPLATE_DEBUG
settings.TEMPLATE_DEBUG = True
def tearDown(self): def tearDown(self):
settings.DEBUG = self.old_debug settings.DEBUG = self.old_debug
settings.TEMPLATE_DEBUG = self.old_template_debug
def test_files(self): def test_files(self):
response = self.client.get('/views/raises/') response = self.client.get('/views/raises/')
@ -33,3 +39,13 @@ class DebugViewTests(TestCase):
self.assertRaises(BrokenException, self.client.get, self.assertRaises(BrokenException, self.client.get,
reverse('view_exception', args=(n,))) reverse('view_exception', args=(n,)))
def test_template_exceptions(self):
for n in range(len(except_args)):
try:
self.client.get(reverse('template_exception', args=(n,)))
except TemplateSyntaxError, e:
raising_loc = inspect.trace()[-1][-2][0].strip()
self.failIf(raising_loc.find('raise BrokenException') == -1,
"Failed to find 'raise BrokenException' in last frame of traceback, instead found: %s" %
raising_loc)

View File

@ -109,4 +109,5 @@ urlpatterns += patterns('django.views.generic.simple',
urlpatterns += patterns('regressiontests.views.views', urlpatterns += patterns('regressiontests.views.views',
url(r'view_exception/(?P<n>\d+)/$', 'view_exception', name='view_exception'), url(r'view_exception/(?P<n>\d+)/$', 'view_exception', name='view_exception'),
url(r'template_exception/(?P<n>\d+)/$', 'template_exception', name='template_exception'),
) )

View File

@ -5,6 +5,7 @@ from django import forms
from django.views.debug import technical_500_response from django.views.debug import technical_500_response
from django.views.generic.create_update import create_object from django.views.generic.create_update import create_object
from django.core.urlresolvers import get_resolver from django.core.urlresolvers import get_resolver
from django.shortcuts import render_to_response
from regressiontests.views import BrokenException, except_args from regressiontests.views import BrokenException, except_args
@ -52,3 +53,7 @@ def redirect(request):
def view_exception(request, n): def view_exception(request, n):
raise BrokenException(except_args[int(n)]) raise BrokenException(except_args[int(n)])
def template_exception(request, n):
return render_to_response('debug/template_exception.html',
{'arg': except_args[int(n)]})