Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #12787: Correctly identify the template that does not exist whe…

…n a template being extended includes another template that does not exist. Thanks to trigeek38 for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12792 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 80e744945c4d6c16c820fe0671b36654ca484e43 1 parent e89a5e0
@kmtracey kmtracey authored
View
11 django/template/loader.py
@@ -44,8 +44,15 @@ def __call__(self, template_name, template_dirs=None):
def load_template(self, template_name, template_dirs=None):
source, display_name = self.load_template_source(template_name, template_dirs)
origin = make_origin(display_name, self.load_template_source, template_name, template_dirs)
- template = get_template_from_string(source, origin, template_name)
- return template, None
+ try:
+ template = get_template_from_string(source, origin, template_name)
+ return template, None
+ except TemplateDoesNotExist:
+ # If compiling the template we found raises TemplateDoesNotExist, back off to
+ # returning the source and display name for the template we were asked to load.
+ # This allows for correct identification (later) of the actual template that does
+ # not exist.
+ return source, display_name
def load_template_source(self, template_name, template_dirs=None):
"""
View
5 django/template/loader_tags.py
@@ -97,10 +97,7 @@ def get_parent(self, context):
raise TemplateSyntaxError(error_msg)
if hasattr(parent, 'render'):
return parent # parent is a Template object
- try:
- return get_template(parent)
- except TemplateDoesNotExist:
- raise TemplateSyntaxError("Template %r cannot be extended, because it doesn't exist" % parent)
+ return get_template(parent)
def render(self, context):
compiled_parent = self.get_parent(context)
View
9 django/template/loaders/cached.py
@@ -37,7 +37,14 @@ def load_template(self, template_name, template_dirs=None):
if template_name not in self.template_cache:
template, origin = self.find_template(template_name, template_dirs)
if not hasattr(template, 'render'):
- template = get_template_from_string(template, origin, template_name)
+ try:
+ template = get_template_from_string(template, origin, template_name)
+ except TemplateDoesNotExist:
+ # If compiling the template we found raises TemplateDoesNotExist,
+ # back off to returning the source and display name for the template
+ # we were asked to load. This allows for correct identification (later)
+ # of the actual template that does not exist.
+ return template, origin
self.template_cache[template_name] = template
return self.template_cache[template_name], None
View
1  tests/regressiontests/templates/templates/broken_base.html
@@ -0,0 +1 @@
+{% include "missing.html" %}
View
1  tests/regressiontests/templates/templates/test_extends_error.html
@@ -0,0 +1 @@
+{% extends "broken_base.html" %}
View
134 tests/regressiontests/templates/tests.py
@@ -160,38 +160,106 @@ def test_loader_debug_origin(self):
# Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
# the compiled templates.
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
+ old_loaders = loader.template_source_loaders
+ try:
+ loader.template_source_loaders = (filesystem.Loader(),)
+
+ # We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
+ # point to a directory containing a 404.html file. Also that
+ # the file system and app directories loaders both inherit the
+ # load_template method from the BaseLoader class, so we only need
+ # to test one of them.
+ load_name = '404.html'
+ template = loader.get_template(load_name)
+ template_name = template.nodelist[0].source[0].name
+ self.assertTrue(template_name.endswith(load_name),
+ 'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name)
+
+ # Aso test the cached loader, since it overrides load_template
+ cache_loader = cached.Loader(('',))
+ cache_loader._cached_loaders = loader.template_source_loaders
+ loader.template_source_loaders = (cache_loader,)
+
+ template = loader.get_template(load_name)
+ template_name = template.nodelist[0].source[0].name
+ self.assertTrue(template_name.endswith(load_name),
+ 'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
+
+ template = loader.get_template(load_name)
+ template_name = template.nodelist[0].source[0].name
+ self.assertTrue(template_name.endswith(load_name),
+ 'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)
+ finally:
+ loader.template_source_loaders = old_loaders
+ settings.TEMPLATE_DEBUG = old_td
+
+ def test_extends_include_missing_baseloader(self):
+ """
+ Tests that the correct template is identified as not existing
+ when {% extends %} specifies a template that does exist, but
+ that template has an {% include %} of something that does not
+ exist. See #12787.
+ """
+
+ # TEMPLATE_DEBUG must be true, otherwise the exception raised
+ # during {% include %} processing will be suppressed.
+ old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
old_loaders = loader.template_source_loaders
- loader.template_source_loaders = (filesystem.Loader(),)
-
- # We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
- # point to a directory containing a 404.html file. Also that
- # the file system and app directories loaders both inherit the
- # load_template method from the BaseLoader class, so we only need
- # to test one of them.
- load_name = '404.html'
- template = loader.get_template(load_name)
- template_name = template.nodelist[0].source[0].name
- self.assertTrue(template_name.endswith(load_name),
- 'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name)
-
- # Aso test the cached loader, since it overrides load_template
- cache_loader = cached.Loader(('',))
- cache_loader._cached_loaders = loader.template_source_loaders
- loader.template_source_loaders = (cache_loader,)
-
- template = loader.get_template(load_name)
- template_name = template.nodelist[0].source[0].name
- self.assertTrue(template_name.endswith(load_name),
- 'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
-
- template = loader.get_template(load_name)
- template_name = template.nodelist[0].source[0].name
- self.assertTrue(template_name.endswith(load_name),
- 'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)
-
- loader.template_source_loaders = old_loaders
- settings.TEMPLATE_DEBUG = old_td
+
+ try:
+ # Test the base loader class via the app loader. load_template
+ # from base is used by all shipped loaders excepting cached,
+ # which has its own test.
+ loader.template_source_loaders = (app_directories.Loader(),)
+
+ load_name = 'test_extends_error.html'
+ tmpl = loader.get_template(load_name)
+ r = None
+ try:
+ r = tmpl.render(template.Context({}))
+ except template.TemplateSyntaxError, e:
+ settings.TEMPLATE_DEBUG = old_td
+ self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
+ self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
+ finally:
+ loader.template_source_loaders = old_loaders
+ settings.TEMPLATE_DEBUG = old_td
+
+ def test_extends_include_missing_cachedloader(self):
+ """
+ Same as test_extends_include_missing_baseloader, only tests
+ behavior of the cached loader instead of BaseLoader.
+ """
+
+ old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
+ old_loaders = loader.template_source_loaders
+
+ try:
+ cache_loader = cached.Loader(('',))
+ cache_loader._cached_loaders = (app_directories.Loader(),)
+ loader.template_source_loaders = (cache_loader,)
+
+ load_name = 'test_extends_error.html'
+ tmpl = loader.get_template(load_name)
+ r = None
+ try:
+ r = tmpl.render(template.Context({}))
+ except template.TemplateSyntaxError, e:
+ self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
+ self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
+
+ # For the cached loader, repeat the test, to ensure the first attempt did not cache a
+ # result that behaves incorrectly on subsequent attempts.
+ tmpl = loader.get_template(load_name)
+ try:
+ tmpl.render(template.Context({}))
+ except template.TemplateSyntaxError, e:
+ self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
+ self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
+ finally:
+ loader.template_source_loaders = old_loaders
+ settings.TEMPLATE_DEBUG = old_td
def test_token_smart_split(self):
# Regression test for #7027
@@ -269,7 +337,7 @@ def test_template_loader(template_name, template_dirs=None):
if isinstance(vals[2], tuple):
normal_string_result = vals[2][0]
invalid_string_result = vals[2][1]
- if '%s' in invalid_string_result:
+ if isinstance(invalid_string_result, basestring) and '%s' in invalid_string_result:
expected_invalid_str = 'INVALID %s'
invalid_string_result = invalid_string_result % vals[2][2]
template.invalid_var_format_string = True
@@ -530,10 +598,10 @@ def get_template_tests(self):
### EXCEPTIONS ############################################################
# Raise exception for invalid template name
- 'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
+ 'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateDoesNotExist),
# Raise exception for invalid template name (in variable)
- 'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),
+ 'exception02': ("{% extends nonexistent %}", {}, (template.TemplateSyntaxError, template.TemplateDoesNotExist)),
# Raise exception for extra {% extends %} tags
'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
Please sign in to comment.
Something went wrong with that request. Please try again.