Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions Doc/deprecations/pending-removal-in-future.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ although there is currently no date scheduled for their removal.
:keyword:`and`, :keyword:`else`, :keyword:`for`, :keyword:`if`,
:keyword:`in`, :keyword:`is` and :keyword:`or`. In a future release it
will be changed to a syntax error. (:gh:`87999`)
* Support for ``__index__()`` and ``__int__()`` method returning non-int type:
these methods will be required to return an instance of a strict subclass of
:class:`int`.
* Support for ``__float__()`` method returning a strict subclass of
:class:`float`: these methods will be required to return an instance of
:class:`float`.
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,13 @@ zipimport
Use :meth:`zipimport.zipimporter.exec_module` instead.
(Contributed by Jiahao Li in :gh:`133656`.)

Others
------

* Remove support for returning non-:class:`int` objects in
:meth:`~object.__index__` and :meth:`~object.__int__`.
(Contributed by Sergey B Kirpichev in :gh:`144584`.)


Deprecated
==========
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_capi/test_float.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ def __float__(self):
self.assertRaises(TypeError, asdouble, BadIndex())
self.assertRaises(TypeError, asdouble, BadFloat())
self.assertRaises(RuntimeError, asdouble, BadFloat3())
with self.assertWarns(DeprecationWarning):
self.assertEqual(asdouble(BadIndex2()), 1.)
self.assertRaises(TypeError, asdouble, BadIndex2())
with self.assertWarns(DeprecationWarning):
self.assertEqual(asdouble(BadFloat2()), 4.25)
with warnings.catch_warnings():
Expand Down
33 changes: 11 additions & 22 deletions Lib/test/test_capi/test_getargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,7 @@ def test_b(self):
self.assertEqual(99, getargs_b(Index()))
self.assertEqual(0, getargs_b(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_b, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_b(BadIndex2()))
self.assertRaises(TypeError, getargs_b, BadIndex2())
self.assertEqual(0, getargs_b(BadIndex3()))
self.assertRaises(TypeError, getargs_b, Int())
self.assertEqual(0, getargs_b(IntSubclass()))
Expand All @@ -196,8 +195,7 @@ def test_B(self):
self.assertEqual(99, getargs_B(Index()))
self.assertEqual(0, getargs_B(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_B, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_B(BadIndex2()))
self.assertRaises(TypeError, getargs_B, BadIndex2())
self.assertEqual(0, getargs_B(BadIndex3()))
self.assertRaises(TypeError, getargs_B, Int())
self.assertEqual(0, getargs_B(IntSubclass()))
Expand Down Expand Up @@ -233,8 +231,7 @@ def test_H(self):
self.assertEqual(99, getargs_H(Index()))
self.assertEqual(0, getargs_H(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_H, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_H(BadIndex2()))
self.assertRaises(TypeError, getargs_H, BadIndex2())
self.assertEqual(0, getargs_H(BadIndex3()))
self.assertRaises(TypeError, getargs_H, Int())
self.assertEqual(0, getargs_H(IntSubclass()))
Expand Down Expand Up @@ -265,8 +262,7 @@ def test_I(self):
self.assertEqual(99, getargs_I(Index()))
self.assertEqual(0, getargs_I(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_I, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_I(BadIndex2()))
self.assertRaises(TypeError, getargs_I, BadIndex2())
self.assertEqual(0, getargs_I(BadIndex3()))
self.assertRaises(TypeError, getargs_I, Int())
self.assertEqual(0, getargs_I(IntSubclass()))
Expand Down Expand Up @@ -297,8 +293,7 @@ def test_k(self):
self.assertEqual(99, getargs_k(Index()))
self.assertEqual(0, getargs_k(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_k, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_k(BadIndex2()))
self.assertRaises(TypeError, getargs_k, BadIndex2())
self.assertEqual(0, getargs_k(BadIndex3()))
self.assertRaises(TypeError, getargs_k, Int())
self.assertEqual(0, getargs_k(IntSubclass()))
Expand Down Expand Up @@ -330,8 +325,7 @@ def test_h(self):
self.assertEqual(99, getargs_h(Index()))
self.assertEqual(0, getargs_h(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_h, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_h(BadIndex2()))
self.assertRaises(TypeError, getargs_h, BadIndex2())
self.assertEqual(0, getargs_h(BadIndex3()))
self.assertRaises(TypeError, getargs_h, Int())
self.assertEqual(0, getargs_h(IntSubclass()))
Expand All @@ -354,8 +348,7 @@ def test_i(self):
self.assertEqual(99, getargs_i(Index()))
self.assertEqual(0, getargs_i(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_i, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_i(BadIndex2()))
self.assertRaises(TypeError, getargs_i, BadIndex2())
self.assertEqual(0, getargs_i(BadIndex3()))
self.assertRaises(TypeError, getargs_i, Int())
self.assertEqual(0, getargs_i(IntSubclass()))
Expand All @@ -378,8 +371,7 @@ def test_l(self):
self.assertEqual(99, getargs_l(Index()))
self.assertEqual(0, getargs_l(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_l, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_l(BadIndex2()))
self.assertRaises(TypeError, getargs_l, BadIndex2())
self.assertEqual(0, getargs_l(BadIndex3()))
self.assertRaises(TypeError, getargs_l, Int())
self.assertEqual(0, getargs_l(IntSubclass()))
Expand All @@ -403,8 +395,7 @@ def test_n(self):
self.assertEqual(99, getargs_n(Index()))
self.assertEqual(0, getargs_n(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_n, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_n(BadIndex2()))
self.assertRaises(TypeError, getargs_n, BadIndex2())
self.assertEqual(0, getargs_n(BadIndex3()))
self.assertRaises(TypeError, getargs_n, Int())
self.assertEqual(0, getargs_n(IntSubclass()))
Expand All @@ -431,8 +422,7 @@ def test_L(self):
self.assertEqual(99, getargs_L(Index()))
self.assertEqual(0, getargs_L(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_L, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_L(BadIndex2()))
self.assertRaises(TypeError, getargs_L, BadIndex2())
self.assertEqual(0, getargs_L(BadIndex3()))
self.assertRaises(TypeError, getargs_L, Int())
self.assertEqual(0, getargs_L(IntSubclass()))
Expand All @@ -455,8 +445,7 @@ def test_K(self):
self.assertEqual(99, getargs_K(Index()))
self.assertEqual(0, getargs_K(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_K, BadIndex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_K(BadIndex2()))
self.assertRaises(TypeError, getargs_K, BadIndex2())
self.assertEqual(0, getargs_K(BadIndex3()))
self.assertRaises(TypeError, getargs_K, Int())
self.assertEqual(0, getargs_K(IntSubclass()))
Expand Down
12 changes: 2 additions & 10 deletions Lib/test/test_capi/test_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,7 @@ def test_long(self):
self.assertEqual(long(IntLike.with_val(99)), 99)

self.assertRaises(TypeError, long, IntLike.with_val(1.0))
with warnings.catch_warnings():
warnings.simplefilter("error", DeprecationWarning)
self.assertRaises(DeprecationWarning, long, IntLike.with_val(True))
with self.assertWarns(DeprecationWarning):
self.assertEqual(long(IntLike.with_val(True)), 1)
self.assertRaises(TypeError, long, IntLike.with_val(True))
self.assertRaises(RuntimeError, long, IntLike.with_exc(RuntimeError))

self.assertRaises(TypeError, long, 1j)
Expand Down Expand Up @@ -307,11 +303,7 @@ def test_index(self):

self.assertEqual(index(11), 11)

with warnings.catch_warnings():
warnings.simplefilter("error", DeprecationWarning)
self.assertRaises(DeprecationWarning, index, IndexLike.with_val(True))
with self.assertWarns(DeprecationWarning):
self.assertEqual(index(IndexLike.with_val(True)), 1)
self.assertRaises(TypeError, index, IndexLike.with_val(True))
self.assertRaises(TypeError, index, IndexLike.with_val(1.0))
self.assertRaises(RuntimeError, index, IndexLike.with_exc(RuntimeError))

Expand Down
4 changes: 1 addition & 3 deletions Lib/test/test_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ def __index__(self):
return True

bad_int = BadInt()
with self.assertWarns(DeprecationWarning):
n = operator.index(bad_int)
self.assertEqual(n, 1)
self.assertRaises(TypeError, operator.index, bad_int)

bad_int = BadInt2()
n = operator.index(bad_int)
Expand Down
18 changes: 6 additions & 12 deletions Lib/test/test_int.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,27 +456,21 @@ def __int__(self):
return True

bad_int = BadIndex()
with self.assertWarns(DeprecationWarning):
n = int(bad_int)
self.assertEqual(n, 1)
self.assertIs(type(n), int)
with self.assertRaises(TypeError):
int(bad_int)

bad_int = BadIndex2()
n = int(bad_int)
self.assertEqual(n, 0)
self.assertIs(type(n), int)

bad_int = BadInt()
with self.assertWarns(DeprecationWarning):
n = int(bad_int)
self.assertEqual(n, 1)
self.assertIs(type(n), int)
with self.assertRaises(TypeError):
int(bad_int)

bad_int = BadInt2()
with self.assertWarns(DeprecationWarning):
n = int(bad_int)
self.assertEqual(n, 1)
self.assertIs(type(n), int)
with self.assertRaises(TypeError):
int(bad_int)

def test_error_message(self):
def check(s, base=None):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Remove support for returning non-:class:`int` objects in
:meth:`~object.__index__` and :meth:`~object.__int__`.
47 changes: 10 additions & 37 deletions Objects/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -1428,24 +1428,11 @@ _PyNumber_Index(PyObject *item)
if (!result || PyLong_CheckExact(result)) {
return result;
}

if (!PyLong_Check(result)) {
PyErr_Format(PyExc_TypeError,
"%T.__index__() must return an int, not %T",
item, result);
Py_DECREF(result);
return NULL;
}
/* Issue #17576: warn if 'result' not of exact type int. */
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"%T.__index__() must return an int, not %T. "
"The ability to return an instance of a strict subclass of int "
"is deprecated, and may be removed in a future version of Python.",
item, result)) {
Py_DECREF(result);
return NULL;
}
return result;
PyErr_Format(PyExc_TypeError,
"%T.__index__() must return an int, not %T",
item, result);
Py_DECREF(result);
return NULL;
}

/* Return an exact Python int from the object item.
Expand Down Expand Up @@ -1538,25 +1525,11 @@ PyNumber_Long(PyObject *o)
if (!result || PyLong_CheckExact(result)) {
return result;
}

if (!PyLong_Check(result)) {
PyErr_Format(PyExc_TypeError,
"%T.__int__() must return an int, not %T",
o, result);
Py_DECREF(result);
return NULL;
}
/* Issue #17576: warn if 'result' not of exact type int. */
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"%T.__int__() must return an int, not %T. "
"The ability to return an instance of a strict subclass of int "
"is deprecated, and may be removed in a future version of Python.",
o, result)) {
Py_DECREF(result);
return NULL;
}
Py_SETREF(result, _PyLong_Copy((PyLongObject *)result));
return result;
PyErr_Format(PyExc_TypeError,
"%T.__int__() must return an int, not %T",
o, result);
Py_DECREF(result);
return NULL;
}
if (m && m->nb_index) {
return PyNumber_Index(o);
Expand Down
Loading