Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #15789 -- Set the decimal precisio to avoid an exception in the…

… floatformat filter, and added a few more tests. Thanks akaihola for the report, igalarzab for the patch and ptone for the review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17297 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 27444618f6f8822110808a5d663a400334b8e9d7 1 parent baf63f6
Aymeric Augustin authored December 30, 2011
10  django/template/defaultfilters.py
@@ -3,7 +3,7 @@
3 3
 import re
4 4
 import random as random_module
5 5
 import unicodedata
6  
-from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
  6
+from decimal import Decimal, InvalidOperation, Context, ROUND_HALF_UP
7 7
 from functools import wraps
8 8
 from pprint import pformat
9 9
 
@@ -166,9 +166,15 @@ def floatformat(text, arg=-1):
166 166
     else:
167 167
         exp = Decimal(u'1.0') / (Decimal(10) ** abs(p))
168 168
     try:
  169
+        # Set the precision high enough to avoid an exception, see #15789.
  170
+        tupl = d.as_tuple()
  171
+        units = len(tupl[1]) - tupl[2]
  172
+        prec = abs(arg) + units + 1
  173
+
169 174
         # Avoid conversion to scientific notation by accessing `sign`, `digits`
170 175
         # and `exponent` from `Decimal.as_tuple()` directly.
171  
-        sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP).as_tuple()
  176
+        sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP,
  177
+            Context(prec=prec)).as_tuple()
172 178
         digits = [unicode(digit) for digit in reversed(digits)]
173 179
         while len(digits) <= abs(exponent):
174 180
             digits.append(u'0')
18  tests/regressiontests/defaultfilters/tests.py
@@ -2,6 +2,7 @@
2 2
 from __future__ import with_statement
3 3
 
4 4
 import datetime
  5
+import decimal
5 6
 
6 7
 from django.template.defaultfilters import *
7 8
 from django.test import TestCase
@@ -26,6 +27,11 @@ def test_floatformat(self):
26 27
         self.assertEqual(floatformat(11.0000, -2), u'11')
27 28
         self.assertEqual(floatformat(11.000001, -2), u'11.00')
28 29
         self.assertEqual(floatformat(8.2798, 3), u'8.280')
  30
+        self.assertEqual(floatformat(5555.555, 2), u'5555.56')
  31
+        self.assertEqual(floatformat(001.3000, 2), u'1.30')
  32
+        self.assertEqual(floatformat(0.12345, 2), u'0.12')
  33
+        self.assertEqual(floatformat(decimal.Decimal('555.555'), 2), u'555.56')
  34
+        self.assertEqual(floatformat(decimal.Decimal('09.000')), u'9')
29 35
         self.assertEqual(floatformat(u'foo'), u'')
30 36
         self.assertEqual(floatformat(13.1031, u'bar'), u'13.1031')
31 37
         self.assertEqual(floatformat(18.125, 2), u'18.13')
@@ -57,6 +63,18 @@ def __float__(self):
57 63
 
58 64
         self.assertEqual(floatformat(FloatWrapper(11.000001), -2), u'11.00')
59 65
 
  66
+        # Regression for #15789
  67
+        decimal_ctx = decimal.getcontext()
  68
+        old_prec, decimal_ctx.prec = decimal_ctx.prec, 2
  69
+        try:
  70
+            self.assertEqual(floatformat(1.2345, 2), u'1.23')
  71
+            self.assertEqual(floatformat(15.2042, -3), u'15.204')
  72
+            self.assertEqual(floatformat(decimal.Decimal('1.2345'), 2), u'1.23')
  73
+            self.assertEqual(floatformat(decimal.Decimal('15.2042'), -3), u'15.204')
  74
+        finally:
  75
+            decimal_ctx.prec = old_prec
  76
+
  77
+
60 78
     # This fails because of Python's float handling. Floats with many zeroes
61 79
     # after the decimal point should be passed in as another type such as
62 80
     # unicode or Decimal.

0 notes on commit 2744461

Please sign in to comment.
Something went wrong with that request. Please try again.