summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/decimal.py46
-rw-r--r--Lib/test/test_decimal.py27
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.