Commit df6ad35c authored by Chris Beaven's avatar Chris Beaven
Browse files

Fixed #7153 -- _resolve_lookup now does a better job of resolving callables...

Fixed #7153 -- _resolve_lookup now does a better job of resolving callables and correctly catches all silent_variable_exceptions

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14992 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 6fc7d829
Loading
Loading
Loading
Loading
+29 −38
Original line number Diff line number Diff line
@@ -674,27 +674,13 @@ class Variable(object):
        instead.
        """
        current = context
        try: # catch-all for silent variable failures
            for bit in self.lookups:
                try: # dictionary lookup
                    current = current[bit]
                except (TypeError, AttributeError, KeyError):
                    try: # attribute lookup
                        current = getattr(current, bit)
                    if callable(current):
                        if getattr(current, 'alters_data', False):
                            current = settings.TEMPLATE_STRING_IF_INVALID
                        else:
                            try: # method call (assuming no args required)
                                current = current()
                            except TypeError: # arguments *were* required
                                # GOTCHA: This will also catch any TypeError
                                # raised in the function itself.
                                current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
                            except Exception, e:
                                if getattr(e, 'silent_variable_failure', False):
                                    current = settings.TEMPLATE_STRING_IF_INVALID
                                else:
                                    raise
                    except (TypeError, AttributeError):
                        try: # list-index lookup
                            current = current[int(bit)]
@@ -704,11 +690,16 @@ class Variable(object):
                                TypeError,  # unsubscriptable object
                                ):
                            raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
                except Exception, e:
                    if getattr(e, 'silent_variable_failure', False):
                if callable(current):
                    if getattr(current, 'alters_data', False):
                        current = settings.TEMPLATE_STRING_IF_INVALID
                    else:
                        raise
                        try: # method call (assuming no args required)
                            current = current()
                        except TypeError: # arguments *were* required
                            # GOTCHA: This will also catch any TypeError
                            # raised in the function itself.
                            current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
        except Exception, e:
            if getattr(e, 'silent_variable_failure', False):
                current = settings.TEMPLATE_STRING_IF_INVALID
+32 −0
Original line number Diff line number Diff line
@@ -91,6 +91,21 @@ class SomeClass:
    def method4(self):
        raise SomeOtherException

    def __getitem__(self, key):
        if key == 'silent_fail_key':
            raise SomeException
        elif key == 'noisy_fail_key':
            raise SomeOtherException
        raise KeyError

    def silent_fail_attribute(self):
        raise SomeException
    silent_fail_attribute = property(silent_fail_attribute)

    def noisy_fail_attribute(self):
        raise SomeOtherException
    noisy_fail_attribute = property(noisy_fail_attribute)

class OtherClass:
    def method(self):
        return "OtherClass.method"
@@ -529,6 +544,12 @@ class Templates(unittest.TestCase):
            'basic-syntax35': ("{{ 1 }}", {"1": "abc"}, "1"),
            'basic-syntax36': ("{{ 1.2 }}", {"1": "abc"}, "1.2"),

            # Call methods in the top level of the context
            'basic-syntax37': ('{{ callable }}', {"callable": lambda: "foo bar"}, "foo bar"),

            # Call methods returned from dictionary lookups
            'basic-syntax38': ('{{ var.callable }}', {"var": {"callable": lambda: "foo bar"}}, "foo bar"),

            # List-index syntax allows a template to access a certain item of a subscriptable object.
            'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),

@@ -616,6 +637,17 @@ class Templates(unittest.TestCase):
            #filters should accept empty string constants
            'filter-syntax20': ('{{ ""|default_if_none:"was none" }}', {}, ""),

            # Fail silently for non-callable attribute and dict lookups which
            # raise an exception with a "silent_variable_failure" attribute
            'filter-syntax21': (r'1{{ var.silent_fail_key }}2', {"var": SomeClass()}, ("12", "1INVALID2")),
            'filter-syntax22': (r'1{{ var.silent_fail_attribute }}2', {"var": SomeClass()}, ("12", "1INVALID2")),

            # In attribute and dict lookups that raise an unexpected exception
            # without a "silent_variable_attribute" set to True, the exception
            # propagates
            'filter-syntax23': (r'1{{ var.noisy_fail_key }}2', {"var": SomeClass()}, SomeOtherException),
            'filter-syntax24': (r'1{{ var.noisy_fail_attribute }}2', {"var": SomeClass()}, SomeOtherException),

            ### COMMENT SYNTAX ########################################################
            'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
            'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"),