Fixes #1338, Refs #1400, #2237 -- Modified variable resolution to allow template 'if' statements to work if TEMPLATE_STRING_IF_INVALID is set. Modified unit tests to force the use of this variable, so that returning '' isn't confused with an actual failure.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@3268 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2006-07-04 03:21:44 +00:00
parent 009f224e57
commit 6b383afd39
4 changed files with 32 additions and 16 deletions

View File

@ -318,7 +318,7 @@ class Parser(object):
self.tags.update(lib.tags)
self.filters.update(lib.filters)
def compile_filter(self,token):
def compile_filter(self, token):
"Convenient wrapper for FilterExpression"
return FilterExpression(token, self)
@ -543,11 +543,14 @@ class FilterExpression(object):
raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:]
self.var, self.filters = var, filters
def resolve(self, context):
def resolve(self, context, ignore_failures=False):
try:
obj = resolve_variable(self.var, context)
except VariableDoesNotExist:
obj = settings.TEMPLATE_STRING_IF_INVALID
if ignore_failures:
return None
else:
return settings.TEMPLATE_STRING_IF_INVALID
for func, args in self.filters:
arg_vals = []
for lookup, arg in args:

View File

@ -37,7 +37,7 @@ class Context(object):
for d in self.dicts:
if d.has_key(key):
return d[key]
return settings.TEMPLATE_STRING_IF_INVALID
raise KeyError(key)
def __delitem__(self, key):
"Delete a variable from the current context"
@ -49,7 +49,7 @@ class Context(object):
return True
return False
def get(self, key, otherwise):
def get(self, key, otherwise=None):
for d in self.dicts:
if d.has_key(key):
return d[key]

View File

@ -45,7 +45,10 @@ class FirstOfNode(Node):
def render(self, context):
for var in self.vars:
try:
value = resolve_variable(var, context)
except VariableDoesNotExist:
continue
if value:
return str(value)
return ''
@ -144,8 +147,14 @@ class IfEqualNode(Node):
return "<IfEqualNode>"
def render(self, context):
try:
val1 = resolve_variable(self.var1, context)
except VariableDoesNotExist:
val1 = None
try:
val2 = resolve_variable(self.var2, context)
except VariableDoesNotExist:
val2 = None
if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
return self.nodelist_true.render(context)
return self.nodelist_false.render(context)
@ -177,7 +186,7 @@ class IfNode(Node):
if self.link_type == IfNode.LinkTypes.or_:
for ifnot, bool_expr in self.bool_exprs:
try:
value = bool_expr.resolve(context)
value = bool_expr.resolve(context, True)
except VariableDoesNotExist:
value = None
if (value and not ifnot) or (ifnot and not value):
@ -186,7 +195,7 @@ class IfNode(Node):
else:
for ifnot, bool_expr in self.bool_exprs:
try:
value = bool_expr.resolve(context)
value = bool_expr.resolve(context, True)
except VariableDoesNotExist:
value = None
if not ((value and not ifnot) or (ifnot and not value)):

View File

@ -78,7 +78,7 @@ TEMPLATE_TESTS = {
'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
# Fail silently when a variable is not found in the current context
'basic-syntax04': ("as{{ missing }}df", {}, "asdf"),
'basic-syntax04': ("as{{ missing }}df", {}, "asINVALIDdf"),
# A variable may not contain more than one word
'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
@ -94,7 +94,7 @@ TEMPLATE_TESTS = {
'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
# Fail silently when a variable's attribute isn't found
'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ""),
'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "INVALID"),
# Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
@ -110,10 +110,10 @@ TEMPLATE_TESTS = {
'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
# Fail silently when a variable's dictionary key isn't found
'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ""),
'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "INVALID"),
# Fail silently when accessing a non-simple method
'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ""),
'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "INVALID"),
# Basic filter usage
'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
@ -152,7 +152,7 @@ TEMPLATE_TESTS = {
'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),
# Fail silently for methods that raise an exception with a "silent_variable_failure" attribute
'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "12"),
'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1INVALID2"),
# In methods that raise an exception without a "silent_variable_attribute" set to True,
# the exception propogates
@ -495,7 +495,7 @@ TEMPLATE_TESTS = {
'{{ item.foo }}' + \
'{% endfor %},' + \
'{% endfor %}',
{}, ''),
{}, 'INVALID:INVALIDINVALIDINVALIDINVALIDINVALIDINVALIDINVALID,'),
### TEMPLATETAG TAG #######################################################
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
@ -579,6 +579,9 @@ def run_tests(verbosity=0, standalone=False):
# Turn TEMPLATE_DEBUG off, because tests assume that.
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False
# Set TEMPLATE_STRING_IF_INVALID to a known string
old_invalid, settings.TEMPLATE_STRING_IF_INVALID = settings.TEMPLATE_STRING_IF_INVALID, 'INVALID'
for name, vals in tests:
install()
if 'LANGUAGE_CODE' in vals[1]:
@ -609,6 +612,7 @@ def run_tests(verbosity=0, standalone=False):
loader.template_source_loaders = old_template_loaders
deactivate()
settings.TEMPLATE_DEBUG = old_td
settings.TEMPLATE_STRING_IF_INVALID = old_invalid
if failed_tests and not standalone:
msg = "Template tests %s failed." % failed_tests