diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst index a54f98d6866e9f..81f46eaf0b4d29 100644 --- a/Doc/deprecations/pending-removal-in-future.rst +++ b/Doc/deprecations/pending-removal-in-future.rst @@ -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`. diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 68fa10b0c08d17..adb777df0c2e05 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -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 ========== diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py index 8b25607b6d504f..99f631737bd765 100644 --- a/Lib/test/test_capi/test_float.py +++ b/Lib/test/test_capi/test_float.py @@ -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(): diff --git a/Lib/test/test_capi/test_getargs.py b/Lib/test/test_capi/test_getargs.py index 0b2473bac2be11..7369b1d1b1d3f4 100644 --- a/Lib/test/test_capi/test_getargs.py +++ b/Lib/test/test_capi/test_getargs.py @@ -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())) @@ -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())) @@ -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())) @@ -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())) @@ -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())) @@ -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())) @@ -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())) @@ -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())) @@ -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())) @@ -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())) @@ -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())) diff --git a/Lib/test/test_capi/test_number.py b/Lib/test/test_capi/test_number.py index bdd8868529f632..f8b9fa6214ac89 100644 --- a/Lib/test/test_capi/test_number.py +++ b/Lib/test/test_capi/test_number.py @@ -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) @@ -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)) diff --git a/Lib/test/test_index.py b/Lib/test/test_index.py index cbdc56c801a4bd..4d68dda7b0354a 100644 --- a/Lib/test/test_index.py +++ b/Lib/test/test_index.py @@ -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) diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index fa675f626cbe10..acb55b78f27132 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -456,10 +456,8 @@ 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) @@ -467,16 +465,12 @@ def __int__(self): 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): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-09-11-02-08.gh-issue-144584.nJs_21.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-09-11-02-08.gh-issue-144584.nJs_21.rst new file mode 100644 index 00000000000000..f13056cc19cb42 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-09-11-02-08.gh-issue-144584.nJs_21.rst @@ -0,0 +1,2 @@ +Remove support for returning non-:class:`int` objects in +:meth:`~object.__index__` and :meth:`~object.__int__`. diff --git a/Objects/abstract.c b/Objects/abstract.c index f2c7de3d1ef1ad..3d41b02ceb3f2c 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -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. @@ -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);