Django

Code

Changeset 9369

Show
Ignore:
Timestamp:
11/07/08 19:44:46 (2 months ago)
Author:
kmtracey
Message:

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.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/template/defaultfilters.py

    r9291 r9369  
    22 
    33import re 
     4 
     5try: 
     6    from decimal import Decimal, InvalidOperation, ROUND_HALF_UP 
     7except ImportError: 
     8    from django.utils._decimal import Decimal, InvalidOperation, ROUND_HALF_UP 
     9 
    410import random as random_module 
    511try: 
     
    4551# STRINGS         # 
    4652################### 
    47  
    4853 
    4954def addslashes(value): 
     
    9398fix_ampersands = stringfilter(fix_ampersands) 
    9499 
     100# Values for testing floatformat input against infinity and NaN representations, 
     101# which differ across platforms and Python versions.  Some (i.e. old Windows 
     102# ones) are not recognized by Decimal but we want to return them unchanged vs.  
     103# returning an empty string as we do for completley invalid input.  Note these 
     104# need to be built up from values that are not inf/nan, since inf/nan values do  
     105# not reload properly from .pyc files on Windows prior to some level of Python 2.5  
     106# (see Python Issue757815 and Issue1080440). 
     107pos_inf = 1e200 * 1e200 
     108neg_inf = -1e200 * 1e200 
     109nan = (1e200 * 1e200) / (1e200 * 1e200) 
     110special_floats = [str(pos_inf), str(neg_inf), str(nan)] 
     111 
    95112def floatformat(text, arg=-1): 
    96113    """ 
     
    120137    * {{ num2|floatformat:"-3" }} displays "34" 
    121138    * {{ num3|floatformat:"-3" }} displays "34.260" 
    122     """ 
    123     try: 
    124         f = float(text) 
    125     except (ValueError, TypeError): 
    126         return u'' 
    127     try: 
    128         d = int(arg) 
     139     
     140    If the input float is infinity or NaN, the (platform-dependent) string 
     141    representation of that value will be displayed. 
     142    """ 
     143         
     144    try: 
     145        input_val = force_unicode(text) 
     146        d = Decimal(input_val) 
     147    except UnicodeEncodeError: 
     148        return u'' 
     149    except InvalidOperation: 
     150        if input_val in special_floats: 
     151            return input_val 
     152        else: 
     153            return u'' 
     154    try: 
     155        p = int(arg) 
    129156    except ValueError: 
    130         return force_unicode(f) 
    131     try: 
    132         m = f - int(f) 
    133     except OverflowError: 
    134         return force_unicode(f) 
    135     if not m and d < 0: 
    136         return mark_safe(u'%d' % int(f)) 
     157        return input_val 
     158     
     159    try: 
     160        m = int(d) - d 
     161    except (OverflowError, InvalidOperation): 
     162        return input_val 
     163     
     164    if not m and p < 0: 
     165        return mark_safe(u'%d' % (int(d))) 
     166     
     167    if p == 0: 
     168        exp = Decimal(1) 
    137169    else: 
    138         formatstr = u'%%.%df' % abs(d) 
    139         return mark_safe(formatstr % f) 
     170        exp = Decimal('1.0') / (Decimal(10) ** abs(p)) 
     171    try: 
     172        return mark_safe(u'%s' % str(d.quantize(exp, ROUND_HALF_UP))) 
     173    except InvalidOperation: 
     174        return input_val 
    140175floatformat.is_safe = True 
    141176 
  • django/trunk/tests/regressiontests/defaultfilters/tests.py

    r8599 r9369  
    1414>>> floatformat(0.0) 
    1515u'0' 
    16 >>> floatformat(7.7,3) 
     16>>> floatformat(7.7, 3) 
    1717u'7.700' 
    18 >>> floatformat(6.000000,3) 
     18>>> floatformat(6.000000, 3) 
    1919u'6.000' 
    2020>>> floatformat(6.200000, 3) 
     
    2222>>> floatformat(6.200000, -3) 
    2323u'6.200' 
    24 >>> floatformat(13.1031,-3) 
     24>>> floatformat(13.1031, -3) 
    2525u'13.103' 
    2626>>> floatformat(11.1197, -2) 
     
    3636>>> floatformat(13.1031, u'bar') 
    3737u'13.1031' 
     38>>> floatformat(18.125, 2)  
     39u'18.13'  
    3840>>> floatformat(u'foo', u'bar') 
    3941u'' 
     42>>> floatformat(u'¿Cómo esta usted?') 
     43u'' 
    4044>>> floatformat(None) 
    4145u'' 
     46>>> pos_inf = float(1e30000) 
     47>>> floatformat(pos_inf) == unicode(pos_inf) 
     48True 
     49>>> neg_inf = float(-1e30000) 
     50>>> floatformat(neg_inf) == unicode(neg_inf) 
     51True 
     52>>> nan = pos_inf / pos_inf 
     53>>> floatformat(nan) == unicode(nan) 
     54True 
    4255 
    4356>>> addslashes(u'"double quotes" and \'single quotes\'')