Index: Lib/decimal.py =================================================================== --- Lib/decimal.py (revisiĆ³n: 77330) +++ Lib/decimal.py (copia de trabajo) @@ -3863,7 +3863,13 @@ >>> ExtendedContext.add(Decimal('1E+2'), Decimal('1.01E+4')) Decimal('1.02E+4') """ - return a.__add__(b, context=self) + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + r = a.__add__(b, context=self) + if r is NotImplemented: + raise TypeError("Unable to convert %s to Decimal" % r) + else: + return r def _apply(self, a): return str(a._fix(self)) @@ -3906,6 +3912,8 @@ >>> ExtendedContext.compare(Decimal('-3'), Decimal('2.1')) Decimal('-1') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.compare(b, context=self) def compare_signal(self, a, b): @@ -3934,6 +3942,8 @@ >>> print c.flags[InvalidOperation] 1 """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.compare_signal(b, context=self) def compare_total(self, a, b): @@ -3956,6 +3966,8 @@ >>> ExtendedContext.compare_total(Decimal('12.3'), Decimal('NaN')) Decimal('-1') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.compare_total(b) def compare_total_mag(self, a, b): @@ -3963,6 +3975,8 @@ Like compare_total, but with operand's sign ignored and assumed to be 0. """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.compare_total_mag(b) def copy_abs(self, a): @@ -4010,6 +4024,8 @@ >>> ExtendedContext.copy_sign(Decimal('-1.50'), Decimal('-7.33')) Decimal('-1.50') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.copy_sign(b) def divide(self, a, b): @@ -4036,7 +4052,13 @@ >>> ExtendedContext.divide(Decimal('2.40E+6'), Decimal('2')) Decimal('1.20E+6') """ - return a.__div__(b, context=self) + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + r = a.__div__(b, context=self) + if r is NotImplemented: + raise TypeError("Unable to convert %s to Decimal" % r) + else: + return r def divide_int(self, a, b): """Divides two numbers and returns the integer part of the result. @@ -4048,18 +4070,30 @@ >>> ExtendedContext.divide_int(Decimal('1'), Decimal('0.3')) Decimal('3') """ - return a.__floordiv__(b, context=self) - + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + r = a.__floordiv__(b, context=self) + if r is NotImplemented: + raise TypeError("Unable to convert %s to Decimal" % r) + else: + return r + def divmod(self, a, b): - """Return (a // b, a % b) - + """Return (self // other, self % other) + >>> ExtendedContext.divmod(Decimal(8), Decimal(3)) (Decimal('2'), Decimal('2')) >>> ExtendedContext.divmod(Decimal(8), Decimal(4)) (Decimal('2'), Decimal('0')) """ - return a.__divmod__(b, context=self) - + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + r = a.__divmod__(b, context=self) + if r is NotImplemented: + raise TypeError("Unable to convert %s to Decimal" % r) + else: + return r + def exp(self, a): """Returns e ** a. @@ -4095,6 +4129,8 @@ >>> ExtendedContext.fma(Decimal('888565290'), Decimal('1557.96930'), Decimal('-86087.7578')) Decimal('1.38435736E+12') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.fma(b, c, context=self) def is_canonical(self, a): @@ -4319,6 +4355,8 @@ >>> ExtendedContext.logical_and(Decimal('1111'), Decimal('10')) Decimal('10') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.logical_and(b, context=self) def logical_invert(self, a): @@ -4355,6 +4393,8 @@ >>> ExtendedContext.logical_or(Decimal('1110'), Decimal('10')) Decimal('1110') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.logical_or(b, context=self) def logical_xor(self, a, b): @@ -4375,6 +4415,8 @@ >>> ExtendedContext.logical_xor(Decimal('1111'), Decimal('10')) Decimal('1101') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.logical_xor(b, context=self) def max(self, a,b): @@ -4395,10 +4437,14 @@ >>> ExtendedContext.max(Decimal('7'), Decimal('NaN')) Decimal('7') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.max(b, context=self) def max_mag(self, a, b): """Compares the values numerically with their sign ignored.""" + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.max_mag(b, context=self) def min(self, a,b): @@ -4419,10 +4465,14 @@ >>> ExtendedContext.min(Decimal('7'), Decimal('NaN')) Decimal('7') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.min(b, context=self) def min_mag(self, a, b): """Compares the values numerically with their sign ignored.""" + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.min_mag(b, context=self) def minus(self, a): @@ -4458,8 +4508,14 @@ >>> ExtendedContext.multiply(Decimal('654321'), Decimal('654321')) Decimal('4.28135971E+11') """ - return a.__mul__(b, context=self) - + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + r = a.__mul__(b, context=self) + if r is NotImplemented: + raise TypeError("Unable to convert %s to Decimal" % r) + else: + return r + def next_minus(self, a): """Returns the largest representable number smaller than a. @@ -4520,6 +4576,8 @@ >>> c.next_toward(Decimal('0.00'), Decimal('-0.0000')) Decimal('-0.00') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.next_toward(b, context=self) def normalize(self, a): @@ -4671,6 +4729,8 @@ >>> c.power(Decimal('-23'), Decimal('0'), Decimal('65537')) Decimal('1') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.__pow__(b, modulo, context=self) def quantize(self, a, b): @@ -4722,6 +4782,8 @@ >>> ExtendedContext.quantize(Decimal('217'), Decimal('1e+2')) Decimal('2E+2') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.quantize(b, context=self) def radix(self): @@ -4757,8 +4819,14 @@ >>> ExtendedContext.remainder(Decimal('3.6'), Decimal('1.3')) Decimal('1.0') """ - return a.__mod__(b, context=self) - + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + r = a.__mod__(b, context=self) + if r is NotImplemented: + raise TypeError("Unable to convert %s to Decimal" % r) + else: + return r + def remainder_near(self, a, b): """Returns to be "a - b * n", where n is the integer nearest the exact value of "x / b" (if two integers are equally near then the even one @@ -4784,6 +4852,8 @@ >>> ExtendedContext.remainder_near(Decimal('3.6'), Decimal('1.3')) Decimal('-0.3') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.remainder_near(b, context=self) def rotate(self, a, b): @@ -4806,6 +4876,8 @@ >>> ExtendedContext.rotate(Decimal('123456789'), Decimal('+2')) Decimal('345678912') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.rotate(b, context=self) def same_quantum(self, a, b): @@ -4823,6 +4895,8 @@ >>> ExtendedContext.same_quantum(Decimal('Inf'), Decimal('-Inf')) True """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.same_quantum(b) def scaleb (self, a, b): @@ -4835,7 +4909,9 @@ >>> ExtendedContext.scaleb(Decimal('7.50'), Decimal('3')) Decimal('7.50E+3') """ - return a.scaleb (b, context=self) + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + return a.scaleb(b, context=self) def shift(self, a, b): """Returns a shifted copy of a, b times. @@ -4858,6 +4934,8 @@ >>> ExtendedContext.shift(Decimal('123456789'), Decimal('+2')) Decimal('345678900') """ + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) return a.shift(b, context=self) def sqrt(self, a): @@ -4899,8 +4977,14 @@ >>> ExtendedContext.subtract(Decimal('1.3'), Decimal('2.07')) Decimal('-0.77') """ - return a.__sub__(b, context=self) - + if not isinstance(a, Decimal): + a = _convert_other(a, raiseit=True) + r = a.__sub__(b, context=self) + if r is NotImplemented: + raise TypeError("Unable to convert %s to Decimal" % r) + else: + return r + def to_eng_string(self, a): """Converts a number to a string, using scientific notation. Index: Lib/test/test_decimal.py =================================================================== --- Lib/test/test_decimal.py (revisiĆ³n: 77330) +++ Lib/test/test_decimal.py (copia de trabajo) @@ -1638,7 +1638,256 @@ self.assertNotEqual(id(c), id(d)) self.assertNotEqual(id(c.flags), id(d.flags)) self.assertNotEqual(id(c.traps), id(d.traps)) + + def test_add(self): + c = Context() + d = c.add(Decimal(1), Decimal(1)) + self.assertEqual(c.add(1, 1), d) + self.assertEqual(c.add(Decimal(1), 1), d) + self.assertEqual(c.add(1, Decimal(1)), d) + self.assertRaises(TypeError, c.add, '1', 1) + self.assertRaises(TypeError, c.add, 1, '1') + + def test_compare(self): + c = Context() + d = c.compare(Decimal(1), Decimal(1)) + self.assertEqual(c.compare(1, 1), d) + self.assertEqual(c.compare(Decimal(1), 1), d) + self.assertEqual(c.compare(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare, '1', 1) + self.assertRaises(TypeError, c.compare, 1, '1') + def test_compare_signal(self): + c = Context() + d = c.compare_signal(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_signal(1, 1), d) + self.assertEqual(c.compare_signal(Decimal(1), 1), d) + self.assertEqual(c.compare_signal(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_signal, '1', 1) + self.assertRaises(TypeError, c.compare_signal, 1, '1') + + def test_compare_total(self): + c = Context() + d = c.compare_total(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_total(1, 1), d) + self.assertEqual(c.compare_total(Decimal(1), 1), d) + self.assertEqual(c.compare_total(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_total, '1', 1) + self.assertRaises(TypeError, c.compare_total, 1, '1') + + def test_compare_total_mag(self): + c = Context() + d = c.compare_total_mag(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_total_mag(1, 1), d) + self.assertEqual(c.compare_total_mag(Decimal(1), 1), d) + self.assertEqual(c.compare_total_mag(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_total_mag, '1', 1) + self.assertRaises(TypeError, c.compare_total_mag, 1, '1') + + def test_divide(self): + c = Context() + d = c.divide(Decimal(1), Decimal(2)) + self.assertEqual(c.divide(1, 2), d) + self.assertEqual(c.divide(Decimal(1), 2), d) + self.assertEqual(c.divide(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divide, '1', 2) + self.assertRaises(TypeError, c.divide, 1, '2') + + def test_divide_int(self): + c = Context() + d = c.divide_int(Decimal(1), Decimal(2)) + self.assertEqual(c.divide_int(1, 2), d) + self.assertEqual(c.divide_int(Decimal(1), 2), d) + self.assertEqual(c.divide_int(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divide_int, '1', 2) + self.assertRaises(TypeError, c.divide_int, 1, '2') + + def test_divmod(self): + c = Context() + d = c.divmod(Decimal(1), Decimal(2)) + self.assertEqual(c.divmod(1, 2), d) + self.assertEqual(c.divmod(Decimal(1), 2), d) + self.assertEqual(c.divmod(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divmod, '1', 2) + self.assertRaises(TypeError, c.divmod, 1, '2') + + def test_fma(self): + c = Context() + d = c.fma(Decimal(2), Decimal(3), Decimal(4)) + self.assertEqual(c.fma(2, 3, 4), d) + self.assertEqual(c.fma(Decimal(2), 3, 4), d) + self.assertEqual(c.fma(2, Decimal(3), 4), d) + self.assertEqual(c.fma(2, 3, Decimal(4)), d) + self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d) + self.assertRaises(TypeError, c.fma, '2', 3, 4) + self.assertRaises(TypeError, c.fma, 2, '3', 4) + self.assertRaises(TypeError, c.fma, 2, 3, '4') + + def test_logical_and(self): + c = Context() + d = c.logical_and(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_and(1, 1), d) + self.assertEqual(c.logical_and(Decimal(1), 1), d) + self.assertEqual(c.logical_and(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_and, '1', 1) + self.assertRaises(TypeError, c.logical_and, 1, '1') + + def test_logical_or(self): + c = Context() + d = c.logical_or(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_or(1, 1), d) + self.assertEqual(c.logical_or(Decimal(1), 1), d) + self.assertEqual(c.logical_or(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_or, '1', 1) + self.assertRaises(TypeError, c.logical_or, 1, '1') + + def test_logical_xor(self): + c = Context() + d = c.logical_xor(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_xor(1, 1), d) + self.assertEqual(c.logical_xor(Decimal(1), 1), d) + self.assertEqual(c.logical_xor(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_xor, '1', 1) + self.assertRaises(TypeError, c.logical_xor, 1, '1') + + def test_max(self): + c = Context() + d = c.max(Decimal(1), Decimal(2)) + self.assertEqual(c.max(1, 2), d) + self.assertEqual(c.max(Decimal(1), 2), d) + self.assertEqual(c.max(1, Decimal(2)), d) + self.assertRaises(TypeError, c.max, '1', 2) + self.assertRaises(TypeError, c.max, 1, '2') + + def test_max_mag(self): + c = Context() + d = c.max_mag(Decimal(1), Decimal(2)) + self.assertEqual(c.max_mag(1, 2), d) + self.assertEqual(c.max_mag(Decimal(1), 2), d) + self.assertEqual(c.max_mag(1, Decimal(2)), d) + self.assertRaises(TypeError, c.max_mag, '1', 2) + self.assertRaises(TypeError, c.max_mag, 1, '2') + + def test_min(self): + c = Context() + d = c.min(Decimal(1), Decimal(2)) + self.assertEqual(c.min(1, 2), d) + self.assertEqual(c.min(Decimal(1), 2), d) + self.assertEqual(c.min(1, Decimal(2)), d) + self.assertRaises(TypeError, c.min, '1', 2) + self.assertRaises(TypeError, c.min, 1, '2') + + def test_min_mag(self): + c = Context() + d = c.min_mag(Decimal(1), Decimal(2)) + self.assertEqual(c.min_mag(1, 2), d) + self.assertEqual(c.min_mag(Decimal(1), 2), d) + self.assertEqual(c.min_mag(1, Decimal(2)), d) + self.assertRaises(TypeError, c.min_mag, '1', 2) + self.assertRaises(TypeError, c.min_mag, 1, '2') + + def test_multiply(self): + c = Context() + d = c.multiply(Decimal(1), Decimal(2)) + self.assertEqual(c.multiply(1, 2), d) + self.assertEqual(c.multiply(Decimal(1), 2), d) + self.assertEqual(c.multiply(1, Decimal(2)), d) + self.assertRaises(TypeError, c.multiply, '1', 2) + self.assertRaises(TypeError, c.multiply, 1, '2') + + def test_next_toward(self): + c = Context() + d = c.next_toward(Decimal(1), Decimal(2)) + self.assertEqual(c.next_toward(1, 2), d) + self.assertEqual(c.next_toward(Decimal(1), 2), d) + self.assertEqual(c.next_toward(1, Decimal(2)), d) + self.assertRaises(TypeError, c.next_toward, '1', 2) + self.assertRaises(TypeError, c.next_toward, 1, '2') + + def test_power(self): + c = Context() + d = c.power(Decimal(1), Decimal(4), Decimal(2)) + self.assertEqual(c.power(1, 4, 2), d) + self.assertEqual(c.power(Decimal(1), 4, 2), d) + self.assertEqual(c.power(1, Decimal(4), 2), d) + self.assertEqual(c.power(1, 4, Decimal(2)), d) + self.assertEqual(c.power(Decimal(1), Decimal(4), 2), d) + self.assertRaises(TypeError, c.power, '1', 4, 2) + self.assertRaises(TypeError, c.power, 1, '4', 2) + self.assertRaises(TypeError, c.power, 1, 4, '2') + + def test_quantize(self): + c = Context() + d = c.quantize(Decimal(1), Decimal(2)) + self.assertEqual(c.quantize(1, 2), d) + self.assertEqual(c.quantize(Decimal(1), 2), d) + self.assertEqual(c.quantize(1, Decimal(2)), d) + self.assertRaises(TypeError, c.quantize, '1', 2) + self.assertRaises(TypeError, c.quantize, 1, '2') + + def test_remainder(self): + c = Context() + d = c.remainder(Decimal(1), Decimal(2)) + self.assertEqual(c.remainder(1, 2), d) + self.assertEqual(c.remainder(Decimal(1), 2), d) + self.assertEqual(c.remainder(1, Decimal(2)), d) + self.assertRaises(TypeError, c.remainder, '1', 2) + self.assertRaises(TypeError, c.remainder, 1, '2') + + def test_remainder_near(self): + c = Context() + d = c.remainder_near(Decimal(1), Decimal(2)) + self.assertEqual(c.remainder_near(1, 2), d) + self.assertEqual(c.remainder_near(Decimal(1), 2), d) + self.assertEqual(c.remainder_near(1, Decimal(2)), d) + self.assertRaises(TypeError, c.remainder_near, '1', 2) + self.assertRaises(TypeError, c.remainder_near, 1, '2') + + def test_rotate(self): + c = Context() + d = c.rotate(Decimal(1), Decimal(2)) + self.assertEqual(c.rotate(1, 2), d) + self.assertEqual(c.rotate(Decimal(1), 2), d) + self.assertEqual(c.rotate(1, Decimal(2)), d) + self.assertRaises(TypeError, c.rotate, '1', 2) + self.assertRaises(TypeError, c.rotate, 1, '2') + + def test_same_quantum(self): + c = Context() + d = c.same_quantum(Decimal(1), Decimal(2)) + self.assertEqual(c.same_quantum(1, 2), d) + self.assertEqual(c.same_quantum(Decimal(1), 2), d) + self.assertEqual(c.same_quantum(1, Decimal(2)), d) + self.assertRaises(TypeError, c.same_quantum, '1', 2) + self.assertRaises(TypeError, c.same_quantum, 1, '2') + + def test_scaleb(self): + c = Context() + d = c.scaleb(Decimal(1), Decimal(2)) + self.assertEqual(c.scaleb(1, 2), d) + self.assertEqual(c.scaleb(Decimal(1), 2), d) + self.assertEqual(c.scaleb(1, Decimal(2)), d) + self.assertRaises(TypeError, c.scaleb, '1', 2) + self.assertRaises(TypeError, c.scaleb, 1, '2') + + def test_shift(self): + c = Context() + d = c.shift(Decimal(1), Decimal(2)) + self.assertEqual(c.shift(1, 2), d) + self.assertEqual(c.shift(Decimal(1), 2), d) + self.assertEqual(c.shift(1, Decimal(2)), d) + self.assertRaises(TypeError, c.shift, '1', 2) + self.assertRaises(TypeError, c.shift, 1, '2') + + def test_subtract(self): + c = Context() + d = c.subtract(Decimal(1), Decimal(2)) + self.assertEqual(c.subtract(1, 2), d) + self.assertEqual(c.subtract(Decimal(1), 2), d) + self.assertEqual(c.subtract(1, Decimal(2)), d) + self.assertRaises(TypeError, c.subtract, '1', 2) + self.assertRaises(TypeError, c.subtract, 1, '2') + class WithStatementTest(unittest.TestCase): # Can't do these as docstrings until Python 2.6 # as doctest can't handle __future__ statements