Code

Ticket #7153: 7153.2.diff

File 7153.2.diff, 6.9 KB (added by SmileyChris, 5 years ago)

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

Line 
1### Eclipse Workspace Patch 1.0
2#P Django trunk
3Index: django/template/__init__.py
4===================================================================
5--- django/template/__init__.py (revision 11447)
6+++ django/template/__init__.py (working copy)
7@@ -708,41 +708,37 @@
8         instead.
9         """
10         current = context
11-        for bit in self.lookups:
12-            try: # dictionary lookup
13-                current = current[bit]
14-            except (TypeError, AttributeError, KeyError):
15-                try: # attribute lookup
16-                    current = getattr(current, bit)
17-                    if callable(current):
18-                        if getattr(current, 'alters_data', False):
19-                            current = settings.TEMPLATE_STRING_IF_INVALID
20-                        else:
21-                            try: # method call (assuming no args required)
22-                                current = current()
23-                            except TypeError: # arguments *were* required
24-                                # GOTCHA: This will also catch any TypeError
25-                                # raised in the function itself.
26-                                current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
27-                            except Exception, e:
28-                                if getattr(e, 'silent_variable_failure', False):
29-                                    current = settings.TEMPLATE_STRING_IF_INVALID
30-                                else:
31-                                    raise
32-                except (TypeError, AttributeError):
33-                    try: # list-index lookup
34-                        current = current[int(bit)]
35-                    except (IndexError, # list index out of range
36-                            ValueError, # invalid literal for int()
37-                            KeyError,   # current is a dict without `int(bit)` key
38-                            TypeError,  # unsubscriptable object
39-                            ):
40-                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
41-                except Exception, e:
42-                    if getattr(e, 'silent_variable_failure', False):
43-                        current = settings.TEMPLATE_STRING_IF_INVALID
44+        try: # catch-all for silent variable failures
45+            for bit in self.lookups:
46+                try: # dictionary lookup
47+                    current = current[bit]
48+                except (TypeError, AttributeError, KeyError):
49+                    try: # attribute lookup
50+                        current = getattr(current, bit)
51+                    except (TypeError, AttributeError):
52+                        try: # list-index lookup
53+                            current = current[int(bit)]
54+                        except (IndexError, # list index out of range
55+                                ValueError, # invalid literal for int()
56+                                KeyError,   # current is a dict without `int(bit)` key
57+                                TypeError,  # unsubscriptable object
58+                                ):
59+                            raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
60+                if callable(current):
61+                    if getattr(current, 'alters_data', False):
62+                        return settings.TEMPLATE_STRING_IF_INVALID
63                     else:
64-                        raise
65+                        try: # method call (assuming no args required)
66+                            current = current()
67+                        except TypeError: # arguments *were* required
68+                            # GOTCHA: This will also catch any TypeError
69+                            # raised in the function itself.
70+                            return settings.TEMPLATE_STRING_IF_INVALID # invalid method call
71+        except Exception, e:
72+            if getattr(e, 'silent_variable_failure', False):
73+                return settings.TEMPLATE_STRING_IF_INVALID
74+            else:
75+                raise
76 
77         return current
78 
79Index: tests/regressiontests/templates/tests.py
80===================================================================
81--- tests/regressiontests/templates/tests.py    (revision 11447)
82+++ tests/regressiontests/templates/tests.py    (working copy)
83@@ -89,6 +89,21 @@
84     def method4(self):
85         raise SomeOtherException
86 
87+    def __getitem__(self, key):
88+        if key == 'silent_fail_key':
89+            raise SomeException
90+        elif key == 'noisy_fail_key':
91+            raise SomeOtherException
92+        raise KeyError
93+   
94+    def silent_fail_attribute(self):
95+        raise SomeException
96+    silent_fail_attribute = property(silent_fail_attribute)
97+
98+    def noisy_fail_attribute(self):
99+        raise SomeOtherException
100+    noisy_fail_attribute = property(noisy_fail_attribute)
101+
102 class OtherClass:
103     def method(self):
104         return "OtherClass.method"
105@@ -340,6 +355,12 @@
106             'basic-syntax25': ('{{ "fred" }}', {}, "fred"),
107             'basic-syntax26': (r'{{ "\"fred\"" }}', {}, "\"fred\""),
108             'basic-syntax27': (r'{{ _("\"fred\"") }}', {}, "\"fred\""),
109+           
110+            # Call methods in the top level of the context
111+            'basic-syntax28': (r'{{ callable }}', {"callable": lambda: "foo bar"}, "foo bar"),
112+           
113+            # Call methods returned from dictionary lookups
114+            'basic-syntax29': (r'{{ var.callable }}', {"var": {"callable": lambda: "foo bar"}}, "foo bar"),
115 
116             # List-index syntax allows a template to access a certain item of a subscriptable object.
117             'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
118@@ -428,6 +449,17 @@
119             #filters should accept empty string constants
120             'filter-syntax20': ('{{ ""|default_if_none:"was none" }}', {}, ""),
121 
122+            # Fail silently for non-callable attribute and dict lookups which
123+            # raise an exception with a "silent_variable_failure" attribute
124+            'filter-syntax21': (r'1{{ var.silent_fail_key }}2', {"var": SomeClass()}, ("12", "1INVALID2")),
125+            'filter-syntax22': (r'1{{ var.silent_fail_attribute }}2', {"var": SomeClass()}, ("12", "1INVALID2")),
126+
127+            # In attribute and dict lookups that raise an unexpected exception
128+            # without a "silent_variable_attribute" set to True, the exception
129+            # propagates
130+            'filter-syntax23': (r'1{{ var.noisy_fail_key }}2', {"var": SomeClass()}, SomeOtherException),
131+            'filter-syntax24': (r'1{{ var.noisy_fail_attribute }}2', {"var": SomeClass()}, SomeOtherException),
132+
133             ### COMMENT SYNTAX ########################################################
134             'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
135             'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"),