From 80c66e40f7beecbd5ee501f757a2e61236597349 Mon Sep 17 00:00:00 2001 From: Giebisch Date: Mon, 21 Nov 2022 16:54:57 +0100 Subject: [PATCH] Fixed #33747 -- Added exception notes to the technical 500 debug page. --- django/views/debug.py | 2 ++ django/views/templates/technical_500.html | 4 +-- django/views/templates/technical_500.txt | 2 +- docs/releases/4.2.txt | 2 +- tests/view_tests/tests/test_debug.py | 37 ++++++++++++++++++++++- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/django/views/debug.py b/django/views/debug.py index 30a1dbc6da..b93afa5737 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -396,6 +396,8 @@ class ExceptionReporter: c["exception_type"] = self.exc_type.__name__ if self.exc_value: c["exception_value"] = str(self.exc_value) + if exc_notes := getattr(self.exc_value, "__notes__", None): + c["exception_notes"] = "\n" + "\n".join(exc_notes) if frames: c["lastframe"] = frames[-1] return c diff --git a/django/views/templates/technical_500.html b/django/views/templates/technical_500.html index 4483145ec3..ae0411729a 100644 --- a/django/views/templates/technical_500.html +++ b/django/views/templates/technical_500.html @@ -100,7 +100,7 @@

{% if exception_type %}{{ exception_type }}{% else %}Report{% endif %} {% if request %} at {{ request.path_info }}{% endif %}

-
{% if exception_value %}{{ exception_value|force_escape }}{% else %}No exception message supplied{% endif %}
+
{% if exception_value %}{{ exception_value|force_escape }}{% if exception_notes %}{{ exception_notes }}{% endif %}{% else %}No exception message supplied{% endif %}
{% if request %} @@ -330,7 +330,7 @@ During handling of the above exception ({{ frame.exc_cause|force_escape }}), ano {% if frame.context_line %} {% spaceless %}{{ frame.context_line }}{% endspaceless %}{% endif %}{% elif forloop.first %}None{% else %}Traceback: None{% endif %}{% endfor %} Exception Type: {{ exception_type }}{% if request %} at {{ request.path_info }}{% endif %} -Exception Value: {{ exception_value|force_escape }} +Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ exception_notes }}{% endif %}

diff --git a/django/views/templates/technical_500.txt b/django/views/templates/technical_500.txt index 87cf6b5bbc..a481c5db0d 100644 --- a/django/views/templates/technical_500.txt +++ b/django/views/templates/technical_500.txt @@ -34,7 +34,7 @@ Traceback (most recent call last): {% if frame.context_line %} {% spaceless %}{{ frame.context_line }}{% endspaceless %}{% endif %}{% elif forloop.first %}None{% else %}Traceback: None{% 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 %} +{% if exception_value %}Exception Value: {{ exception_value }}{% endif %}{% if exception_notes %}{{ exception_notes }}{% endif %}{% endif %}{% endif %} {% if raising_view_name %}Raised during: {{ raising_view_name }}{% endif %} {% if request %}Request information: {% if user_str %}USER: {{ user_str }}{% endif %} diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt index 7b3ca37b35..a9841d1af4 100644 --- a/docs/releases/4.2.txt +++ b/docs/releases/4.2.txt @@ -158,7 +158,7 @@ Email Error Reporting ~~~~~~~~~~~~~~~ -* ... +* The debug page now shows :pep:`exception notes <678>` on Python 3.11+. File Storage ~~~~~~~~~~~~ diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index 7224a2b6b6..a9b7625617 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -7,7 +7,7 @@ import tempfile import threading from io import StringIO from pathlib import Path -from unittest import mock, skipIf +from unittest import mock, skipIf, skipUnless from django.core import mail from django.core.files.uploadedfile import SimpleUploadedFile @@ -22,6 +22,7 @@ from django.urls.converters import IntConverter from django.utils.functional import SimpleLazyObject from django.utils.regex_helper import _lazy_re_compile from django.utils.safestring import mark_safe +from django.utils.version import PY311 from django.views.debug import ( CallableSettingWrapper, ExceptionCycleWarning, @@ -659,6 +660,40 @@ class ExceptionReporterTests(SimpleTestCase): text, ) + @skipUnless(PY311, "Exception notes were added in Python 3.11.") + def test_exception_with_notes(self): + request = self.rf.get("/test_view/") + try: + try: + raise RuntimeError("Oops") + except Exception as err: + err.add_note("First Note") + err.add_note("Second Note") + err.add_note(mark_safe("")) + raise err + except Exception: + exc_type, exc_value, tb = sys.exc_info() + + reporter = ExceptionReporter(request, exc_type, exc_value, tb) + html = reporter.get_traceback_html() + self.assertIn( + '
Oops\nFirst Note\nSecond Note\n'
+            "<script>alert(1);</script>
", + html, + ) + self.assertIn( + "Exception Value: Oops\nFirst Note\nSecond Note\n" + "<script>alert(1);</script>", + html, + ) + + text = reporter.get_traceback_text() + self.assertIn( + "Exception Value: Oops\nFirst Note\nSecond Note\n" + "", + text, + ) + def test_mid_stack_exception_without_traceback(self): try: try: