Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #7153 -- _resolve_lookup now does a better job of resolving cal…

…lables and correctly catches all silent_variable_exceptions

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14992 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit df6ad35c56c270ea04865e43a83b1ff0f35a71f4 1 parent 6fc7d82
Chris Beaven authored December 19, 2010
67  django/template/base.py
@@ -674,46 +674,37 @@ def _resolve_lookup(self, context):
674 674
         instead.
675 675
         """
676 676
         current = context
677  
-        for bit in self.lookups:
678  
-            try: # dictionary lookup
679  
-                current = current[bit]
680  
-            except (TypeError, AttributeError, KeyError):
681  
-                try: # attribute lookup
682  
-                    current = getattr(current, bit)
683  
-                    if callable(current):
684  
-                        if getattr(current, 'alters_data', False):
685  
-                            current = settings.TEMPLATE_STRING_IF_INVALID
686  
-                        else:
687  
-                            try: # method call (assuming no args required)
688  
-                                current = current()
689  
-                            except TypeError: # arguments *were* required
690  
-                                # GOTCHA: This will also catch any TypeError
691  
-                                # raised in the function itself.
692  
-                                current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
693  
-                            except Exception, e:
694  
-                                if getattr(e, 'silent_variable_failure', False):
695  
-                                    current = settings.TEMPLATE_STRING_IF_INVALID
696  
-                                else:
697  
-                                    raise
698  
-                except (TypeError, AttributeError):
699  
-                    try: # list-index lookup
700  
-                        current = current[int(bit)]
701  
-                    except (IndexError, # list index out of range
702  
-                            ValueError, # invalid literal for int()
703  
-                            KeyError,   # current is a dict without `int(bit)` key
704  
-                            TypeError,  # unsubscriptable object
705  
-                            ):
706  
-                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
707  
-                except Exception, e:
708  
-                    if getattr(e, 'silent_variable_failure', False):
  677
+        try: # catch-all for silent variable failures
  678
+            for bit in self.lookups:
  679
+                try: # dictionary lookup
  680
+                    current = current[bit]
  681
+                except (TypeError, AttributeError, KeyError):
  682
+                    try: # attribute lookup
  683
+                        current = getattr(current, bit)
  684
+                    except (TypeError, AttributeError):
  685
+                        try: # list-index lookup
  686
+                            current = current[int(bit)]
  687
+                        except (IndexError, # list index out of range
  688
+                                ValueError, # invalid literal for int()
  689
+                                KeyError,   # current is a dict without `int(bit)` key
  690
+                                TypeError,  # unsubscriptable object
  691
+                                ):
  692
+                            raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
  693
+                if callable(current):
  694
+                    if getattr(current, 'alters_data', False):
709 695
                         current = settings.TEMPLATE_STRING_IF_INVALID
710 696
                     else:
711  
-                        raise
712  
-            except Exception, e:
713  
-                if getattr(e, 'silent_variable_failure', False):
714  
-                    current = settings.TEMPLATE_STRING_IF_INVALID
715  
-                else:
716  
-                    raise
  697
+                        try: # method call (assuming no args required)
  698
+                            current = current()
  699
+                        except TypeError: # arguments *were* required
  700
+                            # GOTCHA: This will also catch any TypeError
  701
+                            # raised in the function itself.
  702
+                            current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
  703
+        except Exception, e:
  704
+            if getattr(e, 'silent_variable_failure', False):
  705
+                current = settings.TEMPLATE_STRING_IF_INVALID
  706
+            else:
  707
+                raise
717 708
 
718 709
         return current
719 710
 
32  tests/regressiontests/templates/tests.py
@@ -91,6 +91,21 @@ def method3(self):
91 91
     def method4(self):
92 92
         raise SomeOtherException
93 93
 
  94
+    def __getitem__(self, key):
  95
+        if key == 'silent_fail_key':
  96
+            raise SomeException
  97
+        elif key == 'noisy_fail_key':
  98
+            raise SomeOtherException
  99
+        raise KeyError
  100
+
  101
+    def silent_fail_attribute(self):
  102
+        raise SomeException
  103
+    silent_fail_attribute = property(silent_fail_attribute)
  104
+
  105
+    def noisy_fail_attribute(self):
  106
+        raise SomeOtherException
  107
+    noisy_fail_attribute = property(noisy_fail_attribute)
  108
+
94 109
 class OtherClass:
95 110
     def method(self):
96 111
         return "OtherClass.method"
@@ -529,6 +544,12 @@ def get_template_tests(self):
529 544
             'basic-syntax35': ("{{ 1 }}", {"1": "abc"}, "1"),
530 545
             'basic-syntax36': ("{{ 1.2 }}", {"1": "abc"}, "1.2"),
531 546
 
  547
+            # Call methods in the top level of the context
  548
+            'basic-syntax37': ('{{ callable }}', {"callable": lambda: "foo bar"}, "foo bar"),
  549
+
  550
+            # Call methods returned from dictionary lookups
  551
+            'basic-syntax38': ('{{ var.callable }}', {"var": {"callable": lambda: "foo bar"}}, "foo bar"),
  552
+
532 553
             # List-index syntax allows a template to access a certain item of a subscriptable object.
533 554
             'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
534 555
 
@@ -616,6 +637,17 @@ def get_template_tests(self):
616 637
             #filters should accept empty string constants
617 638
             'filter-syntax20': ('{{ ""|default_if_none:"was none" }}', {}, ""),
618 639
 
  640
+            # Fail silently for non-callable attribute and dict lookups which
  641
+            # raise an exception with a "silent_variable_failure" attribute
  642
+            'filter-syntax21': (r'1{{ var.silent_fail_key }}2', {"var": SomeClass()}, ("12", "1INVALID2")),
  643
+            'filter-syntax22': (r'1{{ var.silent_fail_attribute }}2', {"var": SomeClass()}, ("12", "1INVALID2")),
  644
+
  645
+            # In attribute and dict lookups that raise an unexpected exception
  646
+            # without a "silent_variable_attribute" set to True, the exception
  647
+            # propagates
  648
+            'filter-syntax23': (r'1{{ var.noisy_fail_key }}2', {"var": SomeClass()}, SomeOtherException),
  649
+            'filter-syntax24': (r'1{{ var.noisy_fail_attribute }}2', {"var": SomeClass()}, SomeOtherException),
  650
+
619 651
             ### COMMENT SYNTAX ########################################################
620 652
             'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
621 653
             'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"),

0 notes on commit df6ad35

Please sign in to comment.
Something went wrong with that request. Please try again.