changeset 580:ea413a4d754b trunk

fix format_decimal() with small Decimal values (#214, patch from George Lund)
author fschwarz
date Fri, 03 Aug 2012 08:36:21 +0000
parents 99d51589c822
children 99706377c930
files ChangeLog babel/numbers.py babel/tests/numbers.py
diffstat 3 files changed, 41 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -42,6 +42,7 @@
  * fix formatting of fraction in format_decimal() if the input value is a float
    with more than 7 significant digits (#183)
  * fix format_date() with datetime parameter (#282, patch from Xavier Morel)
+ * fix format_decimal() with small Decimal values (#214, patch from George Lund)
 
 
 Version 0.9.6
--- a/babel/numbers.py
+++ b/babel/numbers.py
@@ -323,9 +323,39 @@
 def split_number(value):
     """Convert a number into a (intasstring, fractionasstring) tuple"""
     if isinstance(value, Decimal):
-        text = str(value)
-    else:
-        text = ('%.9f' % value).rstrip('0')
+       # NB can't just do text = str(value) as str repr of Decimal may be
+       # in scientific notation, e.g. for small numbers.
+       
+       sign, digits, exp = value.as_tuple()
+       # build list of digits in reverse order, then reverse+join
+       # as per http://docs.python.org/library/decimal.html#recipes
+       int_part = []
+       frac_part = []
+       
+       digits = map(str, digits)
+       
+       # get figures after decimal point
+       for i in range(-exp):
+           # add digit if available, else 0
+           frac_part.append(digits.pop() if digits else '0')
+       
+       # add in some zeroes...
+       for i in range(exp):
+           int_part.append('0')
+       
+       # and the rest
+       while digits:
+           int_part.append(digits.pop())
+       
+       # if < 1, int_part must be set to '0'
+       if len(int_part) == 0:
+           int_part = '0',
+       
+       if sign:
+           int_part.append('-')
+       
+       return ''.join(reversed(int_part)), ''.join(reversed(frac_part))
+    text = ('%.9f' % value).rstrip('0')
     if '.' in text:
         a, b = text.split('.', 1)
         if b == '0':
--- a/babel/tests/numbers.py
+++ b/babel/tests/numbers.py
@@ -140,6 +140,13 @@
         # 0 (see ticket #99)
         fmt = numbers.format_scientific(0, '#E0', locale='en_US')
         self.assertEqual(fmt, '0E0')
+    
+    def test_formatting_of_very_small_decimals(self):
+        # previously formatting very small decimals could lead to a type error
+        # because the Decimal->string conversion was too simple (see #214)
+        number = Decimal("7E-7")
+        fmt = numbers.format_decimal(number, format="@@@", locale='en_US')
+        self.assertEqual('0.000000700', fmt)
 
 
 class BankersRoundTestCase(unittest.TestCase):
Copyright (C) 2012-2017 Edgewall Software