@@ -319,8 +323,8 @@ Traceback (most recent call last):{% for frame in frames %}
The above exception ({{ frame.exc_cause|force_escape }}) was the direct cause of the following exception:
{% else %}
During handling of the above exception ({{ frame.exc_cause|force_escape }}), another exception occurred:
-{% endif %}{% endif %}{% endifchanged %} File "{{ frame.filename }}"{% if frame.context_line %}, line {{ frame.lineno }}{% endif %}, in {{ frame.function }}
-{% if frame.context_line %} {% spaceless %}{{ frame.context_line }}{% endspaceless %}{% endif %}{% endfor %}
+{% endif %}{% endif %}{% endifchanged %} {% if frame.tb %}File "{{ frame.filename }}"{% if frame.context_line %}, line {{ frame.lineno }}{% endif %}, in {{ frame.function }}
+{% if frame.context_line %} {% spaceless %}{{ frame.context_line }}{% endspaceless %}{% endif %}{% else %}{% if forloop.first %}None{% else %}Traceback: None{% endif %}{% endif %}{% endfor %}
Exception Type: {{ exception_type }}{% if request %} at {{ request.path_info }}{% endif %}
Exception Value: {{ exception_value|force_escape }}
diff --git a/django/views/templates/technical_500.txt b/django/views/templates/technical_500.txt
index 71a6e150d8..551413aab7 100644
--- a/django/views/templates/technical_500.txt
+++ b/django/views/templates/technical_500.txt
@@ -30,8 +30,8 @@ In template {{ template_info.name }}, error at line {{ template_info.line }}
Traceback (most recent call last):
{% for frame in frames %}{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}
{% if frame.exc_cause_explicit %}The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception:{% else %}During handling of the above exception ({{ frame.exc_cause }}), another exception occurred:{% endif %}
-{% endif %}{% endifchanged %} File "{{ frame.filename }}"{% if frame.context_line %}, line {{ frame.lineno }}{% endif %}, in {{ frame.function }}
-{% if frame.context_line %} {% spaceless %}{{ frame.context_line }}{% endspaceless %}{% endif %}
+{% endif %}{% endifchanged %} {% if frame.tb %}File "{{ frame.filename }}"{% if frame.context_line %}, line {{ frame.lineno }}{% endif %}, in {{ frame.function }}
+{% if frame.context_line %} {% spaceless %}{{ frame.context_line }}{% endspaceless %}{% endif %}{% else %}{% if forloop.first %}None{% else %}Traceback: None{% endif %}{% endif %}
{% endfor %}
{% if exception_type %}Exception Type: {{ exception_type }}{% if request %} at {{ request.path_info }}{% endif %}
{% if exception_value %}Exception Value: {{ exception_value }}{% endif %}{% endif %}{% endif %}
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py
index ccb870c238..a0da6e1adc 100644
--- a/tests/view_tests/tests/test_debug.py
+++ b/tests/view_tests/tests/test_debug.py
@@ -494,7 +494,7 @@ class ExceptionReporterTests(SimpleTestCase):
reporter = ExceptionReporter(None, exc_type, exc_value, tb)
frames = reporter.get_traceback_frames()
- self.assertEqual(len(frames), 1)
+ self.assertEqual(len(frames), 2)
html = reporter.get_traceback_html()
self.assertInHTML('
RuntimeError
', html)
self.assertIn('
Oops
', html)
@@ -508,6 +508,52 @@ class ExceptionReporterTests(SimpleTestCase):
'exception occurred',
html,
)
+ self.assertInHTML('
None', html)
+ self.assertIn('Traceback (most recent call last):\n None', html)
+
+ text = reporter.get_traceback_text()
+ self.assertIn('Exception Type: RuntimeError', text)
+ self.assertIn('Exception Value: Oops', text)
+ self.assertIn('Traceback (most recent call last):\n None', text)
+ self.assertIn(
+ 'During handling of the above exception (My context), another '
+ 'exception occurred',
+ text,
+ )
+
+ def test_mid_stack_exception_without_traceback(self):
+ try:
+ try:
+ raise RuntimeError('Inner Oops')
+ except Exception as exc:
+ new_exc = RuntimeError('My context')
+ new_exc.__context__ = exc
+ raise RuntimeError('Oops') from new_exc
+ except Exception:
+ exc_type, exc_value, tb = sys.exc_info()
+ reporter = ExceptionReporter(None, exc_type, exc_value, tb)
+ html = reporter.get_traceback_html()
+ self.assertInHTML('
RuntimeError
', html)
+ self.assertIn('
Oops
', html)
+ self.assertIn('
Exception Type: | ', html)
+ self.assertIn('
Exception Value: | ', html)
+ self.assertIn('
Traceback ', html)
+ self.assertInHTML('
Traceback: None', html)
+ self.assertIn(
+ 'During handling of the above exception (Inner Oops), another '
+ 'exception occurred:\n Traceback: None',
+ html,
+ )
+
+ text = reporter.get_traceback_text()
+ self.assertIn('Exception Type: RuntimeError', text)
+ self.assertIn('Exception Value: Oops', text)
+ self.assertIn('Traceback (most recent call last):', text)
+ self.assertIn(
+ 'During handling of the above exception (Inner Oops), another '
+ 'exception occurred:\n Traceback: None',
+ text,
+ )
def test_reporting_of_nested_exceptions(self):
request = self.rf.get('/test_view/')
@@ -671,7 +717,7 @@ class ExceptionReporterTests(SimpleTestCase):
self.assertIn('
Request URL: | ', html)
self.assertNotIn('
Exception Type: | ', html)
self.assertNotIn('
Exception Value: | ', html)
- self.assertNotIn('
Traceback ', html)
+ self.assertIn('Traceback ', html)
self.assertIn('Request information
', html)
self.assertNotIn('
Request data not supplied
', html)
@@ -684,7 +730,7 @@ class ExceptionReporterTests(SimpleTestCase):
self.assertNotIn('
Request URL: | ', html)
self.assertNotIn('
Exception Type: | ', html)
self.assertNotIn('
Exception Value: | ', html)
- self.assertNotIn('
Traceback ', html)
+ self.assertIn('Traceback ', html)
self.assertIn('Request information
', html)
self.assertIn('
Request data not supplied
', html)