Author: SmileyChris
Date: 2010-12-19 17:47:24 -0600 (Sun, 19 Dec 2010)
New Revision: 14992

Modified:
   django/trunk/django/template/base.py
   django/trunk/tests/regressiontests/templates/tests.py
Log:
Fixed #7153 -- _resolve_lookup now does a better job of resolving callables and 
correctly catches all silent_variable_exceptions

Modified: django/trunk/django/template/base.py
===================================================================
--- django/trunk/django/template/base.py        2010-12-19 19:20:25 UTC (rev 
14991)
+++ django/trunk/django/template/base.py        2010-12-19 23:47:24 UTC (rev 
14992)
@@ -674,46 +674,37 @@
         instead.
         """
         current = context
-        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)]
-                    except (IndexError, # list index out of range
-                            ValueError, # invalid literal for int()
-                            KeyError,   # current is a dict without `int(bit)` 
key
-                            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):
+        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)
+                    except (TypeError, AttributeError):
+                        try: # list-index lookup
+                            current = current[int(bit)]
+                        except (IndexError, # list index out of range
+                                ValueError, # invalid literal for int()
+                                KeyError,   # current is a dict without 
`int(bit)` key
+                                TypeError,  # unsubscriptable object
+                                ):
+                            raise VariableDoesNotExist("Failed lookup for key 
[%s] in %r", (bit, current)) # missing attribute
+                if callable(current):
+                    if getattr(current, 'alters_data', False):
                         current = settings.TEMPLATE_STRING_IF_INVALID
                     else:
-                        raise
-            except Exception, e:
-                if getattr(e, 'silent_variable_failure', 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
+            else:
+                raise
 
         return current
 

Modified: django/trunk/tests/regressiontests/templates/tests.py
===================================================================
--- django/trunk/tests/regressiontests/templates/tests.py       2010-12-19 
19:20:25 UTC (rev 14991)
+++ django/trunk/tests/regressiontests/templates/tests.py       2010-12-19 
23:47:24 UTC (rev 14992)
@@ -91,6 +91,21 @@
     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 @@
             '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 @@
             #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"),

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to