#Issue 8540: Make Context._clamp attribute public in decimal module.
This commit is contained in:
parent
a92ad7ee2c
commit
b1d8e3229c
|
@ -122,7 +122,7 @@ precision, rounding, or enabled traps::
|
|||
>>> from decimal import *
|
||||
>>> getcontext()
|
||||
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
|
||||
capitals=1, flags=[], traps=[Overflow, DivisionByZero,
|
||||
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
|
||||
InvalidOperation])
|
||||
|
||||
>>> getcontext().prec = 7 # Set a new precision
|
||||
|
@ -244,7 +244,7 @@ enabled:
|
|||
|
||||
>>> ExtendedContext
|
||||
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
|
||||
capitals=1, flags=[], traps=[])
|
||||
capitals=1, clamp=0, flags=[], traps=[])
|
||||
>>> setcontext(ExtendedContext)
|
||||
>>> Decimal(1) / Decimal(7)
|
||||
Decimal('0.142857143')
|
||||
|
@ -269,7 +269,7 @@ using the :meth:`clear_flags` method. ::
|
|||
Decimal('3.14159292')
|
||||
>>> getcontext()
|
||||
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
|
||||
capitals=1, flags=[Inexact, Rounded], traps=[])
|
||||
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
|
||||
|
||||
The *flags* entry shows that the rational approximation to :const:`Pi` was
|
||||
rounded (digits beyond the context precision were thrown away) and that the
|
||||
|
@ -891,7 +891,7 @@ In addition to the three supplied contexts, new contexts can be created with the
|
|||
:class:`Context` constructor.
|
||||
|
||||
|
||||
.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=1)
|
||||
.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=None, clamp=None)
|
||||
|
||||
Creates a new context. If a field is not specified or is :const:`None`, the
|
||||
default values are copied from the :const:`DefaultContext`. If the *flags*
|
||||
|
@ -922,6 +922,23 @@ In addition to the three supplied contexts, new contexts can be created with the
|
|||
:const:`1`, exponents are printed with a capital :const:`E`; otherwise, a
|
||||
lowercase :const:`e` is used: :const:`Decimal('6.02e+23')`.
|
||||
|
||||
The *clamp* field is either :const:`0` (the default) or :const:`1`.
|
||||
If set to :const:`1`, the exponent ``e`` of a :class:`Decimal`
|
||||
instance representable in this context is strictly limited to the
|
||||
range ``Emin - prec + 1 <= e <= Emax - prec + 1``. If *clamp* is
|
||||
:const:`0` then a weaker condition holds: the adjusted exponent of
|
||||
the :class:`Decimal` instance is at most ``Emax``. When *clamp* is
|
||||
:const:`1`, a large normal number will, where possible, have its
|
||||
exponent reduced and a corresponding number of zeros added to its
|
||||
coefficient, in order to fit the exponent constraints; this
|
||||
preserves the value of the number but loses information about
|
||||
significant trailing zeros. For example::
|
||||
|
||||
>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999')
|
||||
Decimal('1.23000E+999')
|
||||
|
||||
A *clamp* value of :const:`1` allows compatibility with the
|
||||
fixed-width decimal interchange formats specified in IEEE 754.
|
||||
|
||||
The :class:`Context` class defines several general purpose methods as well as
|
||||
a large number of methods for doing arithmetic directly in a given context.
|
||||
|
|
|
@ -1611,9 +1611,9 @@ class Decimal(object):
|
|||
"""Decapitate the payload of a NaN to fit the context"""
|
||||
payload = self._int
|
||||
|
||||
# maximum length of payload is precision if _clamp=0,
|
||||
# precision-1 if _clamp=1.
|
||||
max_payload_len = context.prec - context._clamp
|
||||
# maximum length of payload is precision if clamp=0,
|
||||
# precision-1 if clamp=1.
|
||||
max_payload_len = context.prec - context.clamp
|
||||
if len(payload) > max_payload_len:
|
||||
payload = payload[len(payload)-max_payload_len:].lstrip('0')
|
||||
return _dec_from_triple(self._sign, payload, self._exp, True)
|
||||
|
@ -1638,11 +1638,11 @@ class Decimal(object):
|
|||
return Decimal(self)
|
||||
|
||||
# if self is zero then exponent should be between Etiny and
|
||||
# Emax if _clamp==0, and between Etiny and Etop if _clamp==1.
|
||||
# Emax if clamp==0, and between Etiny and Etop if clamp==1.
|
||||
Etiny = context.Etiny()
|
||||
Etop = context.Etop()
|
||||
if not self:
|
||||
exp_max = [context.Emax, Etop][context._clamp]
|
||||
exp_max = [context.Emax, Etop][context.clamp]
|
||||
new_exp = min(max(self._exp, Etiny), exp_max)
|
||||
if new_exp != self._exp:
|
||||
context._raise_error(Clamped)
|
||||
|
@ -1702,8 +1702,8 @@ class Decimal(object):
|
|||
if self_is_subnormal:
|
||||
context._raise_error(Subnormal)
|
||||
|
||||
# fold down if _clamp == 1 and self has too few digits
|
||||
if context._clamp == 1 and self._exp > Etop:
|
||||
# fold down if clamp == 1 and self has too few digits
|
||||
if context.clamp == 1 and self._exp > Etop:
|
||||
context._raise_error(Clamped)
|
||||
self_padded = self._int + '0'*(self._exp - Etop)
|
||||
return _dec_from_triple(self._sign, self_padded, Etop)
|
||||
|
@ -2451,7 +2451,7 @@ class Decimal(object):
|
|||
|
||||
if not dup:
|
||||
return _dec_from_triple(dup._sign, '0', 0)
|
||||
exp_max = [context.Emax, context.Etop()][context._clamp]
|
||||
exp_max = [context.Emax, context.Etop()][context.clamp]
|
||||
end = len(dup._int)
|
||||
exp = dup._exp
|
||||
while dup._int[end-1] == '0' and exp < exp_max:
|
||||
|
@ -3828,13 +3828,13 @@ class Context(object):
|
|||
Emax - Maximum exponent
|
||||
capitals - If 1, 1*10^1 is printed as 1E+1.
|
||||
If 0, printed as 1e1
|
||||
_clamp - If 1, change exponents if too high (Default 0)
|
||||
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=0,
|
||||
capitals=None, clamp=None,
|
||||
_ignored_flags=None):
|
||||
if flags is None:
|
||||
flags = []
|
||||
|
@ -3855,7 +3855,8 @@ class Context(object):
|
|||
"""Show the current context."""
|
||||
s = []
|
||||
s.append('Context(prec=%(prec)d, rounding=%(rounding)s, '
|
||||
'Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d'
|
||||
'Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d, '
|
||||
'clamp=%(clamp)d'
|
||||
% vars(self))
|
||||
names = [f.__name__ for f, v in self.flags.items() if v]
|
||||
s.append('flags=[' + ', '.join(names) + ']')
|
||||
|
@ -3872,17 +3873,39 @@ class Context(object):
|
|||
"""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)
|
||||
self.capitals, self.clamp, 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)
|
||||
self.capitals, self.clamp, self._ignored_flags)
|
||||
return nc
|
||||
__copy__ = copy
|
||||
|
||||
# _clamp is provided for backwards compatibility with third-party
|
||||
# code. May be removed in Python >= 3.3.
|
||||
def _get_clamp(self):
|
||||
"_clamp mirrors the clamp attribute. Its use is deprecated."
|
||||
import warnings
|
||||
warnings.warn('Use of the _clamp attribute is deprecated. '
|
||||
'Please use clamp instead.',
|
||||
DeprecationWarning)
|
||||
return self.clamp
|
||||
|
||||
def _set_clamp(self, clamp):
|
||||
"_clamp mirrors the clamp attribute. Its use is deprecated."
|
||||
import warnings
|
||||
warnings.warn('Use of the _clamp attribute is deprecated. '
|
||||
'Please use clamp instead.',
|
||||
DeprecationWarning)
|
||||
self.clamp = clamp
|
||||
|
||||
# don't bother with _del_clamp; no sane 3rd party code should
|
||||
# be deleting the _clamp attribute
|
||||
_clamp = property(_get_clamp, _set_clamp)
|
||||
|
||||
def _raise_error(self, condition, explanation = None, *args):
|
||||
"""Handles an error
|
||||
|
||||
|
@ -3965,7 +3988,7 @@ class Context(object):
|
|||
"permitted.")
|
||||
|
||||
d = Decimal(num, context=self)
|
||||
if d._isnan() and len(d._int) > self.prec - self._clamp:
|
||||
if d._isnan() and len(d._int) > self.prec - self.clamp:
|
||||
return self._raise_error(ConversionSyntax,
|
||||
"diagnostic info too long in NaN")
|
||||
return d._fix(self)
|
||||
|
@ -5875,7 +5898,8 @@ DefaultContext = Context(
|
|||
flags=[],
|
||||
Emax=999999999,
|
||||
Emin=-999999999,
|
||||
capitals=1
|
||||
capitals=1,
|
||||
clamp=0
|
||||
)
|
||||
|
||||
# Pre-made alternate contexts offered by the specification
|
||||
|
|
|
@ -27,11 +27,13 @@ with the corresponding argument.
|
|||
import math
|
||||
import os, sys
|
||||
import operator
|
||||
import warnings
|
||||
import pickle, copy
|
||||
import unittest
|
||||
from decimal import *
|
||||
import numbers
|
||||
from test.support import run_unittest, run_doctest, is_resource_enabled
|
||||
from test.support import check_warnings
|
||||
import random
|
||||
try:
|
||||
import threading
|
||||
|
@ -412,7 +414,7 @@ class DecimalTest(unittest.TestCase):
|
|||
def change_max_exponent(self, exp):
|
||||
self.context.Emax = exp
|
||||
def change_clamp(self, clamp):
|
||||
self.context._clamp = clamp
|
||||
self.context.clamp = clamp
|
||||
|
||||
|
||||
|
||||
|
@ -1815,6 +1817,26 @@ class ContextAPItests(unittest.TestCase):
|
|||
self.assertNotEqual(id(c.flags), id(d.flags))
|
||||
self.assertNotEqual(id(c.traps), id(d.traps))
|
||||
|
||||
def test__clamp(self):
|
||||
# In Python 3.2, the private attribute `_clamp` was made
|
||||
# public (issue 8540), with the old `_clamp` becoming a
|
||||
# property wrapping `clamp`. For the duration of Python 3.2
|
||||
# only, the attribute should be gettable/settable via both
|
||||
# `clamp` and `_clamp`; in Python 3.3, `_clamp` should be
|
||||
# removed.
|
||||
c = Context(clamp = 0)
|
||||
self.assertEqual(c.clamp, 0)
|
||||
|
||||
with check_warnings(("", DeprecationWarning)):
|
||||
c._clamp = 1
|
||||
self.assertEqual(c.clamp, 1)
|
||||
with check_warnings(("", DeprecationWarning)):
|
||||
self.assertEqual(c._clamp, 1)
|
||||
c.clamp = 0
|
||||
self.assertEqual(c.clamp, 0)
|
||||
with check_warnings(("", DeprecationWarning)):
|
||||
self.assertEqual(c._clamp, 0)
|
||||
|
||||
def test_abs(self):
|
||||
c = Context()
|
||||
d = c.abs(Decimal(-1))
|
||||
|
|
|
@ -393,6 +393,11 @@ C-API
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #8540: Decimal module: rename the Context._clamp attribute to
|
||||
Context.clamp and make it public. This is useful in creating
|
||||
contexts that correspond to the decimal interchange formats
|
||||
specified in IEEE 754.
|
||||
|
||||
- Issue #6268: Fix seek() method of codecs.open(), don't read or write the BOM
|
||||
twice after seek(0). Fix also reset() method of codecs, UTF-16, UTF-32 and
|
||||
StreamWriter classes.
|
||||
|
|
Loading…
Reference in New Issue