Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[1.0.X] Fixed #5748 -- Made floatformat filter round properly on all …

…platforms and handle NaN input correctly on Windows. Also added tests for these cases. Thanks for the report and initial patch to SmileyChris and PJCrosier.

[9369] from trunk.


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@9370 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit dc0389cca04bf84dbc32ca2c9e1e6d5c3267e51a 1 parent f56df04
@kmtracey kmtracey authored
View
59 django/template/defaultfilters.py
@@ -1,6 +1,12 @@
"""Default variable filters."""
import re
+
+try:
+ from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
+except ImportError:
+ from django.utils._decimal import Decimal, InvalidOperation, ROUND_HALF_UP
+
import random as random_module
try:
from functools import wraps
@@ -45,7 +51,6 @@ def _dec(*args, **kwargs):
# STRINGS #
###################
-
def addslashes(value):
"""
Adds slashes before quotes. Useful for escaping strings in CSV, for
@@ -92,6 +97,18 @@ def fix_ampersands(value):
fix_ampersands.is_safe=True
fix_ampersands = stringfilter(fix_ampersands)
+# Values for testing floatformat input against infinity and NaN representations,
+# which differ across platforms and Python versions. Some (i.e. old Windows
+# ones) are not recognized by Decimal but we want to return them unchanged vs.
+# returning an empty string as we do for completley invalid input. Note these
+# need to be built up from values that are not inf/nan, since inf/nan values do
+# not reload properly from .pyc files on Windows prior to some level of Python 2.5
+# (see Python Issue757815 and Issue1080440).
+pos_inf = 1e200 * 1e200
+neg_inf = -1e200 * 1e200
+nan = (1e200 * 1e200) / (1e200 * 1e200)
+special_floats = [str(pos_inf), str(neg_inf), str(nan)]
+
def floatformat(text, arg=-1):
"""
Displays a float to a specified number of decimal places.
@@ -119,24 +136,42 @@ def floatformat(text, arg=-1):
* {{ num1|floatformat:"-3" }} displays "34.232"
* {{ num2|floatformat:"-3" }} displays "34"
* {{ num3|floatformat:"-3" }} displays "34.260"
+
+ If the input float is infinity or NaN, the (platform-dependent) string
+ representation of that value will be displayed.
"""
+
try:
- f = float(text)
- except (ValueError, TypeError):
+ input_val = force_unicode(text)
+ d = Decimal(input_val)
+ except UnicodeEncodeError:
return u''
+ except InvalidOperation:
+ if input_val in special_floats:
+ return input_val
+ else:
+ return u''
try:
- d = int(arg)
+ p = int(arg)
except ValueError:
- return force_unicode(f)
+ return input_val
+
try:
- m = f - int(f)
- except OverflowError:
- return force_unicode(f)
- if not m and d < 0:
- return mark_safe(u'%d' % int(f))
+ m = int(d) - d
+ except (OverflowError, InvalidOperation):
+ return input_val
+
+ if not m and p < 0:
+ return mark_safe(u'%d' % (int(d)))
+
+ if p == 0:
+ exp = Decimal(1)
else:
- formatstr = u'%%.%df' % abs(d)
- return mark_safe(formatstr % f)
+ exp = Decimal('1.0') / (Decimal(10) ** abs(p))
+ try:
+ return mark_safe(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)))
+ except InvalidOperation:
+ return input_val
floatformat.is_safe = True
def iriencode(value):
View
19 tests/regressiontests/defaultfilters/tests.py
@@ -13,15 +13,15 @@
u'0.0'
>>> floatformat(0.0)
u'0'
->>> floatformat(7.7,3)
+>>> floatformat(7.7, 3)
u'7.700'
->>> floatformat(6.000000,3)
+>>> floatformat(6.000000, 3)
u'6.000'
>>> floatformat(6.200000, 3)
u'6.200'
>>> floatformat(6.200000, -3)
u'6.200'
->>> floatformat(13.1031,-3)
+>>> floatformat(13.1031, -3)
u'13.103'
>>> floatformat(11.1197, -2)
u'11.12'
@@ -35,10 +35,23 @@
u''
>>> floatformat(13.1031, u'bar')
u'13.1031'
+>>> floatformat(18.125, 2)
+u'18.13'
>>> floatformat(u'foo', u'bar')
u''
+>>> floatformat(u'¿Cómo esta usted?')
+u''
>>> floatformat(None)
u''
+>>> pos_inf = float(1e30000)
+>>> floatformat(pos_inf) == unicode(pos_inf)
+True
+>>> neg_inf = float(-1e30000)
+>>> floatformat(neg_inf) == unicode(neg_inf)
+True
+>>> nan = pos_inf / pos_inf
+>>> floatformat(nan) == unicode(nan)
+True
>>> addslashes(u'"double quotes" and \'single quotes\'')
u'\\"double quotes\\" and \\\'single quotes\\\''
Please sign in to comment.
Something went wrong with that request. Please try again.