From 3cf907c20c4f4d94f649fbb93a006af5c61b30b8 Mon Sep 17 00:00:00 2001 From: Sky Date: Thu, 31 Oct 2019 13:05:26 +1100 Subject: [PATCH] Fixed #30761 -- Prevented floatformat filter from returning a negative zero. --- django/template/defaultfilters.py | 5 +++-- docs/ref/templates/builtins.txt | 5 +++++ docs/releases/3.1.txt | 3 +++ tests/template_tests/filter_tests/test_floatformat.py | 10 ++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index 174d2a092d..2c5aeba7a0 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -152,12 +152,13 @@ def floatformat(text, arg=-1): # Avoid conversion to scientific notation by accessing `sign`, `digits`, # and `exponent` from Decimal.as_tuple() directly. - sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec)).as_tuple() + rounded_d = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec)) + sign, digits, exponent = rounded_d.as_tuple() digits = [str(digit) for digit in reversed(digits)] while len(digits) <= abs(exponent): digits.append('0') digits.insert(-exponent, '.') - if sign: + if sign and rounded_d: digits.append('-') number = ''.join(reversed(digits)) return mark_safe(formats.number_format(number, abs(p))) diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index b5ebff2b73..34c5a5c005 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1722,6 +1722,11 @@ displayed. For example: Using ``floatformat`` with no argument is equivalent to using ``floatformat`` with an argument of ``-1``. +.. versionchanged:: 3.1 + + In older versions, a negative zero ``-0`` was returned for negative numbers + which round to zero. + .. templatefilter:: force_escape ``force_escape`` diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index ef2ab9b173..e8cb289873 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -279,6 +279,9 @@ Miscellaneous * ``django.utils.decorators.classproperty()`` decorator is moved to ``django.utils.functional.classproperty()``. +* :tfilter:`floatformat` template filter now outputs (positive) ``0`` for + negative numbers which round to zero. + .. _deprecated-features-3.1: Features deprecated in 3.1 diff --git a/tests/template_tests/filter_tests/test_floatformat.py b/tests/template_tests/filter_tests/test_floatformat.py index 9cb838854c..8ad7322af2 100644 --- a/tests/template_tests/filter_tests/test_floatformat.py +++ b/tests/template_tests/filter_tests/test_floatformat.py @@ -64,6 +64,16 @@ class FunctionTests(SimpleTestCase): self.assertEqual(floatformat(0, 10), '0.0000000000') self.assertEqual(floatformat(0.000000000000000000015, 20), '0.00000000000000000002') + def test_negative_zero_values(self): + tests = [ + (-0.01, -1, '0.0'), + (-0.001, 2, '0.00'), + (-0.499, 0, '0'), + ] + for num, decimal_places, expected in tests: + with self.subTest(num=num, decimal_places=decimal_places): + self.assertEqual(floatformat(num, decimal_places), expected) + def test_infinity(self): pos_inf = float(1e30000) neg_inf = float(-1e30000)