]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
Simplify the selection of decimal implementation
authorIsaac Jurado <diptongo@gmail.com>
Sun, 29 May 2016 07:40:24 +0000 (09:40 +0200)
committerIsaac Jurado <diptongo@gmail.com>
Sun, 29 May 2016 07:40:24 +0000 (09:40 +0200)
Instead of selecting individual symbols, expose only the chosen decimal module
through babel._compat.  This forces Babel to always use "decimal." prefix.
Howver, it will simplify the code for users that need to manipulate the decimal
context.

babel/_compat.py
babel/numbers.py
babel/plural.py
babel/units.py
tests/test_numbers.py
tests/test_plural.py
tests/test_smoke.py

index ae290f42c90b208ddada98d230d3a8fed018f2e3..aea338938810c972768cb34abff5599bdbe4348f 100644 (file)
@@ -58,15 +58,13 @@ number_types = integer_types + (float,)
 
 
 #
-# Use cdecimal when available
+# Since Python 3.3, a fast decimal implementation is already included in the
+# standard library.  Otherwise use cdecimal when available
 #
-from decimal import (Decimal as _dec,
-                     InvalidOperation as _invop)
-try:
-    from cdecimal import (Decimal as _cdec,
-                          InvalidOperation as _cinvop)
-    Decimal = _cdec
-    InvalidOperation = (_invop, _cinvop)
-except ImportError:
-    Decimal = _dec
-    InvalidOperation = _invop
+if sys.version_info[:2] >= (3, 3):
+    import decimal
+else:
+    try:
+        import cdecimal as decimal
+    except ImportError:
+        import decimal
index 67881ae56986c5321d32f760829399e37c515c5f..f9be88dd782f203e7810a9554e42cca90103968e 100644 (file)
@@ -22,7 +22,7 @@ import re
 from datetime import date as date_, datetime as datetime_
 
 from babel.core import default_locale, Locale, get_global
-from babel._compat import Decimal, InvalidOperation
+from babel._compat import decimal
 
 
 LC_NUMERIC = default_locale('LC_NUMERIC')
@@ -437,9 +437,9 @@ def parse_decimal(string, locale=LC_NUMERIC):
     """
     locale = Locale.parse(locale)
     try:
-        return Decimal(string.replace(get_group_symbol(locale), '')
-                       .replace(get_decimal_symbol(locale), '.'))
-    except InvalidOperation:
+        return decimal.Decimal(string.replace(get_group_symbol(locale), '')
+                               .replace(get_decimal_symbol(locale), '.'))
+    except decimal.InvalidOperation:
         raise NumberFormatError('%r is not a valid decimal number' % string)
 
 
@@ -566,8 +566,8 @@ class NumberPattern(object):
 
     def apply(self, value, locale, currency=None, force_frac=None):
         frac_prec = force_frac or self.frac_prec
-        if not isinstance(value, Decimal):
-            value = Decimal(str(value))
+        if not isinstance(value, decimal.Decimal):
+            value = decimal.Decimal(str(value))
         value = value.scaleb(self.scale)
         is_negative = int(value.is_signed())
         if self.exp_prec:  # Scientific notation
@@ -603,7 +603,7 @@ class NumberPattern(object):
             if sep:
                 number += get_decimal_symbol(locale) + b
         else:  # A normal number pattern
-            precision = Decimal('1.' + '1' * frac_prec[1])
+            precision = decimal.Decimal('1.' + '1' * frac_prec[1])
             rounded = value.quantize(precision)
             a, sep, b = str(abs(rounded)).partition(".")
             number = (self._format_int(a, self.int_prec[0],
@@ -641,7 +641,7 @@ class NumberPattern(object):
     def _format_significant(self, value, minimum, maximum):
         exp = value.adjusted()
         scale = maximum - 1 - exp
-        digits = str(value.scaleb(scale).quantize(Decimal(1)))
+        digits = str(value.scaleb(scale).quantize(decimal.Decimal(1)))
         if scale <= 0:
             result = digits + '0' * -scale
         else:
index 980629dccee52988d562bd85d5a6cb928fb5f7a9..0b8e425d5a02b50d7a2dc460d7ee718283f1b8ac 100644 (file)
@@ -11,7 +11,7 @@
 import re
 import sys
 
-from babel._compat import Decimal
+from babel._compat import decimal
 
 
 _plural_tags = ('zero', 'one', 'two', 'few', 'many', 'other')
@@ -33,9 +33,9 @@ def extract_operands(source):
             # 2.6's Decimal cannot convert from float directly
             if sys.version_info < (2, 7):
                 n = str(n)
-            n = Decimal(n)
+            n = decimal.Decimal(n)
 
-    if isinstance(n, Decimal):
+    if isinstance(n, decimal.Decimal):
         dec_tuple = n.as_tuple()
         exp = dec_tuple.exponent
         fraction_digits = dec_tuple.digits[exp:] if exp < 0 else ()
index 798ade20aed0d622d1fc722f49502fd8ab637643..1ea5b17cc1715386a9ca8013245b6db0d68f99c4 100644 (file)
@@ -80,8 +80,8 @@ def format_unit(value, measurement_unit, length='long', format=None, locale=LC_N
 
     Number formats may be overridden with the ``format`` parameter.
 
-    >>> from babel._compat import Decimal
-    >>> format_unit(Decimal("-42.774"), 'temperature-celsius', 'short', format='#.0', locale='fr')
+    >>> from babel._compat import decimal
+    >>> format_unit(decimal.Decimal("-42.774"), 'temperature-celsius', 'short', format='#.0', locale='fr')
     u'-42,8 \\xb0C'
 
     The locale's usual pluralization rules are respected.
index 19f9bc76db17c1877557f2a091225501440e75fd..32a969d148d9ef50399c6ee3c3b6440b5bb89c2e 100644 (file)
@@ -17,7 +17,7 @@ import pytest
 from datetime import date
 
 from babel import numbers
-from babel._compat import Decimal
+from babel._compat import decimal
 
 
 class FormatDecimalTestCase(unittest.TestCase):
@@ -94,16 +94,16 @@ class FormatDecimalTestCase(unittest.TestCase):
 
     def test_decimals(self):
         """Test significant digits patterns"""
-        self.assertEqual(numbers.format_decimal(Decimal('1.2345'),
+        self.assertEqual(numbers.format_decimal(decimal.Decimal('1.2345'),
                                                 '#.00', locale='en_US'),
                          '1.23')
-        self.assertEqual(numbers.format_decimal(Decimal('1.2345000'),
+        self.assertEqual(numbers.format_decimal(decimal.Decimal('1.2345000'),
                                                 '#.00', locale='en_US'),
                          '1.23')
-        self.assertEqual(numbers.format_decimal(Decimal('1.2345000'),
+        self.assertEqual(numbers.format_decimal(decimal.Decimal('1.2345000'),
                                                 '@@', locale='en_US'),
                          '1.2')
-        self.assertEqual(numbers.format_decimal(Decimal('12345678901234567890.12345'),
+        self.assertEqual(numbers.format_decimal(decimal.Decimal('12345678901234567890.12345'),
                                                 '#.00', locale='en_US'),
                          '12345678901234567890.12')
 
@@ -136,7 +136,7 @@ class FormatDecimalTestCase(unittest.TestCase):
         self.assertEqual(fmt, '1.23E02 m/s')
         fmt = numbers.format_scientific(0.012345, '#.##E00 m/s', locale='en_US')
         self.assertEqual(fmt, '1.23E-02 m/s')
-        fmt = numbers.format_scientific(Decimal('12345'), '#.##E+00 m/s',
+        fmt = numbers.format_scientific(decimal.Decimal('12345'), '#.##E+00 m/s',
                                         locale='en_US')
         self.assertEqual(fmt, '1.23E+04 m/s')
         # 0 (see ticket #99)
@@ -146,7 +146,7 @@ class FormatDecimalTestCase(unittest.TestCase):
     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")
+        number = decimal.Decimal("7E-7")
         fmt = numbers.format_decimal(number, format="@@@", locale='en_US')
         self.assertEqual('0.000000700', fmt)
 
@@ -154,9 +154,9 @@ class FormatDecimalTestCase(unittest.TestCase):
 class NumberParsingTestCase(unittest.TestCase):
 
     def test_can_parse_decimals(self):
-        self.assertEqual(Decimal('1099.98'),
+        self.assertEqual(decimal.Decimal('1099.98'),
                          numbers.parse_decimal('1,099.98', locale='en_US'))
-        self.assertEqual(Decimal('1099.98'),
+        self.assertEqual(decimal.Decimal('1099.98'),
                          numbers.parse_decimal('1.099,98', locale='de'))
         self.assertRaises(numbers.NumberFormatError,
                           lambda: numbers.parse_decimal('2,109,998', locale='de'))
@@ -302,8 +302,8 @@ def test_parse_number():
 
 def test_parse_decimal():
     assert (numbers.parse_decimal('1,099.98', locale='en_US')
-            == Decimal('1099.98'))
-    assert numbers.parse_decimal('1.099,98', locale='de') == Decimal('1099.98')
+            == decimal.Decimal('1099.98'))
+    assert numbers.parse_decimal('1.099,98', locale='de') == decimal.Decimal('1099.98')
 
     with pytest.raises(numbers.NumberFormatError) as excinfo:
         numbers.parse_decimal('2,109,998', locale='de')
index 60a2de4a1bc434ae164c3e075231394f8ba8baf7..6406af87204186d5eb570f26c7055e822212d6ae 100644 (file)
@@ -14,7 +14,7 @@ import unittest
 import pytest
 
 from babel import plural, localedata
-from babel._compat import Decimal
+from babel._compat import decimal
 
 
 def test_plural_rule():
@@ -34,29 +34,29 @@ def test_plural_rule_operands_i():
 
 def test_plural_rule_operands_v():
     rule = plural.PluralRule({'one': 'v is 2'})
-    assert rule(Decimal('1.20')) == 'one'
-    assert rule(Decimal('1.2')) == 'other'
+    assert rule(decimal.Decimal('1.20')) == 'one'
+    assert rule(decimal.Decimal('1.2')) == 'other'
     assert rule(2) == 'other'
 
 
 def test_plural_rule_operands_w():
     rule = plural.PluralRule({'one': 'w is 2'})
-    assert rule(Decimal('1.23')) == 'one'
-    assert rule(Decimal('1.20')) == 'other'
+    assert rule(decimal.Decimal('1.23')) == 'one'
+    assert rule(decimal.Decimal('1.20')) == 'other'
     assert rule(1.2) == 'other'
 
 
 def test_plural_rule_operands_f():
     rule = plural.PluralRule({'one': 'f is 20'})
-    assert rule(Decimal('1.23')) == 'other'
-    assert rule(Decimal('1.20')) == 'one'
+    assert rule(decimal.Decimal('1.23')) == 'other'
+    assert rule(decimal.Decimal('1.20')) == 'one'
     assert rule(1.2) == 'other'
 
 
 def test_plural_rule_operands_t():
     rule = plural.PluralRule({'one': 't = 5'})
-    assert rule(Decimal('1.53')) == 'other'
-    assert rule(Decimal('1.50')) == 'one'
+    assert rule(decimal.Decimal('1.53')) == 'other'
+    assert rule(decimal.Decimal('1.50')) == 'one'
     assert rule(1.5) == 'one'
 
 
@@ -253,9 +253,9 @@ EXTRACT_OPERANDS_TESTS = (
 
 @pytest.mark.parametrize('source,n,i,v,w,f,t', EXTRACT_OPERANDS_TESTS)
 def test_extract_operands(source, n, i, v, w, f, t):
-    source = Decimal(source) if isinstance(source, str) else source
+    source = decimal.Decimal(source) if isinstance(source, str) else source
     assert (plural.extract_operands(source) ==
-            Decimal(n), i, v, w, f, t)
+            decimal.Decimal(n), i, v, w, f, t)
 
 
 @pytest.mark.parametrize('locale', ('ru', 'pl'))
index eda10ed344cbb9307a0c7b0e91a2b32e52d8e98f..3993f608ca2b57ac3729e3db207bddefc6ef1a56 100644 (file)
@@ -11,7 +11,7 @@ import pytest
 from babel import Locale
 from babel import dates
 from babel import numbers
-from babel._compat import Decimal
+from babel._compat import decimal
 
 
 @pytest.mark.all_locales
@@ -28,8 +28,8 @@ def test_smoke_dates(locale):
 def test_smoke_numbers(locale):
     locale = Locale.parse(locale)
     for number in (
-        Decimal("-33.76"),  # Negative Decimal
-        Decimal("13.37"),  # Positive Decimal
+        decimal.Decimal("-33.76"),  # Negative Decimal
+        decimal.Decimal("13.37"),  # Positive Decimal
         1.2 - 1.0,  # Inaccurate float
         10,  # Plain old integer
         0,  # Zero