Loading django/template/base.py +7 −24 Original line number Diff line number Diff line Loading @@ -622,34 +622,17 @@ class FilterExpression(object): def args_check(name, func, provided): provided = list(provided) plen = len(provided) # First argument, filter input, is implied. plen = len(provided) + 1 # Check to see if a decorator is providing the real function. func = getattr(func, '_decorated_function', func) args, varargs, varkw, defaults = getargspec(func) # First argument is filter input. args.pop(0) if defaults: nondefs = args[:-len(defaults)] else: nondefs = args # Args without defaults must be provided. try: for arg in nondefs: provided.pop(0) except IndexError: # Not enough raise TemplateSyntaxError("%s requires %d arguments, %d provided" % (name, len(nondefs), plen)) # Defaults can be overridden. defaults = list(defaults) if defaults else [] try: for parg in provided: defaults.pop(0) except IndexError: # Too many. alen = len(args) dlen = len(defaults or []) # Not enough OR Too many if plen < (alen - dlen) or plen > alen: raise TemplateSyntaxError("%s requires %d arguments, %d provided" % (name, len(nondefs), plen)) (name, alen - dlen, plen)) return True args_check = staticmethod(args_check) Loading tests/template_tests/test_parser.py +40 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ from __future__ import unicode_literals from unittest import TestCase from django.template import (TokenParser, FilterExpression, Parser, Variable, Template, TemplateSyntaxError) Template, TemplateSyntaxError, Library) from django.test.utils import override_settings from django.utils import six Loading Loading @@ -94,3 +94,42 @@ class ParserTests(TestCase): with six.assertRaisesRegex(self, TemplateSyntaxError, msg) as cm: Template("{% if 1 %}{{ foo@bar }}{% endif %}") self.assertEqual(cm.exception.django_template_source[1], (10, 23)) def test_filter_args_count(self): p = Parser("") l = Library() @l.filter def no_arguments(value): pass @l.filter def one_argument(value, arg): pass @l.filter def one_opt_argument(value, arg=False): pass @l.filter def two_arguments(value, arg, arg2): pass @l.filter def two_one_opt_arg(value, arg, arg2=False): pass p.add_library(l) for expr in ( '1|no_arguments:"1"', '1|two_arguments', '1|two_arguments:"1"', '1|two_one_opt_arg', ): with self.assertRaises(TemplateSyntaxError): FilterExpression(expr, p) for expr in ( # Correct number of arguments '1|no_arguments', '1|one_argument:"1"', # One optional '1|one_opt_argument', '1|one_opt_argument:"1"', # Not supplying all '1|two_one_opt_arg:"1"', ): FilterExpression(expr, p) Loading
django/template/base.py +7 −24 Original line number Diff line number Diff line Loading @@ -622,34 +622,17 @@ class FilterExpression(object): def args_check(name, func, provided): provided = list(provided) plen = len(provided) # First argument, filter input, is implied. plen = len(provided) + 1 # Check to see if a decorator is providing the real function. func = getattr(func, '_decorated_function', func) args, varargs, varkw, defaults = getargspec(func) # First argument is filter input. args.pop(0) if defaults: nondefs = args[:-len(defaults)] else: nondefs = args # Args without defaults must be provided. try: for arg in nondefs: provided.pop(0) except IndexError: # Not enough raise TemplateSyntaxError("%s requires %d arguments, %d provided" % (name, len(nondefs), plen)) # Defaults can be overridden. defaults = list(defaults) if defaults else [] try: for parg in provided: defaults.pop(0) except IndexError: # Too many. alen = len(args) dlen = len(defaults or []) # Not enough OR Too many if plen < (alen - dlen) or plen > alen: raise TemplateSyntaxError("%s requires %d arguments, %d provided" % (name, len(nondefs), plen)) (name, alen - dlen, plen)) return True args_check = staticmethod(args_check) Loading
tests/template_tests/test_parser.py +40 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ from __future__ import unicode_literals from unittest import TestCase from django.template import (TokenParser, FilterExpression, Parser, Variable, Template, TemplateSyntaxError) Template, TemplateSyntaxError, Library) from django.test.utils import override_settings from django.utils import six Loading Loading @@ -94,3 +94,42 @@ class ParserTests(TestCase): with six.assertRaisesRegex(self, TemplateSyntaxError, msg) as cm: Template("{% if 1 %}{{ foo@bar }}{% endif %}") self.assertEqual(cm.exception.django_template_source[1], (10, 23)) def test_filter_args_count(self): p = Parser("") l = Library() @l.filter def no_arguments(value): pass @l.filter def one_argument(value, arg): pass @l.filter def one_opt_argument(value, arg=False): pass @l.filter def two_arguments(value, arg, arg2): pass @l.filter def two_one_opt_arg(value, arg, arg2=False): pass p.add_library(l) for expr in ( '1|no_arguments:"1"', '1|two_arguments', '1|two_arguments:"1"', '1|two_one_opt_arg', ): with self.assertRaises(TemplateSyntaxError): FilterExpression(expr, p) for expr in ( # Correct number of arguments '1|no_arguments', '1|one_argument:"1"', # One optional '1|one_opt_argument', '1|one_opt_argument:"1"', # Not supplying all '1|two_one_opt_arg:"1"', ): FilterExpression(expr, p)