Issue #15783: Except for the number methods, the C version of decimal now

supports all None default values present in decimal.py. These values were
largely undocumented.
This commit is contained in:
Stefan Krah 2012-12-15 22:33:33 +01:00
parent 618c2e13ca
commit 040e311826
8 changed files with 625 additions and 233 deletions

View File

@ -459,7 +459,7 @@ Decimal objects
a :class:`Decimal` instance is always canonical, so this operation returns a :class:`Decimal` instance is always canonical, so this operation returns
its argument unchanged. its argument unchanged.
.. method:: compare(other[, context]) .. method:: compare(other, context=None)
Compare the values of two Decimal instances. :meth:`compare` returns a Compare the values of two Decimal instances. :meth:`compare` returns a
Decimal instance, and if either operand is a NaN then the result is a Decimal instance, and if either operand is a NaN then the result is a
@ -470,13 +470,13 @@ Decimal objects
a == b ==> Decimal('0') a == b ==> Decimal('0')
a > b ==> Decimal('1') a > b ==> Decimal('1')
.. method:: compare_signal(other[, context]) .. method:: compare_signal(other, context=None)
This operation is identical to the :meth:`compare` method, except that all This operation is identical to the :meth:`compare` method, except that all
NaNs signal. That is, if neither operand is a signaling NaN then any NaNs signal. That is, if neither operand is a signaling NaN then any
quiet NaN operand is treated as though it were a signaling NaN. quiet NaN operand is treated as though it were a signaling NaN.
.. method:: compare_total(other) .. method:: compare_total(other, context=None)
Compare two operands using their abstract representation rather than their Compare two operands using their abstract representation rather than their
numerical value. Similar to the :meth:`compare` method, but the result numerical value. Similar to the :meth:`compare` method, but the result
@ -494,13 +494,21 @@ Decimal objects
higher in the total order than the second operand. See the specification higher in the total order than the second operand. See the specification
for details of the total order. for details of the total order.
.. method:: compare_total_mag(other) This operation is unaffected by context and is quiet: no flags are changed
and no rounding is performed. As an exception, the C version may raise
InvalidOperation if the second operand cannot be converted exactly.
.. method:: compare_total_mag(other, context=None)
Compare two operands using their abstract representation rather than their Compare two operands using their abstract representation rather than their
value as in :meth:`compare_total`, but ignoring the sign of each operand. value as in :meth:`compare_total`, but ignoring the sign of each operand.
``x.compare_total_mag(y)`` is equivalent to ``x.compare_total_mag(y)`` is equivalent to
``x.copy_abs().compare_total(y.copy_abs())``. ``x.copy_abs().compare_total(y.copy_abs())``.
This operation is unaffected by context and is quiet: no flags are changed
and no rounding is performed. As an exception, the C version may raise
InvalidOperation if the second operand cannot be converted exactly.
.. method:: conjugate() .. method:: conjugate()
Just returns self, this method is only to comply with the Decimal Just returns self, this method is only to comply with the Decimal
@ -517,7 +525,7 @@ Decimal objects
Return the negation of the argument. This operation is unaffected by the Return the negation of the argument. This operation is unaffected by the
context and is quiet: no flags are changed and no rounding is performed. context and is quiet: no flags are changed and no rounding is performed.
.. method:: copy_sign(other) .. method:: copy_sign(other, context=None)
Return a copy of the first operand with the sign set to be the same as the Return a copy of the first operand with the sign set to be the same as the
sign of the second operand. For example: sign of the second operand. For example:
@ -525,10 +533,11 @@ Decimal objects
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) >>> Decimal('2.3').copy_sign(Decimal('-1.5'))
Decimal('-2.3') Decimal('-2.3')
This operation is unaffected by the context and is quiet: no flags are This operation is unaffected by context and is quiet: no flags are changed
changed and no rounding is performed. and no rounding is performed. As an exception, the C version may raise
InvalidOperation if the second operand cannot be converted exactly.
.. method:: exp([context]) .. method:: exp(context=None)
Return the value of the (natural) exponential function ``e**x`` at the Return the value of the (natural) exponential function ``e**x`` at the
given number. The result is correctly rounded using the given number. The result is correctly rounded using the
@ -565,7 +574,7 @@ Decimal objects
.. versionadded:: 3.1 .. versionadded:: 3.1
.. method:: fma(other, third[, context]) .. method:: fma(other, third, context=None)
Fused multiply-add. Return self*other+third with no rounding of the Fused multiply-add. Return self*other+third with no rounding of the
intermediate product self*other. intermediate product self*other.
@ -594,7 +603,7 @@ Decimal objects
Return :const:`True` if the argument is a (quiet or signaling) NaN and Return :const:`True` if the argument is a (quiet or signaling) NaN and
:const:`False` otherwise. :const:`False` otherwise.
.. method:: is_normal() .. method:: is_normal(context=None)
Return :const:`True` if the argument is a *normal* finite number. Return Return :const:`True` if the argument is a *normal* finite number. Return
:const:`False` if the argument is zero, subnormal, infinite or a NaN. :const:`False` if the argument is zero, subnormal, infinite or a NaN.
@ -614,7 +623,7 @@ Decimal objects
Return :const:`True` if the argument is a signaling NaN and :const:`False` Return :const:`True` if the argument is a signaling NaN and :const:`False`
otherwise. otherwise.
.. method:: is_subnormal() .. method:: is_subnormal(context=None)
Return :const:`True` if the argument is subnormal, and :const:`False` Return :const:`True` if the argument is subnormal, and :const:`False`
otherwise. otherwise.
@ -624,17 +633,17 @@ Decimal objects
Return :const:`True` if the argument is a (positive or negative) zero and Return :const:`True` if the argument is a (positive or negative) zero and
:const:`False` otherwise. :const:`False` otherwise.
.. method:: ln([context]) .. method:: ln(context=None)
Return the natural (base e) logarithm of the operand. The result is Return the natural (base e) logarithm of the operand. The result is
correctly rounded using the :const:`ROUND_HALF_EVEN` rounding mode. correctly rounded using the :const:`ROUND_HALF_EVEN` rounding mode.
.. method:: log10([context]) .. method:: log10(context=None)
Return the base ten logarithm of the operand. The result is correctly Return the base ten logarithm of the operand. The result is correctly
rounded using the :const:`ROUND_HALF_EVEN` rounding mode. rounded using the :const:`ROUND_HALF_EVEN` rounding mode.
.. method:: logb([context]) .. method:: logb(context=None)
For a nonzero number, return the adjusted exponent of its operand as a For a nonzero number, return the adjusted exponent of its operand as a
:class:`Decimal` instance. If the operand is a zero then :class:`Decimal` instance. If the operand is a zero then
@ -642,73 +651,73 @@ Decimal objects
is raised. If the operand is an infinity then ``Decimal('Infinity')`` is is raised. If the operand is an infinity then ``Decimal('Infinity')`` is
returned. returned.
.. method:: logical_and(other[, context]) .. method:: logical_and(other, context=None)
:meth:`logical_and` is a logical operation which takes two *logical :meth:`logical_and` is a logical operation which takes two *logical
operands* (see :ref:`logical_operands_label`). The result is the operands* (see :ref:`logical_operands_label`). The result is the
digit-wise ``and`` of the two operands. digit-wise ``and`` of the two operands.
.. method:: logical_invert([context]) .. method:: logical_invert(context=None)
:meth:`logical_invert` is a logical operation. The :meth:`logical_invert` is a logical operation. The
result is the digit-wise inversion of the operand. result is the digit-wise inversion of the operand.
.. method:: logical_or(other[, context]) .. method:: logical_or(other, context=None)
:meth:`logical_or` is a logical operation which takes two *logical :meth:`logical_or` is a logical operation which takes two *logical
operands* (see :ref:`logical_operands_label`). The result is the operands* (see :ref:`logical_operands_label`). The result is the
digit-wise ``or`` of the two operands. digit-wise ``or`` of the two operands.
.. method:: logical_xor(other[, context]) .. method:: logical_xor(other, context=None)
:meth:`logical_xor` is a logical operation which takes two *logical :meth:`logical_xor` is a logical operation which takes two *logical
operands* (see :ref:`logical_operands_label`). The result is the operands* (see :ref:`logical_operands_label`). The result is the
digit-wise exclusive or of the two operands. digit-wise exclusive or of the two operands.
.. method:: max(other[, context]) .. method:: max(other, context=None)
Like ``max(self, other)`` except that the context rounding rule is applied Like ``max(self, other)`` except that the context rounding rule is applied
before returning and that :const:`NaN` values are either signaled or before returning and that :const:`NaN` values are either signaled or
ignored (depending on the context and whether they are signaling or ignored (depending on the context and whether they are signaling or
quiet). quiet).
.. method:: max_mag(other[, context]) .. method:: max_mag(other, context=None)
Similar to the :meth:`.max` method, but the comparison is done using the Similar to the :meth:`.max` method, but the comparison is done using the
absolute values of the operands. absolute values of the operands.
.. method:: min(other[, context]) .. method:: min(other, context=None)
Like ``min(self, other)`` except that the context rounding rule is applied Like ``min(self, other)`` except that the context rounding rule is applied
before returning and that :const:`NaN` values are either signaled or before returning and that :const:`NaN` values are either signaled or
ignored (depending on the context and whether they are signaling or ignored (depending on the context and whether they are signaling or
quiet). quiet).
.. method:: min_mag(other[, context]) .. method:: min_mag(other, context=None)
Similar to the :meth:`.min` method, but the comparison is done using the Similar to the :meth:`.min` method, but the comparison is done using the
absolute values of the operands. absolute values of the operands.
.. method:: next_minus([context]) .. method:: next_minus(context=None)
Return the largest number representable in the given context (or in the Return the largest number representable in the given context (or in the
current thread's context if no context is given) that is smaller than the current thread's context if no context is given) that is smaller than the
given operand. given operand.
.. method:: next_plus([context]) .. method:: next_plus(context=None)
Return the smallest number representable in the given context (or in the Return the smallest number representable in the given context (or in the
current thread's context if no context is given) that is larger than the current thread's context if no context is given) that is larger than the
given operand. given operand.
.. method:: next_toward(other[, context]) .. method:: next_toward(other, context=None)
If the two operands are unequal, return the number closest to the first If the two operands are unequal, return the number closest to the first
operand in the direction of the second operand. If both operands are operand in the direction of the second operand. If both operands are
numerically equal, return a copy of the first operand with the sign set to numerically equal, return a copy of the first operand with the sign set to
be the same as the sign of the second operand. be the same as the sign of the second operand.
.. method:: normalize([context]) .. method:: normalize(context=None)
Normalize the number by stripping the rightmost trailing zeros and Normalize the number by stripping the rightmost trailing zeros and
converting any result equal to :const:`Decimal('0')` to converting any result equal to :const:`Decimal('0')` to
@ -717,7 +726,7 @@ Decimal objects
``Decimal('0.321000e+2')`` both normalize to the equivalent value ``Decimal('0.321000e+2')`` both normalize to the equivalent value
``Decimal('32.1')``. ``Decimal('32.1')``.
.. method:: number_class([context]) .. method:: number_class(context=None)
Return a string describing the *class* of the operand. The returned value Return a string describing the *class* of the operand. The returned value
is one of the following ten strings. is one of the following ten strings.
@ -733,7 +742,7 @@ Decimal objects
* ``"NaN"``, indicating that the operand is a quiet NaN (Not a Number). * ``"NaN"``, indicating that the operand is a quiet NaN (Not a Number).
* ``"sNaN"``, indicating that the operand is a signaling NaN. * ``"sNaN"``, indicating that the operand is a signaling NaN.
.. method:: quantize(exp[, rounding[, context[, watchexp]]]) .. method:: quantize(exp, rounding=None, context=None, watchexp=True)
Return a value equal to the first operand after rounding and having the Return a value equal to the first operand after rounding and having the
exponent of the second operand. exponent of the second operand.
@ -771,7 +780,7 @@ Decimal objects
class does all its arithmetic. Included for compatibility with the class does all its arithmetic. Included for compatibility with the
specification. specification.
.. method:: remainder_near(other[, context]) .. method:: remainder_near(other, context=None)
Return the remainder from dividing *self* by *other*. This differs from Return the remainder from dividing *self* by *other*. This differs from
``self % other`` in that the sign of the remainder is chosen so as to ``self % other`` in that the sign of the remainder is chosen so as to
@ -789,7 +798,7 @@ Decimal objects
>>> Decimal(35).remainder_near(Decimal(10)) >>> Decimal(35).remainder_near(Decimal(10))
Decimal('-5') Decimal('-5')
.. method:: rotate(other[, context]) .. method:: rotate(other, context=None)
Return the result of rotating the digits of the first operand by an amount Return the result of rotating the digits of the first operand by an amount
specified by the second operand. The second operand must be an integer in specified by the second operand. The second operand must be an integer in
@ -800,18 +809,22 @@ Decimal objects
length precision if necessary. The sign and exponent of the first operand length precision if necessary. The sign and exponent of the first operand
are unchanged. are unchanged.
.. method:: same_quantum(other[, context]) .. method:: same_quantum(other, context=None)
Test whether self and other have the same exponent or whether both are Test whether self and other have the same exponent or whether both are
:const:`NaN`. :const:`NaN`.
.. method:: scaleb(other[, context]) This operation is unaffected by context and is quiet: no flags are changed
and no rounding is performed. As an exception, the C version may raise
InvalidOperation if the second operand cannot be converted exactly.
.. method:: scaleb(other, context=None)
Return the first operand with exponent adjusted by the second. Return the first operand with exponent adjusted by the second.
Equivalently, return the first operand multiplied by ``10**other``. The Equivalently, return the first operand multiplied by ``10**other``. The
second operand must be an integer. second operand must be an integer.
.. method:: shift(other[, context]) .. method:: shift(other, context=None)
Return the result of shifting the digits of the first operand by an amount Return the result of shifting the digits of the first operand by an amount
specified by the second operand. The second operand must be an integer in specified by the second operand. The second operand must be an integer in
@ -821,12 +834,12 @@ Decimal objects
right. Digits shifted into the coefficient are zeros. The sign and right. Digits shifted into the coefficient are zeros. The sign and
exponent of the first operand are unchanged. exponent of the first operand are unchanged.
.. method:: sqrt([context]) .. method:: sqrt(context=None)
Return the square root of the argument to full precision. Return the square root of the argument to full precision.
.. method:: to_eng_string([context]) .. method:: to_eng_string(context=None)
Convert to an engineering-type string. Convert to an engineering-type string.
@ -834,12 +847,12 @@ Decimal objects
are up to 3 digits left of the decimal place. For example, converts are up to 3 digits left of the decimal place. For example, converts
``Decimal('123E+1')`` to ``Decimal('1.23E+3')`` ``Decimal('123E+1')`` to ``Decimal('1.23E+3')``
.. method:: to_integral([rounding[, context]]) .. method:: to_integral(rounding=None, context=None)
Identical to the :meth:`to_integral_value` method. The ``to_integral`` Identical to the :meth:`to_integral_value` method. The ``to_integral``
name has been kept for compatibility with older versions. name has been kept for compatibility with older versions.
.. method:: to_integral_exact([rounding[, context]]) .. method:: to_integral_exact(rounding=None, context=None)
Round to the nearest integer, signaling :const:`Inexact` or Round to the nearest integer, signaling :const:`Inexact` or
:const:`Rounded` as appropriate if rounding occurs. The rounding mode is :const:`Rounded` as appropriate if rounding occurs. The rounding mode is
@ -847,7 +860,7 @@ Decimal objects
``context``. If neither parameter is given then the rounding mode of the ``context``. If neither parameter is given then the rounding mode of the
current context is used. current context is used.
.. method:: to_integral_value([rounding[, context]]) .. method:: to_integral_value(rounding=None, context=None)
Round to the nearest integer without signaling :const:`Inexact` or Round to the nearest integer without signaling :const:`Inexact` or
:const:`Rounded`. If given, applies *rounding*; otherwise, uses the :const:`Rounded`. If given, applies *rounding*; otherwise, uses the
@ -893,10 +906,10 @@ Each thread has its own current context which is accessed or changed using the
You can also use the :keyword:`with` statement and the :func:`localcontext` You can also use the :keyword:`with` statement and the :func:`localcontext`
function to temporarily change the active context. function to temporarily change the active context.
.. function:: localcontext([c]) .. function:: localcontext(ctx=None)
Return a context manager that will set the current context for the active thread Return a context manager that will set the current context for the active thread
to a copy of *c* on entry to the with-statement and restore the previous context to a copy of *ctx* on entry to the with-statement and restore the previous context
when exiting the with-statement. If no context is specified, a copy of the when exiting the with-statement. If no context is specified, a copy of the
current context is used. current context is used.
@ -1315,7 +1328,7 @@ In addition to the three supplied contexts, new contexts can be created with the
identity operation. identity operation.
.. method:: power(x, y[, modulo]) .. method:: power(x, y, modulo=None)
Return ``x`` to the power of ``y``, reduced modulo ``modulo`` if given. Return ``x`` to the power of ``y``, reduced modulo ``modulo`` if given.

View File

@ -2596,7 +2596,7 @@ class Decimal(object):
ans = ans._fix(context) ans = ans._fix(context)
return ans return ans
def same_quantum(self, other): def same_quantum(self, other, context=None):
"""Return True if self and other have the same exponent; otherwise """Return True if self and other have the same exponent; otherwise
return False. return False.
@ -2914,7 +2914,7 @@ class Decimal(object):
except TypeError: except TypeError:
return 0 return 0
def canonical(self, context=None): def canonical(self):
"""Returns the same Decimal object. """Returns the same Decimal object.
As we do not have different encodings for the same number, the As we do not have different encodings for the same number, the
@ -2934,7 +2934,7 @@ class Decimal(object):
return ans return ans
return self.compare(other, context=context) return self.compare(other, context=context)
def compare_total(self, other): def compare_total(self, other, context=None):
"""Compares self to other using the abstract representations. """Compares self to other using the abstract representations.
This is not like the standard compare, which use their numerical This is not like the standard compare, which use their numerical
@ -3007,7 +3007,7 @@ class Decimal(object):
return _Zero return _Zero
def compare_total_mag(self, other): def compare_total_mag(self, other, context=None):
"""Compares self to other using abstract repr., ignoring sign. """Compares self to other using abstract repr., ignoring sign.
Like compare_total, but with operand's sign ignored and assumed to be 0. Like compare_total, but with operand's sign ignored and assumed to be 0.
@ -3029,7 +3029,7 @@ class Decimal(object):
else: else:
return _dec_from_triple(1, self._int, self._exp, self._is_special) return _dec_from_triple(1, self._int, self._exp, self._is_special)
def copy_sign(self, other): def copy_sign(self, other, context=None):
"""Returns self with the sign of other.""" """Returns self with the sign of other."""
other = _convert_other(other, raiseit=True) other = _convert_other(other, raiseit=True)
return _dec_from_triple(other._sign, self._int, return _dec_from_triple(other._sign, self._int,
@ -4182,7 +4182,7 @@ class Context(object):
""" """
if not isinstance(a, Decimal): if not isinstance(a, Decimal):
raise TypeError("canonical requires a Decimal as an argument.") raise TypeError("canonical requires a Decimal as an argument.")
return a.canonical(context=self) return a.canonical()
def compare(self, a, b): def compare(self, a, b):
"""Compares values numerically. """Compares values numerically.

View File

@ -2089,6 +2089,248 @@ class UsabilityTest(unittest.TestCase):
self.assertEqual(str(Decimal(0).sqrt()), self.assertEqual(str(Decimal(0).sqrt()),
str(c.sqrt(Decimal(0)))) str(c.sqrt(Decimal(0))))
def test_none_args(self):
Decimal = self.decimal.Decimal
Context = self.decimal.Context
localcontext = self.decimal.localcontext
InvalidOperation = self.decimal.InvalidOperation
DivisionByZero = self.decimal.DivisionByZero
Overflow = self.decimal.Overflow
Underflow = self.decimal.Underflow
Subnormal = self.decimal.Subnormal
Inexact = self.decimal.Inexact
Rounded = self.decimal.Rounded
Clamped = self.decimal.Clamped
ROUND_HALF_EVEN = self.decimal.ROUND_HALF_EVEN
ROUND_DOWN = self.decimal.ROUND_DOWN
ROUND_UP = self.decimal.ROUND_UP
with localcontext(Context()) as c:
c.prec = 7
c.Emax = 999
c.Emin = -999
x = Decimal("111")
y = Decimal("1e9999")
z = Decimal("1e-9999")
##### Unary functions
c.clear_flags()
self.assertEqual(str(x.exp(context=None)), '1.609487E+48')
self.assertTrue(c.flags[Inexact])
self.assertTrue(c.flags[Rounded])
c.clear_flags()
self.assertRaises(Overflow, y.exp, context=None)
self.assertTrue(c.flags[Overflow])
self.assertIs(z.is_normal(context=None), False)
self.assertIs(z.is_subnormal(context=None), True)
c.clear_flags()
self.assertEqual(str(x.ln(context=None)), '4.709530')
self.assertTrue(c.flags[Inexact])
self.assertTrue(c.flags[Rounded])
c.clear_flags()
self.assertRaises(InvalidOperation, Decimal(-1).ln, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
self.assertEqual(str(x.log10(context=None)), '2.045323')
self.assertTrue(c.flags[Inexact])
self.assertTrue(c.flags[Rounded])
c.clear_flags()
self.assertRaises(InvalidOperation, Decimal(-1).log10, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
self.assertEqual(str(x.logb(context=None)), '2')
self.assertRaises(DivisionByZero, Decimal(0).logb, context=None)
self.assertTrue(c.flags[DivisionByZero])
c.clear_flags()
self.assertEqual(str(x.logical_invert(context=None)), '1111000')
self.assertRaises(InvalidOperation, y.logical_invert, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
self.assertEqual(str(y.next_minus(context=None)), '9.999999E+999')
self.assertRaises(InvalidOperation, Decimal('sNaN').next_minus, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
self.assertEqual(str(y.next_plus(context=None)), 'Infinity')
self.assertRaises(InvalidOperation, Decimal('sNaN').next_plus, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
self.assertEqual(str(z.normalize(context=None)), '0')
self.assertRaises(Overflow, y.normalize, context=None)
self.assertTrue(c.flags[Overflow])
self.assertEqual(str(z.number_class(context=None)), '+Subnormal')
c.clear_flags()
self.assertEqual(str(z.sqrt(context=None)), '0E-1005')
self.assertTrue(c.flags[Clamped])
self.assertTrue(c.flags[Inexact])
self.assertTrue(c.flags[Rounded])
self.assertTrue(c.flags[Subnormal])
self.assertTrue(c.flags[Underflow])
c.clear_flags()
self.assertRaises(Overflow, y.sqrt, context=None)
self.assertTrue(c.flags[Overflow])
c.capitals = 0
self.assertEqual(str(z.to_eng_string(context=None)), '1e-9999')
c.capitals = 1
##### Binary functions
c.clear_flags()
ans = str(x.compare(Decimal('Nan891287828'), context=None))
self.assertEqual(ans, 'NaN1287828')
self.assertRaises(InvalidOperation, x.compare, Decimal('sNaN'), context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.compare_signal(8224, context=None))
self.assertEqual(ans, '-1')
self.assertRaises(InvalidOperation, x.compare_signal, Decimal('NaN'), context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.logical_and(101, context=None))
self.assertEqual(ans, '101')
self.assertRaises(InvalidOperation, x.logical_and, 123, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.logical_or(101, context=None))
self.assertEqual(ans, '111')
self.assertRaises(InvalidOperation, x.logical_or, 123, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.logical_xor(101, context=None))
self.assertEqual(ans, '10')
self.assertRaises(InvalidOperation, x.logical_xor, 123, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.max(101, context=None))
self.assertEqual(ans, '111')
self.assertRaises(InvalidOperation, x.max, Decimal('sNaN'), context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.max_mag(101, context=None))
self.assertEqual(ans, '111')
self.assertRaises(InvalidOperation, x.max_mag, Decimal('sNaN'), context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.min(101, context=None))
self.assertEqual(ans, '101')
self.assertRaises(InvalidOperation, x.min, Decimal('sNaN'), context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.min_mag(101, context=None))
self.assertEqual(ans, '101')
self.assertRaises(InvalidOperation, x.min_mag, Decimal('sNaN'), context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.remainder_near(101, context=None))
self.assertEqual(ans, '10')
self.assertRaises(InvalidOperation, y.remainder_near, 101, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.rotate(2, context=None))
self.assertEqual(ans, '11100')
self.assertRaises(InvalidOperation, x.rotate, 101, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.scaleb(7, context=None))
self.assertEqual(ans, '1.11E+9')
self.assertRaises(InvalidOperation, x.scaleb, 10000, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.clear_flags()
ans = str(x.shift(2, context=None))
self.assertEqual(ans, '11100')
self.assertRaises(InvalidOperation, x.shift, 10000, context=None)
self.assertTrue(c.flags[InvalidOperation])
##### Ternary functions
c.clear_flags()
ans = str(x.fma(2, 3, context=None))
self.assertEqual(ans, '225')
self.assertRaises(Overflow, x.fma, Decimal('1e9999'), 3, context=None)
self.assertTrue(c.flags[Overflow])
##### Special cases
c.rounding = ROUND_HALF_EVEN
ans = str(Decimal('1.5').to_integral(rounding=None, context=None))
self.assertEqual(ans, '2')
c.rounding = ROUND_DOWN
ans = str(Decimal('1.5').to_integral(rounding=None, context=None))
self.assertEqual(ans, '1')
ans = str(Decimal('1.5').to_integral(rounding=ROUND_UP, context=None))
self.assertEqual(ans, '2')
c.clear_flags()
self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.rounding = ROUND_HALF_EVEN
ans = str(Decimal('1.5').to_integral_value(rounding=None, context=None))
self.assertEqual(ans, '2')
c.rounding = ROUND_DOWN
ans = str(Decimal('1.5').to_integral_value(rounding=None, context=None))
self.assertEqual(ans, '1')
ans = str(Decimal('1.5').to_integral_value(rounding=ROUND_UP, context=None))
self.assertEqual(ans, '2')
c.clear_flags()
self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral_value, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.rounding = ROUND_HALF_EVEN
ans = str(Decimal('1.5').to_integral_exact(rounding=None, context=None))
self.assertEqual(ans, '2')
c.rounding = ROUND_DOWN
ans = str(Decimal('1.5').to_integral_exact(rounding=None, context=None))
self.assertEqual(ans, '1')
ans = str(Decimal('1.5').to_integral_exact(rounding=ROUND_UP, context=None))
self.assertEqual(ans, '2')
c.clear_flags()
self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral_exact, context=None)
self.assertTrue(c.flags[InvalidOperation])
c.rounding = ROUND_UP
ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=None, context=None))
self.assertEqual(ans, '1.501')
c.rounding = ROUND_DOWN
ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=None, context=None))
self.assertEqual(ans, '1.500')
ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=ROUND_UP, context=None))
self.assertEqual(ans, '1.501')
c.clear_flags()
self.assertRaises(InvalidOperation, y.quantize, Decimal('1e-10'), rounding=ROUND_UP, context=None)
self.assertTrue(c.flags[InvalidOperation])
with localcontext(Context()) as context:
context.prec = 7
context.Emax = 999
context.Emin = -999
with localcontext(ctx=None) as c:
self.assertEqual(c.prec, 7)
self.assertEqual(c.Emax, 999)
self.assertEqual(c.Emin, -999)
def test_conversions_from_int(self): def test_conversions_from_int(self):
# Check that methods taking a second Decimal argument will # Check that methods taking a second Decimal argument will
# always accept an integer in place of a Decimal. # always accept an integer in place of a Decimal.
@ -2423,14 +2665,11 @@ class PythonAPItests(unittest.TestCase):
self.assertRaises(TypeError, D.from_float, 1.1, context=xc) self.assertRaises(TypeError, D.from_float, 1.1, context=xc)
self.assertRaises(TypeError, D(0).as_tuple, context=xc) self.assertRaises(TypeError, D(0).as_tuple, context=xc)
if (self.decimal == C): self.assertEqual(D(1).canonical(), 1)
self.assertRaises(TypeError, D(1).canonical, context=xc) self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
self.assertEqual(D("-1").copy_abs(context=xc), 1) self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
self.assertEqual(D("1").copy_negate(context=xc), -1) self.assertRaises(TypeError, D(1).canonical, context="x")
else: self.assertRaises(TypeError, D(1).canonical, xyz="x")
self.assertEqual(D(1).canonical(context=xc), 1)
self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
def test_exception_hierarchy(self): def test_exception_hierarchy(self):
@ -4593,6 +4832,9 @@ class CWhitebox(unittest.TestCase):
# Invalid local context # Invalid local context
self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass', self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass',
locals()) locals())
self.assertRaises(TypeError, exec,
'with localcontext(context=getcontext()): pass',
locals())
# setcontext # setcontext
saved_context = getcontext() saved_context = getcontext()
@ -4826,6 +5068,50 @@ class CWhitebox(unittest.TestCase):
c.prec = 2 c.prec = 2
self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501) self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501)
def test_va_args_exceptions(self):
Decimal = C.Decimal
Context = C.Context
x = Decimal("10001111111")
for attr in ['exp', 'is_normal', 'is_subnormal', 'ln', 'log10',
'logb', 'logical_invert', 'next_minus', 'next_plus',
'normalize', 'number_class', 'sqrt', 'to_eng_string']:
func = getattr(x, attr)
self.assertRaises(TypeError, func, context="x")
self.assertRaises(TypeError, func, "x", context=None)
for attr in ['compare', 'compare_signal', 'logical_and',
'logical_or', 'max', 'max_mag', 'min', 'min_mag',
'remainder_near', 'rotate', 'scaleb', 'shift']:
func = getattr(x, attr)
self.assertRaises(TypeError, func, context="x")
self.assertRaises(TypeError, func, "x", context=None)
self.assertRaises(TypeError, x.to_integral, rounding=None, context=[])
self.assertRaises(TypeError, x.to_integral, rounding={}, context=[])
self.assertRaises(TypeError, x.to_integral, [], [])
self.assertRaises(TypeError, x.to_integral_value, rounding=None, context=[])
self.assertRaises(TypeError, x.to_integral_value, rounding={}, context=[])
self.assertRaises(TypeError, x.to_integral_value, [], [])
self.assertRaises(TypeError, x.to_integral_exact, rounding=None, context=[])
self.assertRaises(TypeError, x.to_integral_exact, rounding={}, context=[])
self.assertRaises(TypeError, x.to_integral_exact, [], [])
self.assertRaises(TypeError, x.fma, 1, 2, context="x")
self.assertRaises(TypeError, x.fma, 1, 2, "x", context=None)
self.assertRaises(TypeError, x.quantize, 1, [], context=None)
self.assertRaises(TypeError, x.quantize, 1, [], rounding=None)
self.assertRaises(TypeError, x.quantize, 1, [], [])
c = Context()
self.assertRaises(TypeError, c.power, 1, 2, mod="x")
self.assertRaises(TypeError, c.power, 1, "x", mod=None)
self.assertRaises(TypeError, c.power, "x", 2, mod=None)
@requires_extra_functionality @requires_extra_functionality
def test_c_context_templates(self): def test_c_context_templates(self):
self.assertEqual( self.assertEqual(

View File

@ -108,6 +108,10 @@ Core and Builtins
Library Library
------- -------
- Issue #15783: Except for the number methods, the C version of decimal now
supports all None default values present in decimal.py. These values were
largely undocumented.
- Issue #16298: In HTTPResponse.read(), close the socket when there is no - Issue #16298: In HTTPResponse.read(), close the socket when there is no
Content-Length and the incoming stream is finished. Patch by Eran Content-Length and the incoming stream is finished. Patch by Eran
Rundstein. Rundstein.

View File

@ -1486,7 +1486,10 @@ static PyGetSetDef context_getsets [] =
} }
#define CONTEXT_CHECK_VA(obj) \ #define CONTEXT_CHECK_VA(obj) \
if (!PyDecContext_Check(obj)) { \ if (obj == Py_None) { \
CURRENT_CONTEXT(obj); \
} \
else if (!PyDecContext_Check(obj)) { \
PyErr_SetString(PyExc_TypeError, \ PyErr_SetString(PyExc_TypeError, \
"optional argument must be a context"); \ "optional argument must be a context"); \
return NULL; \ return NULL; \
@ -1715,18 +1718,25 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
* owns one reference to the global (outer) context and one * owns one reference to the global (outer) context and one
* to the local (inner) context. */ * to the local (inner) context. */
static PyObject * static PyObject *
ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args) ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"ctx", NULL};
PyDecContextManagerObject *self; PyDecContextManagerObject *self;
PyObject *local; PyObject *local = Py_None;
PyObject *global; PyObject *global;
CURRENT_CONTEXT(global); CURRENT_CONTEXT(global);
local = global; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &local)) {
if (!PyArg_ParseTuple(args, "|O", &local)) { return NULL;
}
if (local == Py_None) {
local = global;
}
else if (!PyDecContext_Check(local)) {
PyErr_SetString(PyExc_TypeError,
"optional argument must be a context");
return NULL; return NULL;
} }
CONTEXT_CHECK_VA(local);
self = PyObject_New(PyDecContextManagerObject, self = PyObject_New(PyDecContextManagerObject,
&PyDecContextManager_Type); &PyDecContextManager_Type);
@ -2749,9 +2759,8 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"value", "context", NULL}; static char *kwlist[] = {"value", "context", NULL};
PyObject *v = NULL; PyObject *v = NULL;
PyObject *context; PyObject *context = Py_None;
CURRENT_CONTEXT(context);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist,
&v, &context)) { &v, &context)) {
return NULL; return NULL;
@ -3315,20 +3324,23 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"rounding", "context", NULL}; static char *kwlist[] = {"rounding", "context", NULL};
PyObject *result; PyObject *result;
PyObject *context; PyObject *rounding = Py_None;
PyObject *context = Py_None;
uint32_t status = 0; uint32_t status = 0;
mpd_context_t workctx; mpd_context_t workctx;
int round = -1;
CURRENT_CONTEXT(context); if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist,
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, &rounding, &context)) {
&round, &context)) {
return NULL; return NULL;
} }
CONTEXT_CHECK_VA(context); CONTEXT_CHECK_VA(context);
workctx = *CTX(context); workctx = *CTX(context);
if (round >= 0) { if (rounding != Py_None) {
int round = getround(rounding);
if (round < 0) {
return NULL;
}
if (!mpd_qsetround(&workctx, round)) { if (!mpd_qsetround(&workctx, round)) {
return type_error_ptr(invalid_rounding_err); return type_error_ptr(invalid_rounding_err);
} }
@ -3353,20 +3365,23 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"rounding", "context", NULL}; static char *kwlist[] = {"rounding", "context", NULL};
PyObject *result; PyObject *result;
PyObject *context; PyObject *rounding = Py_None;
PyObject *context = Py_None;
uint32_t status = 0; uint32_t status = 0;
mpd_context_t workctx; mpd_context_t workctx;
int round = -1;
CURRENT_CONTEXT(context); if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist,
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, &rounding, &context)) {
&round, &context)) {
return NULL; return NULL;
} }
CONTEXT_CHECK_VA(context); CONTEXT_CHECK_VA(context);
workctx = *CTX(context); workctx = *CTX(context);
if (round >= 0) { if (rounding != Py_None) {
int round = getround(rounding);
if (round < 0) {
return NULL;
}
if (!mpd_qsetround(&workctx, round)) { if (!mpd_qsetround(&workctx, round)) {
return type_error_ptr(invalid_rounding_err); return type_error_ptr(invalid_rounding_err);
} }
@ -3633,9 +3648,8 @@ static PyObject * \
dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
{ \ { \
static char *kwlist[] = {"context", NULL}; \ static char *kwlist[] = {"context", NULL}; \
PyObject *context; \ PyObject *context = Py_None; \
\ \
CURRENT_CONTEXT(context); \
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \
&context)) { \ &context)) { \
return NULL; \ return NULL; \
@ -3652,10 +3666,9 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
{ \ { \
static char *kwlist[] = {"context", NULL}; \ static char *kwlist[] = {"context", NULL}; \
PyObject *result; \ PyObject *result; \
PyObject *context; \ PyObject *context = Py_None; \
uint32_t status = 0; \ uint32_t status = 0; \
\ \
CURRENT_CONTEXT(context); \
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \
&context)) { \ &context)) { \
return NULL; \ return NULL; \
@ -3675,49 +3688,18 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
return result; \ return result; \
} }
/* Unary function with an optional context arg. The actual MPDFUNC
only takes a status parameter. */
#define Dec_UnaryFuncVA_NO_CTX(MPDFUNC) \
static PyObject * \
dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
{ \
static char *kwlist[] = {"context", NULL}; \
PyObject *result; \
PyObject *context; \
uint32_t status = 0; \
\
CURRENT_CONTEXT(context); \
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \
&context)) { \
return NULL; \
} \
CONTEXT_CHECK_VA(context); \
\
if ((result = dec_alloc()) == NULL) { \
return NULL; \
} \
\
MPDFUNC(MPD(result), MPD(self), &status); \
if (dec_addstatus(context, status)) { \
Py_DECREF(result); \
return NULL; \
} \
\
return result; \
}
/* Binary function with an optional context arg. */ /* Binary function with an optional context arg. */
#define Dec_BinaryFuncVA(MPDFUNC) \ #define Dec_BinaryFuncVA(MPDFUNC) \
static PyObject * \ static PyObject * \
dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
{ \ { \
static char *kwlist[] = {"other", "context", NULL}; \ static char *kwlist[] = {"other", "context", NULL}; \
PyObject *other, *context; \ PyObject *other; \
PyObject *a, *b; \ PyObject *a, *b; \
PyObject *result; \ PyObject *result; \
PyObject *context = Py_None; \
uint32_t status = 0; \ uint32_t status = 0; \
\ \
CURRENT_CONTEXT(context); \
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \
&other, &context)) { \ &other, &context)) { \
return NULL; \ return NULL; \
@ -3750,11 +3732,11 @@ static PyObject * \
dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
{ \ { \
static char *kwlist[] = {"other", "context", NULL}; \ static char *kwlist[] = {"other", "context", NULL}; \
PyObject *other, *context; \ PyObject *context = Py_None; \
PyObject *other; \
PyObject *a, *b; \ PyObject *a, *b; \
PyObject *result; \ PyObject *result; \
\ \
CURRENT_CONTEXT(context); \
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \
&other, &context)) { \ &other, &context)) { \
return NULL; \ return NULL; \
@ -3781,12 +3763,12 @@ static PyObject * \
dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
{ \ { \
static char *kwlist[] = {"other", "third", "context", NULL}; \ static char *kwlist[] = {"other", "third", "context", NULL}; \
PyObject *other, *third, *context; \ PyObject *other, *third; \
PyObject *a, *b, *c; \ PyObject *a, *b, *c; \
PyObject *result; \ PyObject *result; \
PyObject *context = Py_None; \
uint32_t status = 0; \ uint32_t status = 0; \
\ \
CURRENT_CONTEXT(context); \
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist, \ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist, \
&other, &third, &context)) { \ &other, &third, &context)) { \
return NULL; \ return NULL; \
@ -4019,9 +4001,45 @@ dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED)
return result; return result;
} }
/* Unary functions, optional context arg for conversion errors */ static PyObject *
Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_abs) dec_mpd_qcopy_abs(PyObject *self, PyObject *dummy UNUSED)
Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_negate) {
PyObject *result;
uint32_t status = 0;
if ((result = dec_alloc()) == NULL) {
return NULL;
}
mpd_qcopy_abs(MPD(result), MPD(self), &status);
if (status & MPD_Malloc_error) {
Py_DECREF(result);
PyErr_NoMemory();
return NULL;
}
return result;
}
static PyObject *
dec_mpd_qcopy_negate(PyObject *self, PyObject *dummy UNUSED)
{
PyObject *result;
uint32_t status = 0;
if ((result = dec_alloc()) == NULL) {
return NULL;
}
mpd_qcopy_negate(MPD(result), MPD(self), &status);
if (status & MPD_Malloc_error) {
Py_DECREF(result);
PyErr_NoMemory();
return NULL;
}
return result;
}
/* Unary functions, optional context arg */ /* Unary functions, optional context arg */
Dec_UnaryFuncVA(mpd_qinvert) Dec_UnaryFuncVA(mpd_qinvert)
@ -4031,10 +4049,9 @@ static PyObject *
dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"context", NULL}; static char *kwlist[] = {"context", NULL};
PyObject *context; PyObject *context = Py_None;
const char *cp; const char *cp;
CURRENT_CONTEXT(context);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist,
&context)) { &context)) {
return NULL; return NULL;
@ -4050,11 +4067,10 @@ dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"context", NULL}; static char *kwlist[] = {"context", NULL};
PyObject *result; PyObject *result;
PyObject *context; PyObject *context = Py_None;
mpd_ssize_t size; mpd_ssize_t size;
char *s; char *s;
CURRENT_CONTEXT(context);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist,
&context)) { &context)) {
return NULL; return NULL;
@ -4081,12 +4097,12 @@ static PyObject *
dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"other", "context", NULL}; static char *kwlist[] = {"other", "context", NULL};
PyObject *other, *context; PyObject *other;
PyObject *a, *b; PyObject *a, *b;
PyObject *result; PyObject *result;
PyObject *context = Py_None;
uint32_t status = 0; uint32_t status = 0;
CURRENT_CONTEXT(context);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
&other, &context)) { &other, &context)) {
return NULL; return NULL;
@ -4116,11 +4132,11 @@ static PyObject *
dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"other", "context", NULL}; static char *kwlist[] = {"other", "context", NULL};
PyObject *other, *context; PyObject *other;
PyObject *a, *b; PyObject *a, *b;
PyObject *result; PyObject *result;
PyObject *context = Py_None;
CURRENT_CONTEXT(context);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
&other, &context)) { &other, &context)) {
return NULL; return NULL;
@ -4148,22 +4164,25 @@ static PyObject *
dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"exp", "rounding", "context", NULL}; static char *kwlist[] = {"exp", "rounding", "context", NULL};
PyObject *w, *context; PyObject *rounding = Py_None;
PyObject *a, *b; PyObject *context = Py_None;
PyObject *w, *a, *b;
PyObject *result; PyObject *result;
uint32_t status = 0; uint32_t status = 0;
mpd_context_t workctx; mpd_context_t workctx;
int round = -1;
CURRENT_CONTEXT(context); if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist,
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO", kwlist, &w, &rounding, &context)) {
&w, &round, &context)) {
return NULL; return NULL;
} }
CONTEXT_CHECK_VA(context); CONTEXT_CHECK_VA(context);
workctx = *CTX(context); workctx = *CTX(context);
if (round >= 0) { if (rounding != Py_None) {
int round = getround(rounding);
if (round < 0) {
return NULL;
}
if (!mpd_qsetround(&workctx, round)) { if (!mpd_qsetround(&workctx, round)) {
return type_error_ptr(invalid_rounding_err); return type_error_ptr(invalid_rounding_err);
} }
@ -4585,8 +4604,8 @@ static PyMethodDef dec_methods [] =
{ "radix", dec_mpd_radix, METH_NOARGS, doc_radix }, { "radix", dec_mpd_radix, METH_NOARGS, doc_radix },
/* Unary functions, optional context arg for conversion errors */ /* Unary functions, optional context arg for conversion errors */
{ "copy_abs", (PyCFunction)dec_mpd_qcopy_abs, METH_VARARGS|METH_KEYWORDS, doc_copy_abs }, { "copy_abs", dec_mpd_qcopy_abs, METH_NOARGS, doc_copy_abs },
{ "copy_negate", (PyCFunction)dec_mpd_qcopy_negate, METH_VARARGS|METH_KEYWORDS, doc_copy_negate }, { "copy_negate", dec_mpd_qcopy_negate, METH_NOARGS, doc_copy_negate },
/* Unary functions, optional context arg */ /* Unary functions, optional context arg */
{ "logb", (PyCFunction)dec_mpd_qlogb, METH_VARARGS|METH_KEYWORDS, doc_logb }, { "logb", (PyCFunction)dec_mpd_qlogb, METH_VARARGS|METH_KEYWORDS, doc_logb },
@ -4916,7 +4935,7 @@ static PyObject *
ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds) ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"a", "b", "modulo", NULL}; static char *kwlist[] = {"a", "b", "modulo", NULL};
PyObject *base, *exp, *mod = NULL; PyObject *base, *exp, *mod = Py_None;
PyObject *a, *b, *c = NULL; PyObject *a, *b, *c = NULL;
PyObject *result; PyObject *result;
uint32_t status = 0; uint32_t status = 0;
@ -4928,7 +4947,7 @@ ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds)
CONVERT_BINOP_RAISE(&a, &b, base, exp, context); CONVERT_BINOP_RAISE(&a, &b, base, exp, context);
if (mod != NULL) { if (mod != Py_None) {
if (!convert_op(TYPE_ERR, &c, mod, context)) { if (!convert_op(TYPE_ERR, &c, mod, context)) {
Py_DECREF(a); Py_DECREF(a);
Py_DECREF(b); Py_DECREF(b);
@ -5361,7 +5380,7 @@ static PyMethodDef _decimal_methods [] =
{ {
{ "getcontext", (PyCFunction)PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext}, { "getcontext", (PyCFunction)PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext},
{ "setcontext", (PyCFunction)PyDec_SetCurrentContext, METH_O, doc_setcontext}, { "setcontext", (PyCFunction)PyDec_SetCurrentContext, METH_O, doc_setcontext},
{ "localcontext", (PyCFunction)ctxmanager_new, METH_VARARGS, doc_localcontext}, { "localcontext", (PyCFunction)ctxmanager_new, METH_VARARGS|METH_KEYWORDS, doc_localcontext},
#ifdef EXTRA_FUNCTIONALITY #ifdef EXTRA_FUNCTIONALITY
{ "IEEEContext", (PyCFunction)ieee_context, METH_O, doc_ieee_context}, { "IEEEContext", (PyCFunction)ieee_context, METH_O, doc_ieee_context},
#endif #endif

View File

@ -28,10 +28,10 @@ setcontext(c) - Set a new default context.\n\
\n"); \n");
PyDoc_STRVAR(doc_localcontext,"\n\ PyDoc_STRVAR(doc_localcontext,"\n\
localcontext(c) - Return a context manager that will set the default context\n\ localcontext(ctx=None) - Return a context manager that will set the default\n\
to a copy of c on entry to the with-statement and restore the previous default\n\ context to a copy of ctx on entry to the with-statement and restore the\n\
context when exiting the with-statement. If no context is specified, a copy of\n\ previous default context when exiting the with-statement. If no context is\n\
the current default context is used.\n\ specified, a copy of the current default context is used.\n\
\n"); \n");
#ifdef EXTRA_FUNCTIONALITY #ifdef EXTRA_FUNCTIONALITY
@ -49,8 +49,7 @@ DECIMAL32, DECIMAL64 and DECIMAL128 are provided.\n\
/******************************************************************************/ /******************************************************************************/
PyDoc_STRVAR(doc_decimal,"\n\ PyDoc_STRVAR(doc_decimal,"\n\
Decimal([value[, context]]): Construct a new Decimal object from value.\n\ Decimal(value=\"0\", context=None): Construct a new Decimal object.\n\
\n\
value can be an integer, string, tuple, or another Decimal object.\n\ value can be an integer, string, tuple, or another Decimal object.\n\
If no value is given, return Decimal('0'). The context does not affect\n\ If no value is given, return Decimal('0'). The context does not affect\n\
the conversion and is only passed to determine if the InvalidOperation\n\ the conversion and is only passed to determine if the InvalidOperation\n\
@ -74,7 +73,7 @@ returns its argument unchanged.\n\
\n"); \n");
PyDoc_STRVAR(doc_compare,"\n\ PyDoc_STRVAR(doc_compare,"\n\
compare(other[, context]) - Compare self to other. Return a decimal value:\n\ compare(other, context=None) - Compare self to other. Return a decimal value:\n\
\n\ \n\
a or b is a NaN ==> Decimal('NaN')\n\ a or b is a NaN ==> Decimal('NaN')\n\
a < b ==> Decimal('-1')\n\ a < b ==> Decimal('-1')\n\
@ -83,16 +82,16 @@ compare(other[, context]) - Compare self to other. Return a decimal value:\n\
\n"); \n");
PyDoc_STRVAR(doc_compare_signal,"\n\ PyDoc_STRVAR(doc_compare_signal,"\n\
compare_signal(other[, context]) - Identical to compare, except that\n\ compare_signal(other, context=None) - Identical to compare, except that\n\
all NaNs signal.\n\ all NaNs signal.\n\
\n"); \n");
PyDoc_STRVAR(doc_compare_total,"\n\ PyDoc_STRVAR(doc_compare_total,"\n\
compare_total(other) - Compare two operands using their abstract representation\n\ compare_total(other, context=None) - Compare two operands using their\n\
rather than their numerical value. Similar to the compare() method, but the\n\ abstract representation rather than their numerical value. Similar to the\n\
result gives a total ordering on Decimal instances. Two Decimal instances with\n\ compare() method, but the result gives a total ordering on Decimal instances.\n\
the same numeric value but different representations compare unequal in this\n\ Two Decimal instances with the same numeric value but different representations\n\
ordering:\n\ compare unequal in this ordering:\n\
\n\ \n\
>>> Decimal('12.0').compare_total(Decimal('12'))\n\ >>> Decimal('12.0').compare_total(Decimal('12'))\n\
Decimal('-1')\n\ Decimal('-1')\n\
@ -102,13 +101,21 @@ of this function is Decimal('0') if both operands have the same representation,\
Decimal('-1') if the first operand is lower in the total order than the second,\n\ Decimal('-1') if the first operand is lower in the total order than the second,\n\
and Decimal('1') if the first operand is higher in the total order than the\n\ and Decimal('1') if the first operand is higher in the total order than the\n\
second operand. See the specification for details of the total order.\n\ second operand. See the specification for details of the total order.\n\
\n\
This operation is unaffected by context and is quiet: no flags are changed\n\
and no rounding is performed. As an exception, the C version may raise\n\
InvalidOperation if the second operand cannot be converted exactly.\n\
\n"); \n");
PyDoc_STRVAR(doc_compare_total_mag,"\n\ PyDoc_STRVAR(doc_compare_total_mag,"\n\
compare_total_mag(other) - Compare two operands using their abstract\n\ compare_total_mag(other, context=None) - Compare two operands using their\n\
representation rather than their value as in compare_total(), but\n\ abstract representation rather than their value as in compare_total(), but\n\
ignoring the sign of each operand. x.compare_total_mag(y) is\n\ ignoring the sign of each operand. x.compare_total_mag(y) is equivalent to\n\
equivalent to x.copy_abs().compare_total(y.copy_abs()).\n\ x.copy_abs().compare_total(y.copy_abs()).\n\
\n\
This operation is unaffected by context and is quiet: no flags are changed\n\
and no rounding is performed. As an exception, the C version may raise\n\
InvalidOperation if the second operand cannot be converted exactly.\n\
\n"); \n");
PyDoc_STRVAR(doc_conjugate,"\n\ PyDoc_STRVAR(doc_conjugate,"\n\
@ -117,31 +124,32 @@ conjugate() - Return self.\n\
PyDoc_STRVAR(doc_copy_abs,"\n\ PyDoc_STRVAR(doc_copy_abs,"\n\
copy_abs() - Return the absolute value of the argument. This operation\n\ copy_abs() - Return the absolute value of the argument. This operation\n\
is unaffected by the context and is quiet: no flags are changed and no\n\ is unaffected by context and is quiet: no flags are changed and no rounding\n\
rounding is performed.\n\ is performed.\n\
\n"); \n");
PyDoc_STRVAR(doc_copy_negate,"\n\ PyDoc_STRVAR(doc_copy_negate,"\n\
copy_negate() - Return the negation of the argument. This operation is\n\ copy_negate() - Return the negation of the argument. This operation is\n\
unaffected by the context and is quiet: no flags are changed and no\n\ unaffected by context and is quiet: no flags are changed and no rounding\n\
rounding is performed.\n\ is performed.\n\
\n"); \n");
PyDoc_STRVAR(doc_copy_sign,"\n\ PyDoc_STRVAR(doc_copy_sign,"\n\
copy_sign(other) - Return a copy of the first operand with the sign set\n\ copy_sign(other, context=None) - Return a copy of the first operand with\n\
to be the same as the sign of the second operand. For example:\n\ the sign set to be the same as the sign of the second operand. For example:\n\
\n\ \n\
>>> Decimal('2.3').copy_sign(Decimal('-1.5'))\n\ >>> Decimal('2.3').copy_sign(Decimal('-1.5'))\n\
Decimal('-2.3')\n\ Decimal('-2.3')\n\
\n\ \n\
This operation is unaffected by the context and is quiet: no flags are\n\ This operation is unaffected by context and is quiet: no flags are changed\n\
changed and no rounding is performed.\n\ and no rounding is performed. As an exception, the C version may raise\n\
InvalidOperation if the second operand cannot be converted exactly.\n\
\n"); \n");
PyDoc_STRVAR(doc_exp,"\n\ PyDoc_STRVAR(doc_exp,"\n\
exp([context]) - Return the value of the (natural) exponential function e**x\n\ exp(context=None) - Return the value of the (natural) exponential function\n\
at the given number. The function always uses the ROUND_HALF_EVEN mode and\n\ e**x at the given number. The function always uses the ROUND_HALF_EVEN mode\n\
the result is correctly rounded.\n\ and the result is correctly rounded.\n\
\n"); \n");
PyDoc_STRVAR(doc_from_float,"\n\ PyDoc_STRVAR(doc_from_float,"\n\
@ -161,7 +169,7 @@ Decimal.from_float(0.1) is not the same as Decimal('0.1').\n\
\n"); \n");
PyDoc_STRVAR(doc_fma,"\n\ PyDoc_STRVAR(doc_fma,"\n\
fma(other, third[, context]) - Fused multiply-add. Return self*other+third\n\ fma(other, third, context=None) - Fused multiply-add. Return self*other+third\n\
with no rounding of the intermediate product self*other.\n\ with no rounding of the intermediate product self*other.\n\
\n\ \n\
>>> Decimal(2).fma(3, 5)\n\ >>> Decimal(2).fma(3, 5)\n\
@ -191,9 +199,9 @@ False otherwise.\n\
\n"); \n");
PyDoc_STRVAR(doc_is_normal,"\n\ PyDoc_STRVAR(doc_is_normal,"\n\
is_normal([context]) - Return True if the argument is a normal finite non-zero\n\ is_normal(context=None) - Return True if the argument is a normal finite\n\
number with an adjusted exponent greater than or equal to Emin. Return False\n\ non-zero number with an adjusted exponent greater than or equal to Emin.\n\
if the argument is zero, subnormal, infinite or a NaN.\n\ Return False if the argument is zero, subnormal, infinite or a NaN.\n\
\n"); \n");
PyDoc_STRVAR(doc_is_qnan,"\n\ PyDoc_STRVAR(doc_is_qnan,"\n\
@ -210,8 +218,8 @@ is_snan() - Return True if the argument is a signaling NaN and False otherwise.\
\n"); \n");
PyDoc_STRVAR(doc_is_subnormal,"\n\ PyDoc_STRVAR(doc_is_subnormal,"\n\
is_subnormal([context]) - Return True if the argument is subnormal, and False\n\ is_subnormal(context=None) - Return True if the argument is subnormal, and\n\
otherwise. A number is subnormal if it is non-zero, finite, and has an\n\ False otherwise. A number is subnormal if it is non-zero, finite, and has an\n\
adjusted exponent less than Emin.\n\ adjusted exponent less than Emin.\n\
\n"); \n");
@ -221,94 +229,94 @@ False otherwise.\n\
\n"); \n");
PyDoc_STRVAR(doc_ln,"\n\ PyDoc_STRVAR(doc_ln,"\n\
ln([context]) - Return the natural (base e) logarithm of the operand.\n\ ln(context=None) - Return the natural (base e) logarithm of the operand.\n\
The function always uses the ROUND_HALF_EVEN mode and the result is\n\ The function always uses the ROUND_HALF_EVEN mode and the result is\n\
correctly rounded.\n\ correctly rounded.\n\
\n"); \n");
PyDoc_STRVAR(doc_log10,"\n\ PyDoc_STRVAR(doc_log10,"\n\
log10([context]) - Return the base ten logarithm of the operand.\n\ log10(context=None) - Return the base ten logarithm of the operand.\n\
The function always uses the ROUND_HALF_EVEN mode and the result is\n\ The function always uses the ROUND_HALF_EVEN mode and the result is\n\
correctly rounded.\n\ correctly rounded.\n\
\n"); \n");
PyDoc_STRVAR(doc_logb,"\n\ PyDoc_STRVAR(doc_logb,"\n\
logb([context]) - For a non-zero number, return the adjusted exponent\n\ logb(context=None) - For a non-zero number, return the adjusted exponent\n\
of the operand as a Decimal instance. If the operand is a zero, then\n\ of the operand as a Decimal instance. If the operand is a zero, then\n\
Decimal('-Infinity') is returned and the DivisionByZero condition is\n\ Decimal('-Infinity') is returned and the DivisionByZero condition is\n\
raised. If the operand is an infinity then Decimal('Infinity') is returned.\n\ raised. If the operand is an infinity then Decimal('Infinity') is returned.\n\
\n"); \n");
PyDoc_STRVAR(doc_logical_and,"\n\ PyDoc_STRVAR(doc_logical_and,"\n\
logical_and(other[, context]) - Return the digit-wise and of the two\n\ logical_and(other, context=None) - Return the digit-wise and of the two\n\
(logical) operands.\n\ (logical) operands.\n\
\n"); \n");
PyDoc_STRVAR(doc_logical_invert,"\n\ PyDoc_STRVAR(doc_logical_invert,"\n\
logical_invert([context]) - Return the digit-wise inversion of the\n\ logical_invert(context=None) - Return the digit-wise inversion of the\n\
(logical) operand.\n\ (logical) operand.\n\
\n"); \n");
PyDoc_STRVAR(doc_logical_or,"\n\ PyDoc_STRVAR(doc_logical_or,"\n\
logical_or(other[, context]) - Return the digit-wise or of the two\n\ logical_or(other, context=None) - Return the digit-wise or of the two\n\
(logical) operands.\n\ (logical) operands.\n\
\n"); \n");
PyDoc_STRVAR(doc_logical_xor,"\n\ PyDoc_STRVAR(doc_logical_xor,"\n\
logical_xor(other[, context]) - Return the digit-wise exclusive or of the\n\ logical_xor(other, context=None) - Return the digit-wise exclusive or of the\n\
two (logical) operands.\n\ two (logical) operands.\n\
\n"); \n");
PyDoc_STRVAR(doc_max,"\n\ PyDoc_STRVAR(doc_max,"\n\
max(other[, context]) - Maximum of self and other. If one operand is a quiet\n\ max(other, context=None) - Maximum of self and other. If one operand is a\n\
NaN and the other is numeric, the numeric operand is returned.\n\ quiet NaN and the other is numeric, the numeric operand is returned.\n\
\n"); \n");
PyDoc_STRVAR(doc_max_mag,"\n\ PyDoc_STRVAR(doc_max_mag,"\n\
max_mag(other[, context]) - Similar to the max() method, but the comparison is\n\ max_mag(other, context=None) - Similar to the max() method, but the\n\
done using the absolute values of the operands.\n\ comparison is done using the absolute values of the operands.\n\
\n"); \n");
PyDoc_STRVAR(doc_min,"\n\ PyDoc_STRVAR(doc_min,"\n\
min(other[, context]) - Minimum of self and other. If one operand is a quiet\n\ min(other, context=None) - Minimum of self and other. If one operand is a\n\
NaN and the other is numeric, the numeric operand is returned.\n\ quiet NaN and the other is numeric, the numeric operand is returned.\n\
\n"); \n");
PyDoc_STRVAR(doc_min_mag,"\n\ PyDoc_STRVAR(doc_min_mag,"\n\
min_mag(other[, context]) - Similar to the min() method, but the comparison is\n\ min_mag(other, context=None) - Similar to the min() method, but the\n\
done using the absolute values of the operands.\n\ comparison is done using the absolute values of the operands.\n\
\n"); \n");
PyDoc_STRVAR(doc_next_minus,"\n\ PyDoc_STRVAR(doc_next_minus,"\n\
next_minus([context]) - Return the largest number representable in the given\n\ next_minus(context=None) - Return the largest number representable in the\n\
context (or in the current default context if no context is given) that is\n\ given context (or in the current default context if no context is given) that\n\
smaller than the given operand.\n\ is smaller than the given operand.\n\
\n"); \n");
PyDoc_STRVAR(doc_next_plus,"\n\ PyDoc_STRVAR(doc_next_plus,"\n\
next_plus([context]) - Return the smallest number representable in the given\n\ next_plus(context=None) - Return the smallest number representable in the\n\
context (or in the current default context if no context is given) that is\n\ given context (or in the current default context if no context is given) that\n\
larger than the given operand.\n\ is larger than the given operand.\n\
\n"); \n");
PyDoc_STRVAR(doc_next_toward,"\n\ PyDoc_STRVAR(doc_next_toward,"\n\
next_toward(other[, context]) - If the two operands are unequal, return the\n\ next_toward(other, context=None) - If the two operands are unequal, return\n\
number closest to the first operand in the direction of the second operand.\n\ the number closest to the first operand in the direction of the second operand.\n\
If both operands are numerically equal, return a copy of the first operand\n\ If both operands are numerically equal, return a copy of the first operand\n\
with the sign set to be the same as the sign of the second operand.\n\ with the sign set to be the same as the sign of the second operand.\n\
\n"); \n");
PyDoc_STRVAR(doc_normalize,"\n\ PyDoc_STRVAR(doc_normalize,"\n\
normalize([context]) - Normalize the number by stripping the rightmost trailing\n\ normalize(context=None) - Normalize the number by stripping the rightmost\n\
zeros and converting any result equal to Decimal('0') to Decimal('0e0'). Used\n\ trailing zeros and converting any result equal to Decimal('0') to Decimal('0e0').\n\
for producing canonical values for members of an equivalence class. For example,\n\ Used for producing canonical values for members of an equivalence class. For\n\
Decimal('32.100') and Decimal('0.321000e+2') both normalize to the equivalent\n\ example, Decimal('32.100') and Decimal('0.321000e+2') both normalize to the\n\
value Decimal('32.1').\n\ equivalent value Decimal('32.1').\n\
\n"); \n");
PyDoc_STRVAR(doc_number_class,"\n\ PyDoc_STRVAR(doc_number_class,"\n\
number_class([context]) - Return a string describing the class of the operand.\n\ number_class(context=None) - Return a string describing the class of the\n\
The returned value is one of the following ten strings:\n\ operand. The returned value is one of the following ten strings:\n\
\n\ \n\
* '-Infinity', indicating that the operand is negative infinity.\n\ * '-Infinity', indicating that the operand is negative infinity.\n\
* '-Normal', indicating that the operand is a negative normal number.\n\ * '-Normal', indicating that the operand is a negative normal number.\n\
@ -324,8 +332,8 @@ The returned value is one of the following ten strings:\n\
\n"); \n");
PyDoc_STRVAR(doc_quantize,"\n\ PyDoc_STRVAR(doc_quantize,"\n\
quantize(exp[, rounding[, context]]) - Return a value equal to the first\n\ quantize(exp, rounding=None, context=None) - Return a value equal to the\n\
operand after rounding and having the exponent of the second operand.\n\ first operand after rounding and having the exponent of the second operand.\n\
\n\ \n\
>>> Decimal('1.41421356').quantize(Decimal('1.000'))\n\ >>> Decimal('1.41421356').quantize(Decimal('1.000'))\n\
Decimal('1.414')\n\ Decimal('1.414')\n\
@ -350,16 +358,18 @@ all its arithmetic. Included for compatibility with the specification.\n\
\n"); \n");
PyDoc_STRVAR(doc_remainder_near,"\n\ PyDoc_STRVAR(doc_remainder_near,"\n\
remainder_near(other[, context]) - Compute the modulo as either a positive\n\ remainder_near(other, context=None) - Return the remainder from dividing\n\
or negative value depending on which is closest to zero. For instance,\n\ self by other. This differs from self % other in that the sign of the\n\
Decimal(10).remainder_near(6) returns Decimal('-2'), which is closer to zero\n\ remainder is chosen so as to minimize its absolute value. More precisely, the\n\
than Decimal('4').\n\ return value is self - n * other where n is the integer nearest to the exact\n\
value of self / other, and if two integers are equally near then the even one\n\
is chosen.\n\
\n\ \n\
If both are equally close, the one chosen will have the same sign as self.\n\ If the result is zero then its sign will be the sign of self.\n\
\n"); \n");
PyDoc_STRVAR(doc_rotate,"\n\ PyDoc_STRVAR(doc_rotate,"\n\
rotate(other[, context]) - Return the result of rotating the digits of the\n\ rotate(other, context=None) - Return the result of rotating the digits of the\n\
first operand by an amount specified by the second operand. The second operand\n\ first operand by an amount specified by the second operand. The second operand\n\
must be an integer in the range -precision through precision. The absolute\n\ must be an integer in the range -precision through precision. The absolute\n\
value of the second operand gives the number of places to rotate. If the second\n\ value of the second operand gives the number of places to rotate. If the second\n\
@ -370,18 +380,22 @@ unchanged.\n\
\n"); \n");
PyDoc_STRVAR(doc_same_quantum,"\n\ PyDoc_STRVAR(doc_same_quantum,"\n\
same_quantum(other[, context]) - Test whether self and other have the\n\ same_quantum(other, context=None) - Test whether self and other have the\n\
same exponent or whether both are NaN.\n\ same exponent or whether both are NaN.\n\
\n\
This operation is unaffected by context and is quiet: no flags are changed\n\
and no rounding is performed. As an exception, the C version may raise\n\
InvalidOperation if the second operand cannot be converted exactly.\n\
\n"); \n");
PyDoc_STRVAR(doc_scaleb,"\n\ PyDoc_STRVAR(doc_scaleb,"\n\
scaleb(other[, context]) - Return the first operand with the exponent adjusted\n\ scaleb(other, context=None) - Return the first operand with the exponent\n\
the second. Equivalently, return the first operand multiplied by 10**other.\n\ adjusted the second. Equivalently, return the first operand multiplied by\n\
The second operand must be an integer.\n\ 10**other. The second operand must be an integer.\n\
\n"); \n");
PyDoc_STRVAR(doc_shift,"\n\ PyDoc_STRVAR(doc_shift,"\n\
shift(other[, context]) - Return the result of shifting the digits of\n\ shift(other, context=None) - Return the result of shifting the digits of\n\
the first operand by an amount specified by the second operand. The second\n\ the first operand by an amount specified by the second operand. The second\n\
operand must be an integer in the range -precision through precision. The\n\ operand must be an integer in the range -precision through precision. The\n\
absolute value of the second operand gives the number of places to shift.\n\ absolute value of the second operand gives the number of places to shift.\n\
@ -391,36 +405,40 @@ The sign and exponent of the first operand are unchanged.\n\
\n"); \n");
PyDoc_STRVAR(doc_sqrt,"\n\ PyDoc_STRVAR(doc_sqrt,"\n\
sqrt([context]) - Return the square root of the argument to full precision.\n\ sqrt(context=None) - Return the square root of the argument to full precision.\n\
The result is correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\ The result is correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\
\n"); \n");
PyDoc_STRVAR(doc_to_eng_string,"\n\ PyDoc_STRVAR(doc_to_eng_string,"\n\
to_eng_string([context]) - Convert to an engineering-type string.\n\ to_eng_string(context=None) - Convert to an engineering-type string.\n\
Engineering notation has an exponent which is a multiple of 3, so\n\ Engineering notation has an exponent which is a multiple of 3, so there\n\
there are up to 3 digits left of the decimal place. For example,\n\ are up to 3 digits left of the decimal place. For example, Decimal('123E+1')\n\
Decimal('123E+1') is converted to Decimal('1.23E+3')\n\ is converted to Decimal('1.23E+3').\n\
\n\
The value of context.capitals determines whether the exponent sign is lower\n\
or upper case. Otherwise, the context does not affect the operation.\n\
\n"); \n");
PyDoc_STRVAR(doc_to_integral,"\n\ PyDoc_STRVAR(doc_to_integral,"\n\
to_integral([rounding[, context]]) - Identical to the to_integral_value()\n\ to_integral(rounding=None, context=None) - Identical to the\n\
method. The to_integral name has been kept for compatibility with older\n\ to_integral_value() method. The to_integral() name has been kept\n\
versions.\n\ for compatibility with older versions.\n\
\n"); \n");
PyDoc_STRVAR(doc_to_integral_exact,"\n\ PyDoc_STRVAR(doc_to_integral_exact,"\n\
to_integral_exact([rounding[, context]]) - Round to the nearest integer,\n\ to_integral_exact(rounding=None, context=None) - Round to the nearest\n\
signaling Inexact or Rounded as appropriate if rounding occurs. The rounding\n\ integer, signaling Inexact or Rounded as appropriate if rounding occurs.\n\
mode is determined by the rounding parameter if given, else by the given\n\ The rounding mode is determined by the rounding parameter if given, else\n\
context. If neither parameter is given, then the rounding mode of the current\n\ by the given context. If neither parameter is given, then the rounding mode\n\
default context is used.\n\ of the current default context is used.\n\
\n"); \n");
PyDoc_STRVAR(doc_to_integral_value,"\n\ PyDoc_STRVAR(doc_to_integral_value,"\n\
to_integral_value([rounding[, context]]) - Round to the nearest integer without\n\ to_integral_value(rounding=None, context=None) - Round to the nearest\n\
signaling Inexact or Rounded. The rounding mode is determined by the rounding\n\ integer without signaling Inexact or Rounded. The rounding mode is determined\n\
parameter if given, else by the given context. If neither parameter is given,\n\ by the rounding parameter if given, else by the given context. If neither\n\
then the rounding mode of the current default context is used.\n\ parameter is given, then the rounding mode of the current default context is\n\
used.\n\
\n"); \n");

View File

@ -36,6 +36,7 @@ from copy import copy
from collections import defaultdict from collections import defaultdict
from test.support import import_fresh_module from test.support import import_fresh_module
from randdec import randfloat, all_unary, all_binary, all_ternary from randdec import randfloat, all_unary, all_binary, all_ternary
from randdec import unary_optarg, binary_optarg, ternary_optarg
from formathelper import rand_format, rand_locale from formathelper import rand_format, rand_locale
C = import_fresh_module('decimal', fresh=['_decimal']) C = import_fresh_module('decimal', fresh=['_decimal'])
@ -834,6 +835,17 @@ def test_unary(method, prec, exp_range, restricted_range, itr, stat):
except VerifyError as err: except VerifyError as err:
log(err) log(err)
if not method.startswith('__'):
for op in unary_optarg(prec, exp_range, itr):
t = TestSet(method, op)
try:
if not convert(t):
continue
callfuncs(t)
verify(t, stat)
except VerifyError as err:
log(err)
def test_binary(method, prec, exp_range, restricted_range, itr, stat): def test_binary(method, prec, exp_range, restricted_range, itr, stat):
"""Iterate a binary function through many test cases.""" """Iterate a binary function through many test cases."""
if method in BinaryRestricted: if method in BinaryRestricted:
@ -848,6 +860,17 @@ def test_binary(method, prec, exp_range, restricted_range, itr, stat):
except VerifyError as err: except VerifyError as err:
log(err) log(err)
if not method.startswith('__'):
for op in binary_optarg(prec, exp_range, itr):
t = TestSet(method, op)
try:
if not convert(t):
continue
callfuncs(t)
verify(t, stat)
except VerifyError as err:
log(err)
def test_ternary(method, prec, exp_range, restricted_range, itr, stat): def test_ternary(method, prec, exp_range, restricted_range, itr, stat):
"""Iterate a ternary function through many test cases.""" """Iterate a ternary function through many test cases."""
if method in TernaryRestricted: if method in TernaryRestricted:
@ -862,6 +885,17 @@ def test_ternary(method, prec, exp_range, restricted_range, itr, stat):
except VerifyError as err: except VerifyError as err:
log(err) log(err)
if not method.startswith('__'):
for op in ternary_optarg(prec, exp_range, itr):
t = TestSet(method, op)
try:
if not convert(t):
continue
callfuncs(t)
verify(t, stat)
except VerifyError as err:
log(err)
def test_format(method, prec, exp_range, restricted_range, itr, stat): def test_format(method, prec, exp_range, restricted_range, itr, stat):
"""Iterate the __format__ method through many test cases.""" """Iterate the __format__ method through many test cases."""
for op in all_unary(prec, exp_range, itr): for op in all_unary(prec, exp_range, itr):

View File

@ -527,6 +527,11 @@ def all_unary(prec, exp_range, itr):
for _ in range(100): for _ in range(100):
yield (randtuple(prec, exp_range),) yield (randtuple(prec, exp_range),)
def unary_optarg(prec, exp_range, itr):
for _ in range(100):
yield randdec(prec, exp_range), None
yield randdec(prec, exp_range), None, None
def all_binary(prec, exp_range, itr): def all_binary(prec, exp_range, itr):
for a, b in bin_close_to_pow10(prec, exp_range, itr): for a, b in bin_close_to_pow10(prec, exp_range, itr):
yield a, b yield a, b
@ -543,6 +548,11 @@ def all_binary(prec, exp_range, itr):
for _ in range(100): for _ in range(100):
yield randdec(prec, exp_range), randdec(prec, exp_range) yield randdec(prec, exp_range), randdec(prec, exp_range)
def binary_optarg(prec, exp_range, itr):
for _ in range(100):
yield randdec(prec, exp_range), randdec(prec, exp_range), None
yield randdec(prec, exp_range), randdec(prec, exp_range), None, None
def all_ternary(prec, exp_range, itr): def all_ternary(prec, exp_range, itr):
for a, b, c in tern_close_numbers(prec, exp_range, -exp_range, itr): for a, b, c in tern_close_numbers(prec, exp_range, -exp_range, itr):
yield a, b, c yield a, b, c
@ -557,3 +567,11 @@ def all_ternary(prec, exp_range, itr):
b = randdec(prec, 2*exp_range) b = randdec(prec, 2*exp_range)
c = randdec(prec, 2*exp_range) c = randdec(prec, 2*exp_range)
yield a, b, c yield a, b, c
def ternary_optarg(prec, exp_range, itr):
for _ in range(100):
a = randdec(prec, 2*exp_range)
b = randdec(prec, 2*exp_range)
c = randdec(prec, 2*exp_range)
yield a, b, c, None
yield a, b, c, None, None