Ticket #7153: 7153.2.diff

File 7153.2.diff, 6.9 KB (added by Chris Beaven, 15 years ago)

another test, and also adding catching silent variable failures everywhere (with tests)

  • django/template/__init__.py

    ### Eclipse Workspace Patch 1.0
    #P Django trunk
     
    708708        instead.
    709709        """
    710710        current = context
    711         for bit in self.lookups:
    712             try: # dictionary lookup
    713                 current = current[bit]
    714             except (TypeError, AttributeError, KeyError):
    715                 try: # attribute lookup
    716                     current = getattr(current, bit)
    717                     if callable(current):
    718                         if getattr(current, 'alters_data', False):
    719                             current = settings.TEMPLATE_STRING_IF_INVALID
    720                         else:
    721                             try: # method call (assuming no args required)
    722                                 current = current()
    723                             except TypeError: # arguments *were* required
    724                                 # GOTCHA: This will also catch any TypeError
    725                                 # raised in the function itself.
    726                                 current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
    727                             except Exception, e:
    728                                 if getattr(e, 'silent_variable_failure', False):
    729                                     current = settings.TEMPLATE_STRING_IF_INVALID
    730                                 else:
    731                                     raise
    732                 except (TypeError, AttributeError):
    733                     try: # list-index lookup
    734                         current = current[int(bit)]
    735                     except (IndexError, # list index out of range
    736                             ValueError, # invalid literal for int()
    737                             KeyError,   # current is a dict without `int(bit)` key
    738                             TypeError,  # unsubscriptable object
    739                             ):
    740                         raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
    741                 except Exception, e:
    742                     if getattr(e, 'silent_variable_failure', False):
    743                         current = settings.TEMPLATE_STRING_IF_INVALID
     711        try: # catch-all for silent variable failures
     712            for bit in self.lookups:
     713                try: # dictionary lookup
     714                    current = current[bit]
     715                except (TypeError, AttributeError, KeyError):
     716                    try: # attribute lookup
     717                        current = getattr(current, bit)
     718                    except (TypeError, AttributeError):
     719                        try: # list-index lookup
     720                            current = current[int(bit)]
     721                        except (IndexError, # list index out of range
     722                                ValueError, # invalid literal for int()
     723                                KeyError,   # current is a dict without `int(bit)` key
     724                                TypeError,  # unsubscriptable object
     725                                ):
     726                            raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
     727                if callable(current):
     728                    if getattr(current, 'alters_data', False):
     729                        return settings.TEMPLATE_STRING_IF_INVALID
    744730                    else:
    745                         raise
     731                        try: # method call (assuming no args required)
     732                            current = current()
     733                        except TypeError: # arguments *were* required
     734                            # GOTCHA: This will also catch any TypeError
     735                            # raised in the function itself.
     736                            return settings.TEMPLATE_STRING_IF_INVALID # invalid method call
     737        except Exception, e:
     738            if getattr(e, 'silent_variable_failure', False):
     739                return settings.TEMPLATE_STRING_IF_INVALID
     740            else:
     741                raise
    746742
    747743        return current
    748744
  • tests/regressiontests/templates/tests.py

     
    8989    def method4(self):
    9090        raise SomeOtherException
    9191
     92    def __getitem__(self, key):
     93        if key == 'silent_fail_key':
     94            raise SomeException
     95        elif key == 'noisy_fail_key':
     96            raise SomeOtherException
     97        raise KeyError
     98   
     99    def silent_fail_attribute(self):
     100        raise SomeException
     101    silent_fail_attribute = property(silent_fail_attribute)
     102
     103    def noisy_fail_attribute(self):
     104        raise SomeOtherException
     105    noisy_fail_attribute = property(noisy_fail_attribute)
     106
    92107class OtherClass:
    93108    def method(self):
    94109        return "OtherClass.method"
     
    340355            'basic-syntax25': ('{{ "fred" }}', {}, "fred"),
    341356            'basic-syntax26': (r'{{ "\"fred\"" }}', {}, "\"fred\""),
    342357            'basic-syntax27': (r'{{ _("\"fred\"") }}', {}, "\"fred\""),
     358           
     359            # Call methods in the top level of the context
     360            'basic-syntax28': (r'{{ callable }}', {"callable": lambda: "foo bar"}, "foo bar"),
     361           
     362            # Call methods returned from dictionary lookups
     363            'basic-syntax29': (r'{{ var.callable }}', {"var": {"callable": lambda: "foo bar"}}, "foo bar"),
    343364
    344365            # List-index syntax allows a template to access a certain item of a subscriptable object.
    345366            'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
     
    428449            #filters should accept empty string constants
    429450            'filter-syntax20': ('{{ ""|default_if_none:"was none" }}', {}, ""),
    430451
     452            # Fail silently for non-callable attribute and dict lookups which
     453            # raise an exception with a "silent_variable_failure" attribute
     454            'filter-syntax21': (r'1{{ var.silent_fail_key }}2', {"var": SomeClass()}, ("12", "1INVALID2")),
     455            'filter-syntax22': (r'1{{ var.silent_fail_attribute }}2', {"var": SomeClass()}, ("12", "1INVALID2")),
     456
     457            # In attribute and dict lookups that raise an unexpected exception
     458            # without a "silent_variable_attribute" set to True, the exception
     459            # propagates
     460            'filter-syntax23': (r'1{{ var.noisy_fail_key }}2', {"var": SomeClass()}, SomeOtherException),
     461            'filter-syntax24': (r'1{{ var.noisy_fail_attribute }}2', {"var": SomeClass()}, SomeOtherException),
     462
    431463            ### COMMENT SYNTAX ########################################################
    432464            'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
    433465            'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"),
Back to Top