diff options
-rw-r--r-- | Lib/decimal.py | 46 | ||||
-rw-r--r-- | Lib/test/test_decimal.py | 27 |
2 files changed, 63 insertions, 10 deletions
diff --git a/Lib/decimal.py b/Lib/decimal.py index fa41722..45ecf88 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -562,20 +562,46 @@ class Decimal(object): # tuple/list conversion (possibly from as_tuple()) if isinstance(value, (list,tuple)): if len(value) != 3: - raise ValueError('Invalid arguments') - if value[0] not in (0,1): - raise ValueError('Invalid sign') - for digit in value[1]: - if not isinstance(digit, (int,long)) or digit < 0: - raise ValueError("The second value in the tuple must be " - "composed of non negative integer elements.") + raise ValueError('Invalid tuple size in creation of Decimal ' + 'from list or tuple. The list or tuple ' + 'should have exactly three elements.') + # process sign. The isinstance test rejects floats + if not (isinstance(value[0], (int, long)) and value[0] in (0,1)): + raise ValueError("Invalid sign. The first value in the tuple " + "should be an integer; either 0 for a " + "positive number or 1 for a negative number.") self._sign = value[0] - self._int = tuple(value[1]) - if value[2] in ('F','n','N'): + if value[2] == 'F': + # infinity: value[1] is ignored + self._int = (0,) self._exp = value[2] self._is_special = True else: - self._exp = int(value[2]) + # process and validate the digits in value[1] + digits = [] + for digit in value[1]: + if isinstance(digit, (int, long)) and 0 <= digit <= 9: + # skip leading zeros + if digits or digit != 0: + digits.append(digit) + else: + raise ValueError("The second value in the tuple must " + "be composed of integers in the range " + "0 through 9.") + if value[2] in ('n', 'N'): + # NaN: digits form the diagnostic + self._int = tuple(digits) + self._exp = value[2] + self._is_special = True + elif isinstance(value[2], (int, long)): + # finite number: digits give the coefficient + self._int = tuple(digits or [0]) + self._exp = value[2] + self._is_special = False + else: + raise ValueError("The third value in the tuple must " + "be an integer, or one of the " + "strings 'F', 'n', 'N'.") return self if isinstance(value, float): diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index e4b0ae5..27d1aa6 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -452,13 +452,18 @@ class DecimalExplicitConstructionTest(unittest.TestCase): #bad sign self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) ) + self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) ) + self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2)) #bad exp self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') ) + self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) ) + self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') ) #bad coefficients self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) ) self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) ) + self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) ) def test_explicit_from_Decimal(self): @@ -1060,6 +1065,28 @@ class DecimalUsabilityTest(unittest.TestCase): d = Decimal("Infinity") self.assertEqual(d.as_tuple(), (0, (0,), 'F') ) + #leading zeros in coefficient should be stripped + d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) ) + self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) ) + d = Decimal( (1, (0, 0, 0), 37) ) + self.assertEqual(d.as_tuple(), (1, (0,), 37)) + d = Decimal( (1, (), 37) ) + self.assertEqual(d.as_tuple(), (1, (0,), 37)) + + #leading zeros in NaN diagnostic info should be stripped + d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') ) + self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') ) + d = Decimal( (1, (0, 0, 0), 'N') ) + self.assertEqual(d.as_tuple(), (1, (), 'N') ) + d = Decimal( (1, (), 'n') ) + self.assertEqual(d.as_tuple(), (1, (), 'n') ) + + #coefficient in infinity should be ignored + d = Decimal( (0, (4, 5, 3, 4), 'F') ) + self.assertEqual(d.as_tuple(), (0, (0,), 'F')) + d = Decimal( (1, (0, 2, 7, 1), 'F') ) + self.assertEqual(d.as_tuple(), (1, (0,), 'F')) + def test_immutability_operations(self): # Do operations and check that it didn't change change internal objects. |