From 4e0ce820586e93cfcefb16c2a3df8eaefc54cbca Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Wed, 7 Oct 2020 16:43:44 -0700 Subject: [PATCH] Revert "bpo-26680: Incorporate is_integer in all built-in and standard library numeric types (GH-6121)" (GH-22584) This reverts commit 58a7da9e125422323f79c4ee95ac5549989d8162. --- Doc/library/decimal.rst | 14 ------------ Doc/library/numbers.rst | 26 ++++++--------------- Doc/library/stdtypes.rst | 14 ++++++++---- Lib/_pydecimal.py | 25 --------------------- Lib/numbers.py | 21 +---------------- Lib/test/decimaltestdata/extra.decTest | 18 --------------- Lib/test/test_bool.py | 5 ----- Lib/test/test_decimal.py | 24 -------------------- Lib/test/test_fractions.py | 11 --------- Lib/test/test_long.py | 4 ---- Lib/test/test_numeric_tower.py | 31 -------------------------- Misc/ACKS | 1 - Modules/_decimal/_decimal.c | 6 ++--- Modules/_decimal/docstrings.h | 13 +++-------- Objects/clinic/longobject.c.h | 20 +---------------- Objects/longobject.c | 14 ------------ 16 files changed, 24 insertions(+), 223 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 7a649730595..e194649e30d 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -621,13 +621,6 @@ Decimal objects Return :const:`True` if the argument is either positive or negative infinity and :const:`False` otherwise. - .. method:: is_integer() - - Return :const:`True` if the argument is a finite integral value and - :const:`False` otherwise. - - .. versionadded:: 3.10 - .. method:: is_nan() Return :const:`True` if the argument is a (quiet or signaling) NaN and @@ -1222,13 +1215,6 @@ In addition to the three supplied contexts, new contexts can be created with the Returns ``True`` if *x* is infinite; otherwise returns ``False``. - .. method:: is_integer(x) - - Returns ``True`` if *x* is finite and integral; otherwise - returns ``False``. - - .. versionadded:: 3.10 - .. method:: is_nan(x) Returns ``True`` if *x* is a qNaN or sNaN; otherwise returns ``False``. diff --git a/Doc/library/numbers.rst b/Doc/library/numbers.rst index 5d49f5eb96b..1b594952ead 100644 --- a/Doc/library/numbers.rst +++ b/Doc/library/numbers.rst @@ -49,30 +49,19 @@ The numeric tower numbers. In short, those are: a conversion to :class:`float`, :func:`math.trunc`, - :func:`round`, :func:`math.floor`, :func:`math.ceil`, :func:`divmod`, - :func:`~Real.is_integer`, ``//``, ``%``, ``<``, ``<=``, ``>``, and ``>=``. + :func:`round`, :func:`math.floor`, :func:`math.ceil`, :func:`divmod`, ``//``, + ``%``, ``<``, ``<=``, ``>``, and ``>=``. Real also provides defaults for :func:`complex`, :attr:`~Complex.real`, :attr:`~Complex.imag`, and :meth:`~Complex.conjugate`. - .. method:: is_integer() - - Returns :const:`True` if this number has a finite and integral value, - otherwise :const:`False`. This is a default implementation which - relies on successful conversion to :class:`int`. It may be overridden - in subclasses (such as it is in :class:`float`) for better performance, - or to handle special values such as NaN which are not - convertible to :class:`int`. - - .. versionadded:: 3.10 - .. class:: Rational Subtypes :class:`Real` and adds :attr:`~Rational.numerator` and :attr:`~Rational.denominator` properties, which - should be in lowest terms. With these, it provides defaults for - :func:`float` and :func:`~Real.is_integer`. + should be in lowest terms. With these, it provides a default for + :func:`float`. .. attribute:: numerator @@ -86,10 +75,9 @@ The numeric tower .. class:: Integral Subtypes :class:`Rational` and adds a conversion to :class:`int`. Provides - defaults for :func:`float`, :attr:`~Rational.numerator`, - :attr:`~Rational.denominator`, and :func:`~Real.is_integer`. Adds abstract - methods for ``**`` and bit-string operations: ``<<``, ``>>``, ``&``, ``^``, - ``|``, ``~``. + defaults for :func:`float`, :attr:`~Rational.numerator`, and + :attr:`~Rational.denominator`. Adds abstract methods for ``**`` and + bit-string operations: ``<<``, ``>>``, ``&``, ``^``, ``|``, ``~``. Notes for type implementors diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 04dfea276d2..5c6acc66bb4 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -310,10 +310,6 @@ the operations, see :ref:`operator-summary`): +---------------------+---------------------------------+---------+--------------------+ | ``x ** y`` | *x* to the power *y* | \(5) | | +---------------------+---------------------------------+---------+--------------------+ -| ``x.is_integer()`` | ``True`` if *x* has a finite | | :func:`~numbers\ | -| | and integral value, otherwise | | .Real.is_integer` | -| | ``False``. | | | -+---------------------+---------------------------------+---------+--------------------+ .. index:: triple: operations on; numeric; types @@ -587,6 +583,16 @@ class`. float also has the following additional methods. :exc:`OverflowError` on infinities and a :exc:`ValueError` on NaNs. +.. method:: float.is_integer() + + Return ``True`` if the float instance is finite with integral + value, and ``False`` otherwise:: + + >>> (-2.0).is_integer() + True + >>> (3.2).is_integer() + False + Two methods support conversion to and from hexadecimal strings. Since Python's floats are stored internally as binary numbers, converting a float to or from a diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py index 8c0ef570922..ab989e5206a 100644 --- a/Lib/_pydecimal.py +++ b/Lib/_pydecimal.py @@ -3164,12 +3164,6 @@ class Decimal(object): """Return True if self is a zero; otherwise return False.""" return not self._is_special and self._int == '0' - def is_integer(self): - """Return True is self is finite and integral; otherwise False.""" - if self._is_special: - return False - return self.to_integral_value(rounding=ROUND_FLOOR) == self - def _ln_exp_bound(self): """Compute a lower bound for the adjusted exponent of self.ln(). In other words, compute r such that self.ln() >= 10**r. Assumes @@ -4665,25 +4659,6 @@ class Context(object): a = _convert_other(a, raiseit=True) return a.is_zero() - def is_integer(self, a): - """Return True if the operand is integral; otherwise return False. - - >>> ExtendedContext.is_integer(Decimal('0')) - True - >>> ExtendedContext.is_integer(Decimal('2.50')) - False - >>> ExtendedContext.is_integer(Decimal('-0E+2')) - True - >>> ExtendedContext.is_integer(Decimal('-0.5')) - False - >>> ExtendedContext.is_integer(Decimal('NaN')) - False - >>> ExtendedContext.is_integer(10) - True - """ - a = _convert_other(a, raiseit=True) - return a.is_integer() - def ln(self, a): """Returns the natural (base e) logarithm of the operand. diff --git a/Lib/numbers.py b/Lib/numbers.py index 0634f62ff12..ed815ef41eb 100644 --- a/Lib/numbers.py +++ b/Lib/numbers.py @@ -148,7 +148,7 @@ class Real(Complex): """To Complex, Real adds the operations that work on real numbers. In short, those are: a conversion to float, trunc(), divmod, - is_integer, %, <, <=, >, and >=. + %, <, <=, >, and >=. Real also provides defaults for the derived operations. """ @@ -242,17 +242,6 @@ class Real(Complex): """self <= other""" raise NotImplementedError - def is_integer(self): - """Return True if the Real is integral; otherwise return False. - - This default implementation can be overridden in subclasses - for performance reasons or to deal with values such as NaN, - which would otherwise cause an exception to be raised. - """ - # Although __int__ is not defined at this level, the int - # constructor falls back to __trunc__, which we do have. - return self == int(self) - # Concrete implementations of Complex abstract methods. def __complex__(self): """complex(self) == complex(float(self), 0)""" @@ -301,10 +290,6 @@ class Rational(Real): """ return self.numerator / self.denominator - def is_integer(self): - """Return True if the Rational is integral; otherwise return False.""" - return self.denominator == 1 - class Integral(Rational): """Integral adds a conversion to int and the bit-string operations.""" @@ -401,8 +386,4 @@ class Integral(Rational): """Integers have a denominator of 1.""" return 1 - def is_integer(self): - """Return True; all Integrals represent an integral value.""" - return True - Integral.register(int) diff --git a/Lib/test/decimaltestdata/extra.decTest b/Lib/test/decimaltestdata/extra.decTest index 2f0719ed223..b630d8e3f9d 100644 --- a/Lib/test/decimaltestdata/extra.decTest +++ b/Lib/test/decimaltestdata/extra.decTest @@ -2346,24 +2346,6 @@ bool2096 iszero sNaN -> 0 bool2097 iszero -sNaN -> 0 bool2098 iszero sNaN123 -> 0 bool2099 iszero -sNaN123 -> 0 -bool2100 is_integer -1.0 -> 1 -bool2101 is_integer 0.0 -> 1 -bool2102 is_integer 1.0 -> 1 -bool2103 is_integer 42 -> 1 -bool2104 is_integer 1e2 -> 1 -bool2105 is_integer 1.5 -> 0 -bool2106 is_integer 1e-2 -> 0 -bool2107 is_integer NaN -> 0 -bool2109 is_integer -NaN -> 0 -bool2110 is_integer NaN123 -> 0 -bool2111 is_integer -NaN123 -> 0 -bool2112 is_integer sNaN -> 0 -bool2113 is_integer -sNaN -> 0 -bool2114 is_integer sNaN123 -> 0 -bool2115 is_integer -sNaN123 -> 0 -bool2116 is_integer Infinity -> 0 -bool2117 is_integer -Infinity -> 0 - ------------------------------------------------------------------------ -- The following tests (pwmx0 through pwmx440) are for the -- diff --git a/Lib/test/test_bool.py b/Lib/test/test_bool.py index bc201e10ff2..7b3a3859e08 100644 --- a/Lib/test/test_bool.py +++ b/Lib/test/test_bool.py @@ -354,11 +354,6 @@ class BoolTest(unittest.TestCase): self.assertIs(type(False.real), int) self.assertIs(type(False.imag), int) - def test_always_is_integer(self): - # Issue #26680: Incorporating number.is_integer into bool - self.assertTrue(all(b.is_integer() for b in (False, True))) - - def test_main(): support.run_unittest(BoolTest) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index efb41fd4650..dbd58e8a651 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -276,7 +276,6 @@ class IBMTestCases(unittest.TestCase): 'is_snan', 'is_subnormal', 'is_zero', - 'is_integer', 'same_quantum') def read_unlimited(self, v, context): @@ -2727,7 +2726,6 @@ class PythonAPItests(unittest.TestCase): self.assertRaises(TypeError, D(1).is_snan, context=xc) self.assertRaises(TypeError, D(1).is_signed, context=xc) self.assertRaises(TypeError, D(1).is_zero, context=xc) - self.assertRaises(TypeError, D(1).is_integer, context=xc) self.assertFalse(D("0.01").is_normal(context=xc)) self.assertTrue(D("0.01").is_subnormal(context=xc)) @@ -3199,15 +3197,6 @@ class ContextAPItests(unittest.TestCase): self.assertEqual(c.is_zero(10), d) self.assertRaises(TypeError, c.is_zero, '10') - def test_is_integer(self): - Decimal = self.decimal.Decimal - Context = self.decimal.Context - - c = Context() - b = c.is_integer(Decimal(10)) - self.assertEqual(c.is_integer(10), b) - self.assertRaises(TypeError, c.is_integer, '10') - def test_ln(self): Decimal = self.decimal.Decimal Context = self.decimal.Context @@ -4371,19 +4360,6 @@ class Coverage(unittest.TestCase): self.assertTrue(Decimal("-1").is_signed()) self.assertTrue(Decimal("0").is_zero()) self.assertTrue(Decimal("0").is_zero()) - self.assertTrue(Decimal("-1").is_integer()) - self.assertTrue(Decimal("0").is_integer()) - self.assertTrue(Decimal("1").is_integer()) - self.assertTrue(Decimal("42").is_integer()) - self.assertTrue(Decimal("1e2").is_integer()) - self.assertFalse(Decimal("1.5").is_integer()) - self.assertFalse(Decimal("1e-2").is_integer()) - self.assertFalse(Decimal("NaN").is_integer()) - self.assertFalse(Decimal("-NaN").is_integer()) - self.assertFalse(Decimal("sNaN").is_integer()) - self.assertFalse(Decimal("-sNaN").is_integer()) - self.assertFalse(Decimal("Inf").is_integer()) - self.assertFalse(Decimal("-Inf").is_integer()) # Copy with localcontext() as c: diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 811b58fd8f5..0845f7921c3 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -724,17 +724,6 @@ class FractionTest(unittest.TestCase): self.assertEqual(type(f.numerator), myint) self.assertEqual(type(f.denominator), myint) - def test_is_integer(self): - # Issue #26680: Incorporating number.is_integer into Fraction - self.assertTrue(F(-1, 1).is_integer()) - self.assertTrue(F(0, 1).is_integer()) - self.assertTrue(F(1, 1).is_integer()) - self.assertTrue(F(42, 1).is_integer()) - self.assertTrue(F(2, 2).is_integer()) - self.assertTrue(F(8, 4).is_integer()) - self.assertFalse(F(1, 2).is_integer()) - self.assertFalse(F(1, 3).is_integer()) - self.assertFalse(F(2, 3).is_integer()) if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index 669826c0fa3..c97842b5bfd 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1381,10 +1381,6 @@ class LongTest(unittest.TestCase): self.assertEqual(type(numerator), int) self.assertEqual(type(denominator), int) - def test_int_always_is_integer(self): - # Issue #26680: Incorporating number.is_integer into int - self.assertTrue(all(x.is_integer() for x in (-1, 0, 1, 42))) - if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_numeric_tower.py b/Lib/test/test_numeric_tower.py index 4e46aacad82..c54dedb8b79 100644 --- a/Lib/test/test_numeric_tower.py +++ b/Lib/test/test_numeric_tower.py @@ -6,7 +6,6 @@ import math import sys import operator -from numbers import Real, Rational, Integral from decimal import Decimal as D from fractions import Fraction as F @@ -199,35 +198,5 @@ class ComparisonTest(unittest.TestCase): self.assertRaises(TypeError, op, v, z) -class IsIntegerTest(unittest.TestCase): - - def test_real_is_integer(self): - self.assertTrue(Real.is_integer(-1.0)) - self.assertTrue(Real.is_integer(0.0)) - self.assertTrue(Real.is_integer(1.0)) - self.assertTrue(Real.is_integer(42.0)) - - self.assertFalse(Real.is_integer(-0.5)) - self.assertFalse(Real.is_integer(4.2)) - - def test_rational_is_integer(self): - self.assertTrue(Rational.is_integer(F(-1, 1))) - self.assertTrue(Rational.is_integer(F(0, 1))) - self.assertTrue(Rational.is_integer(F(1, 1))) - self.assertTrue(Rational.is_integer(F(42, 1))) - self.assertTrue(Rational.is_integer(F(2, 2))) - self.assertTrue(Rational.is_integer(F(8, 4))) - - self.assertFalse(Rational.is_integer(F(1, 2))) - self.assertFalse(Rational.is_integer(F(1, 3))) - self.assertFalse(Rational.is_integer(F(2, 3))) - - def test_integral_is_integer(self): - self.assertTrue(Integral.is_integer(-1)) - self.assertTrue(Integral.is_integer(0)) - self.assertTrue(Integral.is_integer(1)) - self.assertTrue(Integral.is_integer(1729)) - - if __name__ == '__main__': unittest.main() diff --git a/Misc/ACKS b/Misc/ACKS index 7d445c57214..660b8ef7504 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1613,7 +1613,6 @@ Roman Skurikhin Ville Skyttä Michael Sloan Nick Sloan -Robert Smallshire Václav Šmilauer Allen W. Smith Christopher Smith diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5200b1a48e4..e7c44acba02 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -4138,7 +4138,6 @@ Dec_BoolFunc(mpd_isqnan) Dec_BoolFunc(mpd_issnan) Dec_BoolFunc(mpd_issigned) Dec_BoolFunc(mpd_iszero) -Dec_BoolFunc(mpd_isinteger) /* Boolean functions, optional context arg */ Dec_BoolFuncVA(mpd_isnormal) @@ -4773,7 +4772,6 @@ static PyMethodDef dec_methods [] = { "is_snan", dec_mpd_issnan, METH_NOARGS, doc_is_snan }, { "is_signed", dec_mpd_issigned, METH_NOARGS, doc_is_signed }, { "is_zero", dec_mpd_iszero, METH_NOARGS, doc_is_zero }, - { "is_integer", dec_mpd_isinteger, METH_NOARGS, doc_is_integer}, /* Boolean functions, optional context arg */ { "is_normal", (PyCFunction)(void(*)(void))dec_mpd_isnormal, METH_VARARGS|METH_KEYWORDS, doc_is_normal }, @@ -5185,7 +5183,6 @@ DecCtx_BoolFunc_NO_CTX(mpd_isqnan) DecCtx_BoolFunc_NO_CTX(mpd_issigned) DecCtx_BoolFunc_NO_CTX(mpd_issnan) DecCtx_BoolFunc_NO_CTX(mpd_iszero) -DecCtx_BoolFunc_NO_CTX(mpd_isinteger) static PyObject * ctx_iscanonical(PyObject *context UNUSED, PyObject *v) @@ -5467,7 +5464,6 @@ static PyMethodDef context_methods [] = { "is_snan", ctx_mpd_issnan, METH_O, doc_ctx_is_snan }, { "is_subnormal", ctx_mpd_issubnormal, METH_O, doc_ctx_is_subnormal }, { "is_zero", ctx_mpd_iszero, METH_O, doc_ctx_is_zero }, - { "is_integer", ctx_mpd_isinteger, METH_O, doc_ctx_is_integer }, /* Functions with a single decimal argument */ { "_apply", PyDecContext_Apply, METH_O, NULL }, /* alias for apply */ @@ -6101,3 +6097,5 @@ error: return NULL; /* GCOV_NOT_REACHED */ } + + diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index bd602ab278e..f7fd6e79529 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -260,11 +260,6 @@ Return True if the argument is a (positive or negative) zero and False\n\ otherwise.\n\ \n"); -PyDoc_STRVAR(doc_is_integer, -"is_integer($self, /)\n--\n\n\ -Return True if the argument is finite and integral, otherwise False.\n\ -\n"); - PyDoc_STRVAR(doc_ln, "ln($self, /, context=None)\n--\n\n\ Return the natural (base e) logarithm of the operand. The function always\n\ @@ -690,11 +685,6 @@ PyDoc_STRVAR(doc_ctx_is_zero, Return True if x is a zero, False otherwise.\n\ \n"); -PyDoc_STRVAR(doc_ctx_is_integer, -"is_integer($self, x, /)\n--\n\n\ -+Return True if x is finite and integral, False otherwise.\n\ -+\n"); - PyDoc_STRVAR(doc_ctx_ln, "ln($self, x, /)\n--\n\n\ Return the natural (base e) logarithm of x.\n\ @@ -889,3 +879,6 @@ Convert a number to a string using scientific notation.\n\ #endif /* DOCSTRINGS_H */ + + + diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h index 16e6f7e619e..4bd47b116f8 100644 --- a/Objects/clinic/longobject.c.h +++ b/Objects/clinic/longobject.c.h @@ -121,24 +121,6 @@ exit: return return_value; } -PyDoc_STRVAR(int_is_integer__doc__, -"is_integer($self, /)\n" -"--\n" -"\n" -"Returns True for all integers."); - -#define INT_IS_INTEGER_METHODDEF \ - {"is_integer", (PyCFunction)int_is_integer, METH_NOARGS, int_is_integer__doc__}, - -static PyObject * -int_is_integer_impl(PyObject *self); - -static PyObject * -int_is_integer(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return int_is_integer_impl(self); -} - PyDoc_STRVAR(int___sizeof____doc__, "__sizeof__($self, /)\n" "--\n" @@ -385,4 +367,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=022614978e2fcdf3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ea18e51af5b53591 input=a9049054013a1b77]*/ diff --git a/Objects/longobject.c b/Objects/longobject.c index bc5b49dcf8b..92514d4154e 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5233,19 +5233,6 @@ int___round___impl(PyObject *self, PyObject *o_ndigits) return result; } -/*[clinic input] -int.is_integer - -Returns True for all integers. -[clinic start generated code]*/ - -static PyObject * -int_is_integer_impl(PyObject *self) -/*[clinic end generated code: output=90f8e794ce5430ef input=1c1a86957301d26d]*/ -{ - Py_RETURN_TRUE; -} - /*[clinic input] int.__sizeof__ -> Py_ssize_t @@ -5560,7 +5547,6 @@ static PyMethodDef long_methods[] = { {"__ceil__", long_long_meth, METH_NOARGS, "Ceiling of an Integral returns itself."}, INT___ROUND___METHODDEF - INT_IS_INTEGER_METHODDEF INT___GETNEWARGS___METHODDEF INT___FORMAT___METHODDEF INT___SIZEOF___METHODDEF