Ticket #2414: 2414.diff

File 2414.diff, 7.4 KB (added by SmileyChris, 6 years ago)

fix with tests

  • django/template/loader_tags.py

    ### Eclipse Workspace Patch 1.0
    #P Django trunk
     
    66
    77register = Library()
    88
    9 class ExtendsError(Exception):
     9class ExtendsError(TemplateSyntaxError):
     10    pass
     11
     12class ExtendsRecursionError(ExtendsError):
     13    pass
     14
     15class ExtendsNotFoundError(ExtendsError):
    1016    pass
    1117
    1218class BlockNode(Node):
     
    4349        self.nodelist = nodelist
    4450        self.parent_name, self.parent_name_expr = parent_name, parent_name_expr
    4551        self.template_dirs = template_dirs
     52        self.seen_parent_names = []
    4653
    4754    def __repr__(self):
    4855        if self.parent_name_expr:
     
    5764            error_msg = "Invalid template name in 'extends' tag: %r." % parent
    5865            if self.parent_name_expr:
    5966                error_msg += " Got this from the '%s' variable." % self.parent_name_expr.token
    60             raise TemplateSyntaxError, error_msg
     67            raise ExtendsError(error_msg)
    6168        if hasattr(parent, 'render'):
    6269            return parent # parent is a Template object
     70        if parent in self.seen_parent_names:
     71            raise ExtendsRecursionError('Template %r cannot be extended, '
     72                    'because it would cause a circular recursion' % parent)
    6373        try:
    6474            source, origin = find_template_source(parent, self.template_dirs)
    6575        except TemplateDoesNotExist:
    66             raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
    67         else:
    68             return get_template_from_string(source, origin, parent)
     76            raise ExtendsNotFoundError("Template %r cannot be extended, "
     77                    "because it doesn't exist" % parent)
     78        compiled_parent = get_template_from_string(source, origin, parent)
     79        # Let the parent extends node know about seen names (to avoid circular
     80        # recursion).
     81        parent_extends_node = self.get_extends_node(compiled_parent)
     82        if parent_extends_node:
     83            seen_parent_names = self.seen_parent_names[:]
     84            seen_parent_names.append(parent)
     85            parent_extends_node.seen_parent_names.extend(seen_parent_names)
     86        return compiled_parent
    6987
    7088    def render(self, context):
    7189        compiled_parent = self.get_parent(context)
     
    8199                # it'll be checked when the parent node's render() is called.
    82100
    83101                # Find out if the parent template has a parent itself
    84                 for node in compiled_parent.nodelist:
    85                     if not isinstance(node, TextNode):
    86                         # If the first non-text node is an extends, handle it.
    87                         if isinstance(node, ExtendsNode):
    88                             node.nodelist.append(block_node)
    89                         # Extends must be the first non-text node, so once you find
    90                         # the first non-text node you can stop looking.
    91                         break
     102                node = self.get_extends_node(compiled_parent)
     103                if node:
     104                    node.nodelist.append(block_node)
    92105            else:
    93106                # Keep any existing parents and add a new one. Used by BlockNode.
    94107                parent_block.parent = block_node.parent
     
    96109                parent_block.nodelist = block_node.nodelist
    97110        return compiled_parent.render(context)
    98111
     112    def get_extends_node(self, template):
     113        for node in template.nodelist:
     114            if not isinstance(node, TextNode):
     115                if isinstance(node, ExtendsNode):
     116                    return node
     117                # Since extends must be the first non-text node, stop looking
     118                # after the first one.
     119                break
     120
    99121class ConstantIncludeNode(Node):
    100122    def __init__(self, template_path):
    101123        try:
  • tests/regressiontests/templates/tests.py

     
    1515from django import template
    1616from django.core import urlresolvers
    1717from django.template import loader
     18from django.template import loader_tags
    1819from django.template.loaders import app_directories, filesystem
    1920from django.utils.translation import activate, deactivate, ugettext as _
    2021from django.utils.safestring import mark_safe
     
    215216            if isinstance(vals[2], tuple):
    216217                normal_string_result = vals[2][0]
    217218                invalid_string_result = vals[2][1]
    218                 if '%s' in invalid_string_result:
     219                if (isinstance(invalid_string_result, basestring) and
     220                            '%s' in invalid_string_result):
    219221                    expected_invalid_str = 'INVALID %s'
    220222                    invalid_string_result = invalid_string_result % vals[2][2]
    221223                    template.invalid_var_format_string = True
     
    474476            ### EXCEPTIONS ############################################################
    475477
    476478            # Raise exception for invalid template name
    477             'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
     479            'exception01': ("{% extends 'nonexistent' %}", {}, loader_tags.ExtendsNotFoundError),
    478480
    479481            # Raise exception for invalid template name (in variable)
    480             'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),
     482            'exception02': ("{% extends nonexistent %}", {}, (loader_tags.ExtendsError, loader_tags.ExtendsNotFoundError)),
    481483
    482484            # Raise exception for extra {% extends %} tags
    483485            'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
     
    802804            # Inheritance from a template with a space in its name should work.
    803805            'inheritance29': ("{% extends 'inheritance 28' %}", {}, '!'),
    804806
     807            ### CIRCULAR INHERITANCE EXCEPTIONS #######################################
     808
     809            # Self-extending template
     810            'circularinheritance01': ("{% extends 'circularinheritance01' %}", {}, loader_tags.ExtendsRecursionError),
     811
     812            # Circular extending template
     813            'circularinheritance02': ("{% extends 'circularinheritance04' %}", {}, loader_tags.ExtendsRecursionError),
     814            'circularinheritance03': ("{% extends 'circularinheritance02' %}", {}, loader_tags.ExtendsRecursionError),
     815            'circularinheritance04': ("{% extends 'circularinheritance03' %}", {}, loader_tags.ExtendsRecursionError),
     816
     817            # Self-extending template (by variable)
     818            'circularinheritance05': ("{% extends var %}", {'var': 'circularinheritance05'}, loader_tags.ExtendsRecursionError),
     819
     820            # Circular template (by variable)
     821            'circularinheritance06': ("{% extends var %}", {'var': 'circularinheritance08'}, loader_tags.ExtendsRecursionError),
     822            'circularinheritance07': ("{% extends var %}", {'var': 'circularinheritance06'}, loader_tags.ExtendsRecursionError),
     823            'circularinheritance08': ("{% extends var %}", {'var': 'circularinheritance07'}, loader_tags.ExtendsRecursionError),
     824
    805825            ### I18N ##################################################################
    806826
    807827            # {% spaceless %} tag
Back to Top