mirror of
https://github.com/django/django.git
synced 2025-08-21 17:29:13 +00:00
* Refs #35816 -- Improved test coverage of FilterExpression. * Fixed #35816 -- Made FilterExpression parse scientific numbers. --------- Co-authored-by: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com>
This commit is contained in:
parent
8df5ce80d2
commit
5183f7c287
@ -633,19 +633,18 @@ constant_string = constant_string.replace("\n", "")
|
|||||||
|
|
||||||
filter_raw_string = r"""
|
filter_raw_string = r"""
|
||||||
^(?P<constant>%(constant)s)|
|
^(?P<constant>%(constant)s)|
|
||||||
^(?P<var>[%(var_chars)s]+|%(num)s)|
|
^(?P<var>[%(var_chars)s]+)|
|
||||||
(?:\s*%(filter_sep)s\s*
|
(?:\s*%(filter_sep)s\s*
|
||||||
(?P<filter_name>\w+)
|
(?P<filter_name>\w+)
|
||||||
(?:%(arg_sep)s
|
(?:%(arg_sep)s
|
||||||
(?:
|
(?:
|
||||||
(?P<constant_arg>%(constant)s)|
|
(?P<constant_arg>%(constant)s)|
|
||||||
(?P<var_arg>[%(var_chars)s]+|%(num)s)
|
(?P<var_arg>[%(var_chars)s]+)
|
||||||
)
|
)
|
||||||
)?
|
)?
|
||||||
)""" % {
|
)""" % {
|
||||||
"constant": constant_string,
|
"constant": constant_string,
|
||||||
"num": r"[-+.]?\d[\d.e]*",
|
"var_chars": r"\w\.\+-",
|
||||||
"var_chars": r"\w\.",
|
|
||||||
"filter_sep": re.escape(FILTER_SEPARATOR),
|
"filter_sep": re.escape(FILTER_SEPARATOR),
|
||||||
"arg_sep": re.escape(FILTER_ARGUMENT_SEPARATOR),
|
"arg_sep": re.escape(FILTER_ARGUMENT_SEPARATOR),
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ from django.template.base import (
|
|||||||
Token,
|
Token,
|
||||||
TokenType,
|
TokenType,
|
||||||
Variable,
|
Variable,
|
||||||
|
VariableDoesNotExist,
|
||||||
)
|
)
|
||||||
from django.template.defaultfilters import register as filter_library
|
from django.template.defaultfilters import register as filter_library
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
@ -72,6 +73,27 @@ class ParserTests(SimpleTestCase):
|
|||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
FilterExpression("article._hidden|upper", p)
|
FilterExpression("article._hidden|upper", p)
|
||||||
|
|
||||||
|
def test_cannot_parse_characters(self):
|
||||||
|
p = Parser("", builtins=[filter_library])
|
||||||
|
for filter_expression, characters in [
|
||||||
|
('<>|default:"Default"|upper', '|<>||default:"Default"|upper'),
|
||||||
|
("test|<>|upper", "test||<>||upper"),
|
||||||
|
]:
|
||||||
|
with self.subTest(filter_expression=filter_expression):
|
||||||
|
with self.assertRaisesMessage(
|
||||||
|
TemplateSyntaxError,
|
||||||
|
f"Could not parse some characters: {characters}",
|
||||||
|
):
|
||||||
|
FilterExpression(filter_expression, p)
|
||||||
|
|
||||||
|
def test_cannot_find_variable(self):
|
||||||
|
p = Parser("", builtins=[filter_library])
|
||||||
|
with self.assertRaisesMessage(
|
||||||
|
TemplateSyntaxError,
|
||||||
|
'Could not find variable at start of |default:"Default"',
|
||||||
|
):
|
||||||
|
FilterExpression('|default:"Default"', p)
|
||||||
|
|
||||||
def test_variable_parsing(self):
|
def test_variable_parsing(self):
|
||||||
c = {"article": {"section": "News"}}
|
c = {"article": {"section": "News"}}
|
||||||
self.assertEqual(Variable("article.section").resolve(c), "News")
|
self.assertEqual(Variable("article.section").resolve(c), "News")
|
||||||
@ -148,3 +170,49 @@ class ParserTests(SimpleTestCase):
|
|||||||
'1|two_one_opt_arg:"1"',
|
'1|two_one_opt_arg:"1"',
|
||||||
):
|
):
|
||||||
FilterExpression(expr, parser)
|
FilterExpression(expr, parser)
|
||||||
|
|
||||||
|
def test_filter_numeric_argument_parsing(self):
|
||||||
|
p = Parser("", builtins=[filter_library])
|
||||||
|
|
||||||
|
cases = {
|
||||||
|
"5": 5,
|
||||||
|
"-5": -5,
|
||||||
|
"5.2": 5.2,
|
||||||
|
".4": 0.4,
|
||||||
|
"5.2e3": 5200.0, # 5.2 × 10³ = 5200.0.
|
||||||
|
"5.2E3": 5200.0, # Case-insensitive.
|
||||||
|
"5.2e-3": 0.0052, # Negative exponent.
|
||||||
|
"-1.5E4": -15000.0,
|
||||||
|
"+3.0e2": 300.0,
|
||||||
|
".5e2": 50.0, # 0.5 × 10² = 50.0
|
||||||
|
}
|
||||||
|
for num, expected in cases.items():
|
||||||
|
with self.subTest(num=num):
|
||||||
|
self.assertEqual(FilterExpression(num, p).resolve({}), expected)
|
||||||
|
self.assertEqual(
|
||||||
|
FilterExpression(f"0|default:{num}", p).resolve({}), expected
|
||||||
|
)
|
||||||
|
|
||||||
|
invalid_numbers = [
|
||||||
|
"abc123",
|
||||||
|
"123abc",
|
||||||
|
"foo",
|
||||||
|
"error",
|
||||||
|
"1e",
|
||||||
|
"e400",
|
||||||
|
"1e.2",
|
||||||
|
"1e2.",
|
||||||
|
"1e2.0",
|
||||||
|
"1e2a",
|
||||||
|
"1e2e3",
|
||||||
|
"1e-",
|
||||||
|
"1e-a",
|
||||||
|
]
|
||||||
|
|
||||||
|
for num in invalid_numbers:
|
||||||
|
with self.subTest(num=num):
|
||||||
|
self.assertIsNone(
|
||||||
|
FilterExpression(num, p).resolve({}, ignore_failures=True)
|
||||||
|
)
|
||||||
|
with self.assertRaises(VariableDoesNotExist):
|
||||||
|
FilterExpression(f"0|default:{num}", p).resolve({})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user