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
This commit is contained in:
parent
baf63f6e57
commit
27444618f6
|
@ -3,7 +3,7 @@
|
||||||
import re
|
import re
|
||||||
import random as random_module
|
import random as random_module
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
|
from decimal import Decimal, InvalidOperation, Context, ROUND_HALF_UP
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
|
||||||
|
@ -166,9 +166,15 @@ def floatformat(text, arg=-1):
|
||||||
else:
|
else:
|
||||||
exp = Decimal(u'1.0') / (Decimal(10) ** abs(p))
|
exp = Decimal(u'1.0') / (Decimal(10) ** abs(p))
|
||||||
try:
|
try:
|
||||||
|
# Set the precision high enough to avoid an exception, see #15789.
|
||||||
|
tupl = d.as_tuple()
|
||||||
|
units = len(tupl[1]) - tupl[2]
|
||||||
|
prec = abs(arg) + units + 1
|
||||||
|
|
||||||
# Avoid conversion to scientific notation by accessing `sign`, `digits`
|
# Avoid conversion to scientific notation by accessing `sign`, `digits`
|
||||||
# and `exponent` from `Decimal.as_tuple()` directly.
|
# and `exponent` from `Decimal.as_tuple()` directly.
|
||||||
sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP).as_tuple()
|
sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP,
|
||||||
|
Context(prec=prec)).as_tuple()
|
||||||
digits = [unicode(digit) for digit in reversed(digits)]
|
digits = [unicode(digit) for digit in reversed(digits)]
|
||||||
while len(digits) <= abs(exponent):
|
while len(digits) <= abs(exponent):
|
||||||
digits.append(u'0')
|
digits.append(u'0')
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import decimal
|
||||||
|
|
||||||
from django.template.defaultfilters import *
|
from django.template.defaultfilters import *
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
@ -26,6 +27,11 @@ class DefaultFiltersTests(TestCase):
|
||||||
self.assertEqual(floatformat(11.0000, -2), u'11')
|
self.assertEqual(floatformat(11.0000, -2), u'11')
|
||||||
self.assertEqual(floatformat(11.000001, -2), u'11.00')
|
self.assertEqual(floatformat(11.000001, -2), u'11.00')
|
||||||
self.assertEqual(floatformat(8.2798, 3), u'8.280')
|
self.assertEqual(floatformat(8.2798, 3), u'8.280')
|
||||||
|
self.assertEqual(floatformat(5555.555, 2), u'5555.56')
|
||||||
|
self.assertEqual(floatformat(001.3000, 2), u'1.30')
|
||||||
|
self.assertEqual(floatformat(0.12345, 2), u'0.12')
|
||||||
|
self.assertEqual(floatformat(decimal.Decimal('555.555'), 2), u'555.56')
|
||||||
|
self.assertEqual(floatformat(decimal.Decimal('09.000')), u'9')
|
||||||
self.assertEqual(floatformat(u'foo'), u'')
|
self.assertEqual(floatformat(u'foo'), u'')
|
||||||
self.assertEqual(floatformat(13.1031, u'bar'), u'13.1031')
|
self.assertEqual(floatformat(13.1031, u'bar'), u'13.1031')
|
||||||
self.assertEqual(floatformat(18.125, 2), u'18.13')
|
self.assertEqual(floatformat(18.125, 2), u'18.13')
|
||||||
|
@ -57,6 +63,18 @@ class DefaultFiltersTests(TestCase):
|
||||||
|
|
||||||
self.assertEqual(floatformat(FloatWrapper(11.000001), -2), u'11.00')
|
self.assertEqual(floatformat(FloatWrapper(11.000001), -2), u'11.00')
|
||||||
|
|
||||||
|
# Regression for #15789
|
||||||
|
decimal_ctx = decimal.getcontext()
|
||||||
|
old_prec, decimal_ctx.prec = decimal_ctx.prec, 2
|
||||||
|
try:
|
||||||
|
self.assertEqual(floatformat(1.2345, 2), u'1.23')
|
||||||
|
self.assertEqual(floatformat(15.2042, -3), u'15.204')
|
||||||
|
self.assertEqual(floatformat(decimal.Decimal('1.2345'), 2), u'1.23')
|
||||||
|
self.assertEqual(floatformat(decimal.Decimal('15.2042'), -3), u'15.204')
|
||||||
|
finally:
|
||||||
|
decimal_ctx.prec = old_prec
|
||||||
|
|
||||||
|
|
||||||
# This fails because of Python's float handling. Floats with many zeroes
|
# This fails because of Python's float handling. Floats with many zeroes
|
||||||
# after the decimal point should be passed in as another type such as
|
# after the decimal point should be passed in as another type such as
|
||||||
# unicode or Decimal.
|
# unicode or Decimal.
|
||||||
|
|
Loading…
Reference in New Issue