Fixed #12787: Correctly identify the template that does not exist when 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
This commit is contained in:
parent
e89a5e06cf
commit
80e744945c
|
@ -44,8 +44,15 @@ class BaseLoader(object):
|
||||||
def load_template(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)
|
source, display_name = self.load_template_source(template_name, template_dirs)
|
||||||
origin = make_origin(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)
|
try:
|
||||||
return template, None
|
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):
|
def load_template_source(self, template_name, template_dirs=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -97,10 +97,7 @@ class ExtendsNode(Node):
|
||||||
raise TemplateSyntaxError(error_msg)
|
raise TemplateSyntaxError(error_msg)
|
||||||
if hasattr(parent, 'render'):
|
if hasattr(parent, 'render'):
|
||||||
return parent # parent is a Template object
|
return parent # parent is a Template object
|
||||||
try:
|
return get_template(parent)
|
||||||
return get_template(parent)
|
|
||||||
except TemplateDoesNotExist:
|
|
||||||
raise TemplateSyntaxError("Template %r cannot be extended, because it doesn't exist" % parent)
|
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
compiled_parent = self.get_parent(context)
|
compiled_parent = self.get_parent(context)
|
||||||
|
|
|
@ -37,7 +37,14 @@ class Loader(BaseLoader):
|
||||||
if template_name not in self.template_cache:
|
if template_name not in self.template_cache:
|
||||||
template, origin = self.find_template(template_name, template_dirs)
|
template, origin = self.find_template(template_name, template_dirs)
|
||||||
if not hasattr(template, 'render'):
|
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
|
self.template_cache[template_name] = template
|
||||||
return self.template_cache[template_name], None
|
return self.template_cache[template_name], None
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{% include "missing.html" %}
|
|
@ -0,0 +1 @@
|
||||||
|
{% extends "broken_base.html" %}
|
|
@ -160,38 +160,106 @@ class Templates(unittest.TestCase):
|
||||||
# Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
|
# Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
|
||||||
# the compiled templates.
|
# the compiled templates.
|
||||||
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
|
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
|
||||||
|
|
||||||
old_loaders = loader.template_source_loaders
|
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
|
try:
|
||||||
# point to a directory containing a 404.html file. Also that
|
loader.template_source_loaders = (filesystem.Loader(),)
|
||||||
# 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
|
# We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
|
||||||
cache_loader = cached.Loader(('',))
|
# point to a directory containing a 404.html file. Also that
|
||||||
cache_loader._cached_loaders = loader.template_source_loaders
|
# the file system and app directories loaders both inherit the
|
||||||
loader.template_source_loaders = (cache_loader,)
|
# 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)
|
||||||
|
|
||||||
template = loader.get_template(load_name)
|
# Aso test the cached loader, since it overrides load_template
|
||||||
template_name = template.nodelist[0].source[0].name
|
cache_loader = cached.Loader(('',))
|
||||||
self.assertTrue(template_name.endswith(load_name),
|
cache_loader._cached_loaders = loader.template_source_loaders
|
||||||
'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
|
loader.template_source_loaders = (cache_loader,)
|
||||||
|
|
||||||
template = loader.get_template(load_name)
|
template = loader.get_template(load_name)
|
||||||
template_name = template.nodelist[0].source[0].name
|
template_name = template.nodelist[0].source[0].name
|
||||||
self.assertTrue(template_name.endswith(load_name),
|
self.assertTrue(template_name.endswith(load_name),
|
||||||
'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)
|
'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
|
||||||
|
|
||||||
loader.template_source_loaders = old_loaders
|
template = loader.get_template(load_name)
|
||||||
settings.TEMPLATE_DEBUG = old_td
|
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
|
||||||
|
|
||||||
|
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):
|
def test_token_smart_split(self):
|
||||||
# Regression test for #7027
|
# Regression test for #7027
|
||||||
|
@ -269,7 +337,7 @@ class Templates(unittest.TestCase):
|
||||||
if isinstance(vals[2], tuple):
|
if isinstance(vals[2], tuple):
|
||||||
normal_string_result = vals[2][0]
|
normal_string_result = vals[2][0]
|
||||||
invalid_string_result = vals[2][1]
|
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'
|
expected_invalid_str = 'INVALID %s'
|
||||||
invalid_string_result = invalid_string_result % vals[2][2]
|
invalid_string_result = invalid_string_result % vals[2][2]
|
||||||
template.invalid_var_format_string = True
|
template.invalid_var_format_string = True
|
||||||
|
@ -530,10 +598,10 @@ class Templates(unittest.TestCase):
|
||||||
### EXCEPTIONS ############################################################
|
### EXCEPTIONS ############################################################
|
||||||
|
|
||||||
# Raise exception for invalid template name
|
# Raise exception for invalid template name
|
||||||
'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
|
'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateDoesNotExist),
|
||||||
|
|
||||||
# Raise exception for invalid template name (in variable)
|
# 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
|
# Raise exception for extra {% extends %} tags
|
||||||
'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
|
'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
|
||||||
|
|
Loading…
Reference in New Issue