Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #6412 -- More details if a template file cannot be loaded

Report more details about template files in loader postmortem.
  • Loading branch information...
commit 61a8de6f4f547518d217a5ff959cbd57bddf4bb0 1 parent fd96194
Mathijs de Bruin authored aaugustin committed
23  django/views/debug.py
@@ -218,6 +218,15 @@ def __init__(self, request, exc_type, exc_value, tb, is_email=False):
218 218
             self.exc_value = Exception('Deprecated String Exception: %r' % self.exc_type)
219 219
             self.exc_type = type(self.exc_value)
220 220
 
  221
+    def format_path_status(self, path):
  222
+        if not os.path.exists(path):
  223
+            return "File does not exist"
  224
+        if not os.path.isfile(path):
  225
+            return "Not a file"
  226
+        if not os.access(path, os.R_OK):
  227
+            return "File is not readable"
  228
+        return "File exists"
  229
+
221 230
     def get_traceback_data(self):
222 231
         "Return a Context instance containing traceback information."
223 232
 
@@ -230,8 +239,10 @@ def get_traceback_data(self):
230 239
                     source_list_func = loader.get_template_sources
231 240
                     # NOTE: This assumes exc_value is the name of the template that
232 241
                     # the loader attempted to load.
233  
-                    template_list = [{'name': t, 'exists': os.path.exists(t)} \
234  
-                        for t in source_list_func(str(self.exc_value))]
  242
+                    template_list = [{
  243
+                        'name': t,
  244
+                        'status': self.format_path_status(t),
  245
+                    } for t in source_list_func(str(self.exc_value))]
235 246
                 except AttributeError:
236 247
                     template_list = []
237 248
                 loader_name = loader.__module__ + '.' + loader.__class__.__name__
@@ -650,7 +661,9 @@ def default_urlconf(request):
650 661
         <ul>
651 662
         {% for loader in loader_debug_info %}
652 663
             <li>Using loader <code>{{ loader.loader }}</code>:
653  
-                <ul>{% for t in loader.templates %}<li><code>{{ t.name }}</code> (File {% if t.exists %}exists{% else %}does not exist{% endif %})</li>{% endfor %}</ul>
  664
+                <ul>
  665
+                {% for t in loader.templates %}<li><code>{{ t.name }}</code> ({{ t.status }})</li>{% endfor %}
  666
+                </ul>
654 667
             </li>
655 668
         {% endfor %}
656 669
         </ul>
@@ -753,7 +766,7 @@ def default_urlconf(request):
753 766
 {% if template_does_not_exist %}Template Loader Error:
754 767
 {% if loader_debug_info %}Django tried loading these templates, in this order:
755 768
 {% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
756  
-{% for t in loader.templates %}{{ t.name }} (File {% if t.exists %}exists{% else %}does not exist{% endif %})
  769
+{% for t in loader.templates %}{{ t.name }} ({{ t.status }})
757 770
 {% endfor %}{% endfor %}
758 771
 {% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!
759 772
 {% endif %}
@@ -943,7 +956,7 @@ def default_urlconf(request):
943 956
 {% if template_does_not_exist %}Template loader Error:
944 957
 {% if loader_debug_info %}Django tried loading these templates, in this order:
945 958
 {% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
946  
-{% for t in loader.templates %}{{ t.name }} (File {% if t.exists %}exists{% else %}does not exist{% endif %})
  959
+{% for t in loader.templates %}{{ t.name }} ({{ t.status }})
947 960
 {% endfor %}{% endfor %}
948 961
 {% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!
949 962
 {% endif %}
43  tests/view_tests/tests/test_debug.py
@@ -5,8 +5,9 @@
5 5
 
6 6
 import inspect
7 7
 import os
  8
+import shutil
8 9
 import sys
9  
-import tempfile
  10
+from tempfile import NamedTemporaryFile, mkdtemp, mkstemp
10 11
 
11 12
 from django.core import mail
12 13
 from django.core.files.uploadedfile import SimpleUploadedFile
@@ -21,6 +22,7 @@
21 22
 from ..views import (sensitive_view, non_sensitive_view, paranoid_view,
22 23
     custom_exception_reporter_filter_view, sensitive_method_view,
23 24
     sensitive_args_function_caller, sensitive_kwargs_function_caller)
  25
+from django.utils.unittest import skipIf
24 26
 
25 27
 
26 28
 @override_settings(DEBUG=True, TEMPLATE_DEBUG=True)
@@ -78,9 +80,38 @@ def test_template_exceptions(self):
78 80
                         raising_loc)
79 81
 
80 82
     def test_template_loader_postmortem(self):
81  
-        response = self.client.get(reverse('raises_template_does_not_exist'))
82  
-        template_path = os.path.join('templates', 'i_dont_exist.html')
83  
-        self.assertContains(response, template_path, status_code=500)
  83
+        """Tests for not existing file"""
  84
+        template_name = "notfound.html"
  85
+        with NamedTemporaryFile(prefix=template_name) as tempfile:
  86
+            tempdir = os.path.dirname(tempfile.name)
  87
+            template_path = os.path.join(tempdir, template_name)
  88
+            with override_settings(TEMPLATE_DIRS=(tempdir,)):
  89
+                response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name}))
  90
+            self.assertContains(response, "%s (File does not exist)" % template_path, status_code=500, count=1)
  91
+
  92
+    @skipIf(sys.platform == "win32", "Python on Windows doesn't have working os.chmod() and os.access().")
  93
+    def test_template_loader_postmortem_notreadable(self):
  94
+        """Tests for not readable file"""
  95
+        with NamedTemporaryFile() as tempfile:
  96
+            template_name = tempfile.name
  97
+            tempdir = os.path.dirname(tempfile.name)
  98
+            template_path = os.path.join(tempdir, template_name)
  99
+            os.chmod(template_path, 0o0222)
  100
+            with override_settings(TEMPLATE_DIRS=(tempdir,)):
  101
+                response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name}))
  102
+            self.assertContains(response, "%s (File is not readable)" % template_path, status_code=500, count=1)
  103
+
  104
+    def test_template_loader_postmortem_notafile(self):
  105
+        """Tests for not being a file"""
  106
+        try:
  107
+            template_path = mkdtemp()
  108
+            template_name = os.path.basename(template_path)
  109
+            tempdir = os.path.dirname(template_path)
  110
+            with override_settings(TEMPLATE_DIRS=(tempdir,)):
  111
+                response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name}))
  112
+            self.assertContains(response, "%s (Not a file)" % template_path, status_code=500, count=1)
  113
+        finally:
  114
+            shutil.rmtree(template_path)
84 115
 
85 116
 
86 117
 class ExceptionReporterTests(TestCase):
@@ -128,8 +159,8 @@ def test_eol_support(self):
128 159
         LINES = list('print %d' % i for i in range(1, 6))
129 160
         reporter = ExceptionReporter(None, None, None, None)
130 161
 
131  
-        for newline in ['\n','\r\n','\r']:
132  
-            fd,filename = tempfile.mkstemp(text = False)
  162
+        for newline in ['\n', '\r\n', '\r']:
  163
+            fd, filename = mkstemp(text=False)
133 164
             os.write(fd, force_bytes(newline.join(LINES)+newline))
134 165
             os.close(fd)
135 166
 
2  tests/view_tests/urls.py
@@ -66,5 +66,5 @@
66 66
 urlpatterns += patterns('view_tests.views',
67 67
     url(r'view_exception/(?P<n>\d+)/$', 'view_exception', name='view_exception'),
68 68
     url(r'template_exception/(?P<n>\d+)/$', 'template_exception', name='template_exception'),
69  
-    url(r'^raises_template_does_not_exist/$', 'raises_template_does_not_exist', name='raises_template_does_not_exist'),
  69
+    url(r'^raises_template_does_not_exist/(?P<path>.+)$', 'raises_template_does_not_exist', name='raises_template_does_not_exist'),
70 70
 )
4  tests/view_tests/views.py
@@ -112,11 +112,11 @@ def render_view_with_current_app_conflict(request):
112 112
         'bar': 'BAR',
113 113
     }, current_app="foobar_app", context_instance=RequestContext(request))
114 114
 
115  
-def raises_template_does_not_exist(request):
  115
+def raises_template_does_not_exist(request, path='i_dont_exist.html'):
116 116
     # We need to inspect the HTML generated by the fancy 500 debug view but
117 117
     # the test client ignores it, so we send it explicitly.
118 118
     try:
119  
-        return render_to_response('i_dont_exist.html')
  119
+        return render_to_response(path)
120 120
     except TemplateDoesNotExist:
121 121
         return technical_500_response(request, *sys.exc_info())
122 122
 

0 notes on commit 61a8de6

Please sign in to comment.
Something went wrong with that request. Please try again.