--- a/Lib/decimal.py Tue Dec 13 15:53:47 2011 +0200 |
+++ b/Lib/decimal.py Wed Dec 14 18:48:33 2011 +0100 |
@@ -46,8 +46,8 @@ |
Decimal('-0.0123') |
>>> Decimal(123456) |
Decimal('123456') |
->>> Decimal('123.45e12345678901234567890') |
-Decimal('1.2345E+12345678901234567892') |
+>>> Decimal('123.45e12345678') |
+Decimal('1.2345E+12345680') |
>>> Decimal('1.33') + Decimal('1.27') |
Decimal('2.60') |
>>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41') |
@@ -380,6 +380,10 @@ |
DivisionUndefined:InvalidOperation, |
InvalidContext:InvalidOperation} |
+# Valid rounding modes |
+_rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING, |
+ ROUND_FLOOR, ROUND_UP, ROUND_HALF_DOWN, ROUND_05UP) |
+ |
##### Context Functions ################################################## |
# The getcontext() and setcontext() function manage access to a thread-local |
@@ -684,7 +688,9 @@ |
""" |
if isinstance(f, int): # handle integer inputs |
return cls(f) |
- if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float |
+ if not isinstance(f, float): |
+ raise TypeError("argument must be int or float.") |
+ if _math.isinf(f) or _math.isnan(f): |
return cls(repr(f)) |
if _math.copysign(1.0, f) == 1.0: |
sign = 0 |
@@ -1906,11 +1912,12 @@ |
def _power_modulo(self, other, modulo, context=None): |
"""Three argument version of __pow__""" |
- # if can't convert other and modulo to Decimal, raise |
- # TypeError; there's no point returning NotImplemented (no |
- # equivalent of __rpow__ for three argument pow) |
- other = _convert_other(other, raiseit=True) |
- modulo = _convert_other(modulo, raiseit=True) |
+ other = _convert_other(other) |
+ if other is NotImplemented: |
+ return other |
+ modulo = _convert_other(modulo) |
+ if modulo is NotImplemented: |
+ return modulo |
if context is None: |
context = getcontext() |
@@ -3832,11 +3839,9 @@ |
clamp - If 1, change exponents if too high (Default 0) |
""" |
- def __init__(self, prec=None, rounding=None, |
- traps=None, flags=None, |
- Emin=None, Emax=None, |
- capitals=None, clamp=None, |
- _ignored_flags=None): |
+ def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, |
+ capitals=None, clamp=None, flags=None, traps=None, |
+ _ignored_flags=None): |
# Set defaults; for everything except flags and _ignored_flags, |
# inherit from DefaultContext. |
try: |
@@ -3859,17 +3864,78 @@ |
if traps is None: |
self.traps = dc.traps.copy() |
elif not isinstance(traps, dict): |
- self.traps = dict((s, int(s in traps)) for s in _signals) |
+ self.traps = dict((s, int(s in traps)) for s in _signals + traps) |
else: |
self.traps = traps |
if flags is None: |
self.flags = dict.fromkeys(_signals, 0) |
elif not isinstance(flags, dict): |
- self.flags = dict((s, int(s in flags)) for s in _signals) |
+ self.flags = dict((s, int(s in flags)) for s in _signals + flags) |
else: |
self.flags = flags |
+ def _set_integer_check(self, name, value, vmin, vmax): |
+ if not isinstance(value, int): |
+ raise TypeError("%s must be an integer" % name) |
+ if vmin == '-inf': |
+ if value > vmax: |
+ raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin, vmax, value)) |
+ elif vmax == 'inf': |
+ if value < vmin: |
+ raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin, vmax, value)) |
+ else: |
+ if value < vmin or value > vmax: |
+ raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value)) |
+ return object.__setattr__(self, name, value) |
+ |
+ def _set_signal_dict(self, name, d): |
+ if not isinstance(d, dict): |
+ raise TypeError("%s must be a signal dict" % d) |
+ for key in d: |
+ if not key in _signals: |
+ raise KeyError("%s is not a valid signal dict" % d) |
+ for key in _signals: |
+ if not key in d: |
+ raise KeyError("%s is not a valid signal dict" % d) |
+ return object.__setattr__(self, name, d) |
+ |
+ def __setattr__(self, name, value): |
+ if name == 'prec': |
+ return self._set_integer_check(name, value, 1, 'inf') |
+ elif name == 'Emin': |
+ return self._set_integer_check(name, value, '-inf', 0) |
+ elif name == 'Emax': |
+ return self._set_integer_check(name, value, 0, 'inf') |
+ elif name == 'capitals': |
+ return self._set_integer_check(name, value, 0, 1) |
+ elif name == 'clamp': |
+ return self._set_integer_check(name, value, 0, 1) |
+ elif name == 'rounding': |
+ if not value in _rounding_modes: |
+ # raise TypeError even for strings to have consistency |
+ # among various implementations. |
+ raise TypeError("%s: invalid rounding mode" % value) |
+ return object.__setattr__(self, name, value) |
+ elif name == 'flags' or name == 'traps': |
+ return self._set_signal_dict(name, value) |
+ elif name == '_ignored_flags': |
+ return object.__setattr__(self, name, value) |
+ else: |
+ raise AttributeError( |
+ "'decimal.Context' object has no attribute '%s'" % name) |
+ |
+ def __delattr__(self, name): |
+ raise AttributeError("%s cannot be deleted" % name) |
+ |
+ # Support for pickling, copy, and deepcopy |
+ def __reduce__(self): |
+ flags = [sig for sig, v in self.flags.items() if v] |
+ traps = [sig for sig, v in self.traps.items() if v] |
+ return (self.__class__, |
+ (self.prec, self.rounding, self.Emin, self.Emax, |
+ self.capitals, self.clamp, flags, traps)) |
+ |
def __repr__(self): |
"""Show the current context.""" |
s = [] |
@@ -3890,16 +3956,17 @@ |
def _shallow_copy(self): |
"""Returns a shallow copy from self.""" |
- nc = Context(self.prec, self.rounding, self.traps, |
- self.flags, self.Emin, self.Emax, |
- self.capitals, self.clamp, self._ignored_flags) |
+ nc = Context(self.prec, self.rounding, self.Emin, self.Emax, |
+ self.capitals, self.clamp, self.flags, self.traps, |
+ self._ignored_flags) |
return nc |
def copy(self): |
"""Returns a deep copy from self.""" |
- nc = Context(self.prec, self.rounding, self.traps.copy(), |
- self.flags.copy(), self.Emin, self.Emax, |
- self.capitals, self.clamp, self._ignored_flags) |
+ nc = Context(self.prec, self.rounding, self.Emin, self.Emax, |
+ self.capitals, self.clamp, |
+ self.flags.copy(), self.traps.copy(), |
+ self._ignored_flags) |
return nc |
__copy__ = copy |
@@ -4062,6 +4129,8 @@ |
>>> ExtendedContext.canonical(Decimal('2.50')) |
Decimal('2.50') |
""" |
+ if not isinstance(a, Decimal): |
+ raise TypeError("canonical requires a Decimal as an argument.") |
return a.canonical(context=self) |
def compare(self, a, b): |
@@ -4372,6 +4441,8 @@ |
>>> ExtendedContext.is_canonical(Decimal('2.50')) |
True |
""" |
+ if not isinstance(a, Decimal): |
+ raise TypeError("is_canonical requires a Decimal as an argument.") |
return a.is_canonical() |
def is_finite(self, a): |
@@ -4964,7 +5035,7 @@ |
+Normal |
+Infinity |
- >>> c = Context(ExtendedContext) |
+ >>> c = ExtendedContext.copy() |
>>> c.Emin = -999 |
>>> c.Emax = 999 |
>>> c.number_class(Decimal('Infinity')) |
@@ -6259,11 +6330,22 @@ |
# hash values to use for positive and negative infinities, and nans |
_PyHASH_INF = sys.hash_info.inf |
_PyHASH_NAN = sys.hash_info.nan |
-del sys |
# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS |
_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS) |
- |
+del sys |
+ |
+try: |
+ import _decimal |
+except ImportError: |
+ pass |
+else: |
+ s1 = set(dir()) |
+ s2 = set(dir(_decimal)) |
+ for name in s1 - s2: |
+ del globals()[name] |
+ del s1, s2, name |
+ from _decimal import * |
if __name__ == '__main__': |
import doctest, decimal |