#12554 closed (fixed)
silent_variable_failure not suppressing exception during dict lookup
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Template system | Version: | dev |
Severity: | Keywords: | ||
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
Example:
from django.template import Context, Template class E(Exception): silent_variable_failure = True class A(object): def __getitem__(self, key): raise E t = Template("{{ a.b }}") t.render(Context({"a": A()}))
According to Django docs, the exception should be suppresed and an empty string should be returned. However, instead, Django raises the exception:
--------------------------------------------------------------------------- TemplateSyntaxError Traceback (most recent call last) /home/user/user/<ipython console> in <module>() /usr/lib/python2.5/site-packages/django/template/__init__.pyc in render(self, context) 176 def render(self, context): 177 "Display stage -- can be called many times" --> 178 return self.nodelist.render(context) 179 180 def compile_string(template_string, origin): /usr/lib/python2.5/site-packages/django/template/__init__.pyc in render(self, context) 777 for node in self: 778 if isinstance(node, Node): --> 779 bits.append(self.render_node(node, context)) 780 else: 781 bits.append(node) /usr/lib/python2.5/site-packages/django/template/debug.py in render_node(self, node, context) 79 wrapped.source = node.source 80 wrapped.exc_info = exc_info() ---> 81 raise wrapped 82 return result 83 TemplateSyntaxError: Caught an exception while rendering: Original Traceback (most recent call last): File "/usr/lib/python2.5/site-packages/django/template/debug.py", line 71, in render_node result = node.render(context) File "/usr/lib/python2.5/site-packages/django/template/debug.py", line 87, in render output = force_unicode(self.filter_expression.resolve(context)) File "/usr/lib/python2.5/site-packages/django/template/__init__.py", line 546, in resolve obj = self.var.resolve(context) File "/usr/lib/python2.5/site-packages/django/template/__init__.py", line 687, in resolve value = self._resolve_lookup(context) File "/usr/lib/python2.5/site-packages/django/template/__init__.py", line 713, in _resolve_lookup current = current[bit] File "<ipython console>", line 4, in __getitem__ E
Proposed patch:
Index: django/template/__init__.py =================================================================== --- django/template/__init__.py (revision 11929) +++ django/template/__init__.py (working copy) @@ -745,11 +745,11 @@ 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): - 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 return current
Attachments (3)
Change History (16)
comment:1 by , 15 years ago
milestone: | → 1.2 |
---|---|
Patch needs improvement: | set |
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 15 years ago
comment:3 by , 15 years ago
I realized I wasn't working from the trunk. Here is a real proposed patch:
=================================================================== --- __init__.py (revision 12610) +++ __init__.py (working copy) @@ -583,7 +583,24 @@ if not lookup: arg_vals.append(mark_safe(arg)) else: - arg_vals.append(arg.resolve(context)) + #arg_vals.append(arg.resolve(context)) + try: + arg_val = arg.resolve(context) + except VariableDoesNotExist: + if ignore_failures: + arg_val = None + else: + if settings.TEMPLATE_STRING_IF_INVALID: + global invalid_var_format_string + if invalid_var_format_string is None: + invalid_var_format_string = '%s' in settings.TEMPLATE_STRING_IF_INVALID + if invalid_var_format_string: + arg_val= settings.TEMPLATE_STRING_IF_INVALID % self.var + else: + arg_val= settings.TEMPLATE_STRING_IF_INVALID + else: + arg_val = settings.TEMPLATE_STRING_IF_INVALID + arg_vals.append(arg_val) if getattr(func, 'needs_autoescape', False): Here is a test case: >>> from django.template import Context, Template >>> t = Template("{{'test'|default:notreal}}") >>> t.render(Context()) Traceback (most recent call last): File "<console>", line 1, in <module> File "/opt/local/OnQueue2/OQTools/pythonlib/trunk/django/template/__init__.py", line 184, in render return self._render(context) File "/opt/local/OnQueue2/OQTools/pythonlib/trunk/django/template/__init__.py", line 178, in _render return self.nodelist.render(context) File "/opt/local/OnQueue2/OQTools/pythonlib/trunk/django/template/__init__.py", line 799, in render bits.append(self.render_node(node, context)) File "/opt/local/OnQueue2/OQTools/pythonlib/trunk/django/template/debug.py", line 82, in render_node raise wrapped TemplateSyntaxError: Caught an exception while rendering: Failed lookup for key [notreal] in u'[{}]'
comment:4 by , 15 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:5 by , 15 years ago
Owner: | changed from | to
---|---|
Status: | assigned → new |
comment:6 by , 15 years ago
This looks to me like two different problems: the problem in the original description regarding an exception with silent_variable_failure=True not being silenced, and a different problem with non-existent variables passed to filters raising exceptions. I'd like to narrow the focus of this ticket to the first problem, which seems clearly wrong. (I'm less sure of what the right behavior is supposed to be for the 2nd situation.)
comment:7 by , 15 years ago
Since we're not sure what should happen in the template filter scenario, I opened #13167.
comment:8 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:9 by , 15 years ago
comment:10 by , 15 years ago
Resolution: | fixed |
---|---|
Status: | closed → reopened |
When I do this:
from django.template import Context, Template from myapp.models import MyModel MyModel(models.Model): some = model.OneToOneField(AnotherModel) obj = MyModel.objects.get(id=1) t = Template("{{ obj.some }}") t.render(Context({"obj": obj}))
Django raises the exception:
--------------------------------------------------------------------------- TemplateSyntaxError Traceback (most recent call last) /home/alejandro/inmegen/<ipython console> in <module>() /usr/lib/python2.6/site-packages/django/template/__init__.pyc in render(self, context) 169 context.render_context.push() 170 try: --> 171 return self._render(context) 172 finally: 173 context.render_context.pop() /usr/lib/python2.6/site-packages/django/template/__init__.pyc in _render(self, context) 163 164 def _render(self, context): --> 165 return self.nodelist.render(context) 166 167 def render(self, context): /usr/lib/python2.6/site-packages/django/template/__init__.pyc in render(self, context) 795 for node in self: 796 if isinstance(node, Node): --> 797 bits.append(self.render_node(node, context)) 798 else: 799 bits.append(node) TemplateSyntaxError: Caught DoesNotExist while rendering: AnotherModel matching query does not exist.
Proposed patch:
Index: django/template/__init__.py =================================================================== --- django/template/__init__.py (revision 12823) +++ django/template/__init__.py (working copy) @@ -745,6 +745,11 @@ 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): + current = settings.TEMPLATE_STRING_IF_INVALID + else: + raise except Exception, e: if getattr(e, 'silent_variable_failure', False): current = settings.TEMPLATE_STRING_IF_INVALID
comment:11 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | reopened → closed |
The same error occurs when a variable that doesn't exist is referenced as the argument of a filter
for example:
The stack trace shows the problem to be the naked call to resolve at around line 576:
My quick fix was to duplicate much of the exception logic used in the primary case just above:
However, it seems to me that Variable.resolve() should be taking care of the settings.TEMPLATE_STRING_IF_INVALID semantic, not FilterExpression.
The patch suggested doesn't seem to do anything since VariableDoesNotExist is not derived from ObjectDoesNotExist. I did not use it.