From f88b9eee53598ac1fd96b321c88fa9189b391cba Mon Sep 17 00:00:00 2001 From: Ramiro Morales Date: Thu, 3 Mar 2011 21:17:48 +0000 Subject: [1.2.X] Fixed #11206 -- Ensure that the floatformat template filter doesn't switch to scientific notation when asked to format a zero value with more than six decimal places. Thanks Tai Lee for the report and fix and Facundo Batista for his help when Decimal module expertise was needed. Backport of [15736] from trunk git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15738 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/template/defaultfilters.py | 14 ++++++++++++-- tests/regressiontests/defaultfilters/tests.py | 13 +++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index fc144073fc..5902ebd301 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -149,9 +149,19 @@ def floatformat(text, arg=-1): if p == 0: exp = Decimal(1) else: - exp = Decimal('1.0') / (Decimal(10) ** abs(p)) + exp = Decimal(u'1.0') / (Decimal(10) ** abs(p)) try: - return mark_safe(formats.number_format(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)), abs(p))) + # 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).as_tuple() + digits = [unicode(digit) for digit in reversed(digits)] + while len(digits) <= abs(exponent): + digits.append(u'0') + digits.insert(-exponent, u'.') + if sign: + digits.append(u'-') + number = u''.join(reversed(digits)) + return mark_safe(formats.number_format(number, abs(p))) except InvalidOperation: return input_val floatformat.is_safe = True diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py index e946915996..a5a4e2a32c 100644 --- a/tests/regressiontests/defaultfilters/tests.py +++ b/tests/regressiontests/defaultfilters/tests.py @@ -29,6 +29,13 @@ class DefaultFiltersTests(unittest.TestCase): self.assertEqual(floatformat(u'¿Cómo esta usted?'), u'') self.assertEqual(floatformat(None), u'') + # Check that we're not converting to scientific notation. + self.assertEqual(floatformat(0, 6), u'0.000000') + self.assertEqual(floatformat(0, 7), u'0.0000000') + self.assertEqual(floatformat(0, 10), u'0.0000000000') + self.assertEqual(floatformat(0.000000000000000000015, 20), + u'0.00000000000000000002') + pos_inf = float(1e30000) self.assertEqual(floatformat(pos_inf), unicode(pos_inf)) @@ -46,6 +53,12 @@ class DefaultFiltersTests(unittest.TestCase): self.assertEqual(floatformat(FloatWrapper(11.000001), -2), u'11.00') + # This would fail because of Python's float handling. Floats with many zeroes + # after the decimal point should be passed in as another type such as + # unicode or Decimal. + #def test_floatformat_fail(self): + # self.assertEqual(floatformat(1.00000000000000015, 16), u'1.0000000000000002') + def test_addslashes(self): self.assertEqual(addslashes(u'"double quotes" and \'single quotes\''), u'\\"double quotes\\" and \\\'single quotes\\\'') -- cgit v1.2.1