diff --git a/django/views/debug.py b/django/views/debug.py
index 2936b276df..4d68cd4d26 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -2,6 +2,7 @@ import functools
import re
import sys
import types
+from pathlib import Path
from django.conf import settings
from django.http import HttpResponse, HttpResponseNotFound
@@ -15,13 +16,17 @@ from django.utils.module_loading import import_string
from django.utils.translation import gettext as _
# Minimal Django templates engine to render the error templates
-# regardless of the project's TEMPLATES setting.
+# regardless of the project's TEMPLATES setting. Templates are
+# read directly from the filesystem so that the error handler
+# works even if the template loader is broken.
DEBUG_ENGINE = Engine(debug=True)
HIDDEN_SETTINGS = re.compile('API|TOKEN|KEY|SECRET|PASS|SIGNATURE', flags=re.IGNORECASE)
CLEANSED_SUBSTITUTE = '********************'
+CURRENT_DIR = Path(__file__).parent
+
class CallableSettingWrapper:
"""
@@ -320,13 +325,15 @@ class ExceptionReporter:
def get_traceback_html(self):
"""Return HTML version of debug 500 HTTP error page."""
- t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEMPLATE)
+ with Path(CURRENT_DIR, 'templates', 'technical_500.html').open() as fh:
+ t = DEBUG_ENGINE.from_string(fh.read())
c = Context(self.get_traceback_data(), use_l10n=False)
return t.render(c)
def get_traceback_text(self):
"""Return plain text version of debug 500 HTTP error page."""
- t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEXT_TEMPLATE)
+ with Path(CURRENT_DIR, 'templates', 'technical_500.txt').open() as fh:
+ t = DEBUG_ENGINE.from_string(fh.read())
c = Context(self.get_traceback_data(), autoescape=False, use_l10n=False)
return t.render(c)
@@ -480,7 +487,8 @@ def technical_404_response(request, exception):
module = obj.__module__
caller = '%s.%s' % (module, caller)
- t = DEBUG_ENGINE.from_string(TECHNICAL_404_TEMPLATE)
+ with Path(CURRENT_DIR, 'templates', 'technical_404.html').open() as fh:
+ t = DEBUG_ENGINE.from_string(fh.read())
c = Context({
'urlconf': urlconf,
'root_urlconf': settings.ROOT_URLCONF,
@@ -496,7 +504,8 @@ def technical_404_response(request, exception):
def default_urlconf(request):
"""Create an empty URLconf 404 error response."""
- t = DEBUG_ENGINE.from_string(DEFAULT_URLCONF_TEMPLATE)
+ with Path(CURRENT_DIR, 'templates', 'default_urlconf.html').open() as fh:
+ t = DEBUG_ENGINE.from_string(fh.read())
c = Context({
"title": _("Welcome to Django"),
"heading": _("It worked!"),
@@ -511,744 +520,3 @@ def default_urlconf(request):
})
return HttpResponse(t.render(c), content_type='text/html')
-
-
-#
-# Templates are embedded in the file so that we know the error handler will
-# always work even if the template loader is broken.
-#
-
-TECHNICAL_500_TEMPLATE = ("""
-
-
-
-
-
- {% if exception_type %}{{ exception_type }}{% else %}Report{% endif %}"""
-r"""{% if request %} at {{ request.path_info|escape }}{% endif %}
-
- {% if not is_email %}
-
- {% endif %}
-
-
-
-
{% if exception_type %}{{ exception_type }}{% else %}Report{% endif %}"""
- """{% if request %} at {{ request.path_info|escape }}{% endif %}
- {% 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 %}
-
- {{ frame.filename|escape }} in {{ frame.function|escape }}
-
- {% if frame.context_line %}
-
- {% if frame.pre_context and not is_email %}
-
- {% for line in frame.pre_context %}
-
{{ line|escape }}
- {% endfor %}
-
- {% endif %}
-
-
-""" """{{ frame.context_line|escape }}
{% if not is_email %} ...{% endif %}
- {% if frame.post_context and not is_email %}
-
- {% for line in frame.post_context %}
-
-
-
- {% for var in request.META.items|dictsort:0 %}
-
-
{{ var.0 }}
-
{{ var.1|pprint }}
-
- {% endfor %}
-
-
-{% else %}
-
Request data not supplied
-{% endif %}
-
-
Settings
-
Using settings module {{ settings.SETTINGS_MODULE }}
-
-
-
-
Setting
-
Value
-
-
-
- {% for var in settings.items|dictsort:0 %}
-
-
{{ var.0 }}
-
{{ var.1|pprint }}
-
- {% endfor %}
-
-
-
-
-{% if not is_email %}
-
-
- You're seeing this error because you have DEBUG = True in your
- Django settings file. Change that to False, and Django will
- display a standard page generated by the handler for this status code.
-
-
-{% endif %}
-
-
-""") # NOQA
-
-TECHNICAL_500_TEXT_TEMPLATE = (""""""
-"""{% firstof exception_type 'Report' %}{% if request %} at {{ request.path_info }}{% endif %}
-{% firstof exception_value 'No exception message supplied' %}
-{% if request %}
-Request Method: {{ request.META.REQUEST_METHOD }}
-Request URL: {{ request.get_raw_uri }}{% endif %}
-Django Version: {{ django_version_info }}
-Python Executable: {{ sys_executable }}
-Python Version: {{ sys_version_info }}
-Python Path: {{ sys_path }}
-Server time: {{server_time|date:"r"}}
-Installed Applications:
-{{ settings.INSTALLED_APPS|pprint }}
-Installed Middleware:
-{{ settings.MIDDLEWARE|pprint }}"""
-"""
-{% if template_does_not_exist %}Template loader postmortem
-{% if postmortem %}Django tried loading these templates, in this order:
-{% for entry in postmortem %}
-Using engine {{ entry.backend.name }}:
-{% if entry.tried %}{% for attempt in entry.tried %}"""
-""" * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }})
-{% endfor %}{% else %} This engine did not provide a list of tried templates.
-{% endif %}{% endfor %}
-{% else %}No templates were found because your 'TEMPLATES' setting is not configured.
-{% endif %}
-{% endif %}{% if template_info %}
-Template error:
-In template {{ template_info.name }}, error at line {{ template_info.line }}
- {{ template_info.message }}
-{% for source_line in template_info.source_lines %}"""
-"{% if source_line.0 == template_info.line %}"
-" {{ source_line.0 }} : {{ template_info.before }} {{ template_info.during }} {{ template_info.after }}"
-"{% else %}"
-" {{ source_line.0 }} : {{ source_line.1 }}"
-"""{% endif %}{% endfor %}{% endif %}{% if frames %}
-
-Traceback:"""
-"{% 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 }}" in {{ frame.function }}
-{% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line }}{% 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 request %}Request information:
-{% if user_str %}USER: {{ user_str }}{% endif %}
-
-GET:{% for k, v in request_GET_items %}
-{{ k }} = {{ v|stringformat:"r" }}{% empty %} No GET data{% endfor %}
-
-POST:{% for k, v in filtered_POST_items %}
-{{ k }} = {{ v|stringformat:"r" }}{% empty %} No POST data{% endfor %}
-
-FILES:{% for k, v in request_FILES_items %}
-{{ k }} = {{ v|stringformat:"r" }}{% empty %} No FILES data{% endfor %}
-
-COOKIES:{% for k, v in request_COOKIES_items %}
-{{ k }} = {{ v|stringformat:"r" }}{% empty %} No cookie data{% endfor %}
-
-META:{% for k, v in request.META.items|dictsort:0 %}
-{{ k }} = {{ v|stringformat:"r" }}{% endfor %}
-{% else %}Request data not supplied
-{% endif %}
-Settings:
-Using settings module {{ settings.SETTINGS_MODULE }}{% for k, v in settings.items|dictsort:0 %}
-{{ k }} = {{ v|stringformat:"r" }}{% endfor %}
-
-{% if not is_email %}
-You're seeing this error because you have DEBUG = True in your
-Django settings file. Change that to False, and Django will
-display a standard page generated by the handler for this status code.
-{% endif %}
-""") # NOQA
-
-TECHNICAL_404_TEMPLATE = """
-
-
-
-
- Page not found at {{ request.path_info|escape }}
-
-
-
-
-
-
Page not found (404)
-
-
-
Request Method:
-
{{ request.META.REQUEST_METHOD }}
-
-
-
Request URL:
-
{{ request.build_absolute_uri|escape }}
-
- {% if raising_view_name %}
-
-
Raised by:
-
{{ raising_view_name }}
-
- {% endif %}
-
-
-
- {% if urlpatterns %}
-
- Using the URLconf defined in {{ urlconf }},
- Django tried these URL patterns, in this order:
-
-
- {% for pattern in urlpatterns %}
-
- {% for pat in pattern %}
- {{ pat.regex.pattern }}
- {% if forloop.last and pat.name %}[name='{{ pat.name }}']{% endif %}
- {% endfor %}
-
- {% endfor %}
-
-
- {% if request_path %}
- The current path, {{ request_path|escape }},{% else %}
- The empty path{% endif %} didn't match any of these.
-
- {% else %}
-
{{ reason }}
- {% endif %}
-
-
-
-
- You're seeing this error because you have DEBUG = True in
- your Django settings file. Change that to False, and Django
- will display a standard 404 page.
-
+
diff --git a/django/views/templates/technical_404.html b/django/views/templates/technical_404.html
new file mode 100644
index 0000000000..b88fecf2eb
--- /dev/null
+++ b/django/views/templates/technical_404.html
@@ -0,0 +1,79 @@
+
+
+
+
+ Page not found at {{ request.path_info|escape }}
+
+
+
+
+
+
Page not found (404)
+
+
+
Request Method:
+
{{ request.META.REQUEST_METHOD }}
+
+
+
Request URL:
+
{{ request.build_absolute_uri|escape }}
+
+ {% if raising_view_name %}
+
+
Raised by:
+
{{ raising_view_name }}
+
+ {% endif %}
+
+
+
+ {% if urlpatterns %}
+
+ Using the URLconf defined in {{ urlconf }},
+ Django tried these URL patterns, in this order:
+
+
+ {% for pattern in urlpatterns %}
+
+ {% for pat in pattern %}
+ {{ pat.regex.pattern }}
+ {% if forloop.last and pat.name %}[name='{{ pat.name }}']{% endif %}
+ {% endfor %}
+
+ {% endfor %}
+
+
+ {% if request_path %}
+ The current path, {{ request_path|escape }},{% else %}
+ The empty path{% endif %} didn't match any of these.
+
+ {% else %}
+
{{ reason }}
+ {% endif %}
+
+
+
+
+ You're seeing this error because you have DEBUG = True in
+ your Django settings file. Change that to False, and Django
+ will display a standard 404 page.
+
+
+
+
diff --git a/django/views/templates/technical_500.html b/django/views/templates/technical_500.html
new file mode 100644
index 0000000000..945c27827a
--- /dev/null
+++ b/django/views/templates/technical_500.html
@@ -0,0 +1,503 @@
+
+
+
+
+
+ {% if exception_type %}{{ exception_type }}{% else %}Report{% endif %}
+ {% if request %} at {{ request.path_info|escape }}{% endif %}
+
+ {% if not is_email %}
+
+ {% endif %}
+
+
+
+
{% if exception_type %}{{ exception_type }}{% else %}Report{% endif %}
+ {% if request %} at {{ request.path_info|escape }}{% endif %}
+ {% 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 %}
+
+ {{ frame.filename|escape }} in {{ frame.function|escape }}
+
+ {% if frame.context_line %}
+
+ {% if frame.pre_context and not is_email %}
+
+ {% for line in frame.pre_context %}
+
{{ line|escape }}
+ {% endfor %}
+
+ {% endif %}
+
+
{{ frame.context_line|escape }}
{% if not is_email %} ...{% endif %}
+
+ {% if frame.post_context and not is_email %}
+
+ {% for line in frame.post_context %}
+
+
+
+ {% for var in request.META.items|dictsort:0 %}
+
+
{{ var.0 }}
+
{{ var.1|pprint }}
+
+ {% endfor %}
+
+
+{% else %}
+
Request data not supplied
+{% endif %}
+
+
Settings
+
Using settings module {{ settings.SETTINGS_MODULE }}
+
+
+
+
Setting
+
Value
+
+
+
+ {% for var in settings.items|dictsort:0 %}
+
+
{{ var.0 }}
+
{{ var.1|pprint }}
+
+ {% endfor %}
+
+
+
+
+{% if not is_email %}
+
+
+ You're seeing this error because you have DEBUG = True in your
+ Django settings file. Change that to False, and Django will
+ display a standard page generated by the handler for this status code.
+
+
+{% endif %}
+
+
diff --git a/django/views/templates/technical_500.txt b/django/views/templates/technical_500.txt
new file mode 100644
index 0000000000..1777051906
--- /dev/null
+++ b/django/views/templates/technical_500.txt
@@ -0,0 +1,66 @@
+{% firstof exception_type 'Report' %}{% if request %} at {{ request.path_info }}{% endif %}
+{% firstof exception_value 'No exception message supplied' %}
+{% if request %}
+Request Method: {{ request.META.REQUEST_METHOD }}
+Request URL: {{ request.get_raw_uri }}{% endif %}
+Django Version: {{ django_version_info }}
+Python Executable: {{ sys_executable }}
+Python Version: {{ sys_version_info }}
+Python Path: {{ sys_path }}
+Server time: {{server_time|date:"r"}}
+Installed Applications:
+{{ settings.INSTALLED_APPS|pprint }}
+Installed Middleware:
+{{ settings.MIDDLEWARE|pprint }}
+{% if template_does_not_exist %}Template loader postmortem
+{% if postmortem %}Django tried loading these templates, in this order:
+{% for entry in postmortem %}
+Using engine {{ entry.backend.name }}:
+{% if entry.tried %}{% for attempt in entry.tried %} * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }})
+{% endfor %}{% else %} This engine did not provide a list of tried templates.
+{% endif %}{% endfor %}
+{% else %}No templates were found because your 'TEMPLATES' setting is not configured.
+{% endif %}
+{% endif %}{% if template_info %}
+Template error:
+In template {{ template_info.name }}, error at line {{ template_info.line }}
+ {{ template_info.message }}
+{% for source_line in template_info.source_lines %}{% if source_line.0 == template_info.line %} {{ source_line.0 }} : {{ template_info.before }} {{ template_info.during }} {{ template_info.after }}{% else %} {{ source_line.0 }} : {{ source_line.1 }}{% endif %}{% endfor %}{% endif %}{% if frames %}
+
+Traceback:
+{% 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 }}" in {{ frame.function }}
+{% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line }}{% 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 request %}Request information:
+{% if user_str %}USER: {{ user_str }}{% endif %}
+
+GET:{% for k, v in request_GET_items %}
+{{ k }} = {{ v|stringformat:"r" }}{% empty %} No GET data{% endfor %}
+
+POST:{% for k, v in filtered_POST_items %}
+{{ k }} = {{ v|stringformat:"r" }}{% empty %} No POST data{% endfor %}
+
+FILES:{% for k, v in request_FILES_items %}
+{{ k }} = {{ v|stringformat:"r" }}{% empty %} No FILES data{% endfor %}
+
+COOKIES:{% for k, v in request_COOKIES_items %}
+{{ k }} = {{ v|stringformat:"r" }}{% empty %} No cookie data{% endfor %}
+
+META:{% for k, v in request.META.items|dictsort:0 %}
+{{ k }} = {{ v|stringformat:"r" }}{% endfor %}
+{% else %}Request data not supplied
+{% endif %}
+Settings:
+Using settings module {{ settings.SETTINGS_MODULE }}{% for k, v in settings.items|dictsort:0 %}
+{{ k }} = {{ v|stringformat:"r" }}{% endfor %}
+
+{% if not is_email %}
+You're seeing this error because you have DEBUG = True in your
+Django settings file. Change that to False, and Django will
+display a standard page generated by the handler for this status code.
+{% endif %}
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py
index 828d59a88f..b026618b4d 100644
--- a/tests/view_tests/tests/test_debug.py
+++ b/tests/view_tests/tests/test_debug.py
@@ -279,7 +279,7 @@ class ExceptionReporterTests(SimpleTestCase):
exc_type, exc_value, tb = sys.exc_info()
reporter = ExceptionReporter(request, exc_type, exc_value, tb)
html = reporter.get_traceback_html()
- self.assertIn('