Mercurial > babel > mirror
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):