mirror of https://github.com/python/cpython
bpo-44977: Deprecate delegation of int to __trunc__ (GH-31031)
Calling int(a) when type(a) implements __trunc__ but not __int__ or __index__ now raises a DeprecationWarning.
This commit is contained in:
parent
7ffe7ba30f
commit
b4bd1e1422
|
@ -891,6 +891,9 @@ are always available. They are listed here in alphabetical order.
|
||||||
.. versionchanged:: 3.8
|
.. versionchanged:: 3.8
|
||||||
Falls back to :meth:`__index__` if :meth:`__int__` is not defined.
|
Falls back to :meth:`__index__` if :meth:`__int__` is not defined.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.11
|
||||||
|
The delegation to :meth:`__trunc__` is deprecated.
|
||||||
|
|
||||||
|
|
||||||
.. function:: isinstance(object, classinfo)
|
.. function:: isinstance(object, classinfo)
|
||||||
|
|
||||||
|
|
|
@ -2760,6 +2760,9 @@ left undefined.
|
||||||
The built-in function :func:`int` falls back to :meth:`__trunc__` if neither
|
The built-in function :func:`int` falls back to :meth:`__trunc__` if neither
|
||||||
:meth:`__int__` nor :meth:`__index__` is defined.
|
:meth:`__int__` nor :meth:`__index__` is defined.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.11
|
||||||
|
The delegation of :func:`int` to :meth:`__trunc__` is deprecated.
|
||||||
|
|
||||||
|
|
||||||
.. _context-managers:
|
.. _context-managers:
|
||||||
|
|
||||||
|
|
|
@ -458,6 +458,11 @@ Deprecated
|
||||||
as deprecated, its docstring is now corrected).
|
as deprecated, its docstring is now corrected).
|
||||||
(Contributed by Hugo van Kemenade in :issue:`45837`.)
|
(Contributed by Hugo van Kemenade in :issue:`45837`.)
|
||||||
|
|
||||||
|
* The delegation of :func:`int` to :meth:`__trunc__` is now deprecated. Calling
|
||||||
|
``int(a)`` when ``type(a)`` implements :meth:`__trunc__` but not
|
||||||
|
:meth:`__int__` or :meth:`__index__` now raises a :exc:`DeprecationWarning`.
|
||||||
|
(Contributed by Zackery Spytz in :issue:`44977`.)
|
||||||
|
|
||||||
* The following have been deprecated in :mod:`configparser` since Python 3.2.
|
* The following have been deprecated in :mod:`configparser` since Python 3.2.
|
||||||
Their deprecation warnings have now been updated to note they will removed in
|
Their deprecation warnings have now been updated to note they will removed in
|
||||||
Python 3.12:
|
Python 3.12:
|
||||||
|
@ -468,6 +473,7 @@ Deprecated
|
||||||
|
|
||||||
(Contributed by Hugo van Kemenade in :issue:`45173`.)
|
(Contributed by Hugo van Kemenade in :issue:`45173`.)
|
||||||
|
|
||||||
|
|
||||||
Removed
|
Removed
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
@ -2061,7 +2061,6 @@ order (MRO) for bases """
|
||||||
("__format__", format, format_impl, set(), {}),
|
("__format__", format, format_impl, set(), {}),
|
||||||
("__floor__", math.floor, zero, set(), {}),
|
("__floor__", math.floor, zero, set(), {}),
|
||||||
("__trunc__", math.trunc, zero, set(), {}),
|
("__trunc__", math.trunc, zero, set(), {}),
|
||||||
("__trunc__", int, zero, set(), {}),
|
|
||||||
("__ceil__", math.ceil, zero, set(), {}),
|
("__ceil__", math.ceil, zero, set(), {}),
|
||||||
("__dir__", dir, empty_seq, set(), {}),
|
("__dir__", dir, empty_seq, set(), {}),
|
||||||
("__round__", round, zero, set(), {}),
|
("__round__", round, zero, set(), {}),
|
||||||
|
|
|
@ -369,12 +369,14 @@ class IntTestCases(unittest.TestCase):
|
||||||
class JustTrunc(base):
|
class JustTrunc(base):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return 42
|
return 42
|
||||||
self.assertEqual(int(JustTrunc()), 42)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertEqual(int(JustTrunc()), 42)
|
||||||
|
|
||||||
class ExceptionalTrunc(base):
|
class ExceptionalTrunc(base):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
1 / 0
|
1 / 0
|
||||||
with self.assertRaises(ZeroDivisionError):
|
with self.assertRaises(ZeroDivisionError), \
|
||||||
|
self.assertWarns(DeprecationWarning):
|
||||||
int(ExceptionalTrunc())
|
int(ExceptionalTrunc())
|
||||||
|
|
||||||
for trunc_result_base in (object, Classic):
|
for trunc_result_base in (object, Classic):
|
||||||
|
@ -385,7 +387,8 @@ class IntTestCases(unittest.TestCase):
|
||||||
class TruncReturnsNonInt(base):
|
class TruncReturnsNonInt(base):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return Index()
|
return Index()
|
||||||
self.assertEqual(int(TruncReturnsNonInt()), 42)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertEqual(int(TruncReturnsNonInt()), 42)
|
||||||
|
|
||||||
class Intable(trunc_result_base):
|
class Intable(trunc_result_base):
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
|
@ -394,7 +397,8 @@ class IntTestCases(unittest.TestCase):
|
||||||
class TruncReturnsNonIndex(base):
|
class TruncReturnsNonIndex(base):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return Intable()
|
return Intable()
|
||||||
self.assertEqual(int(TruncReturnsNonInt()), 42)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertEqual(int(TruncReturnsNonInt()), 42)
|
||||||
|
|
||||||
class NonIntegral(trunc_result_base):
|
class NonIntegral(trunc_result_base):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
|
@ -405,7 +409,8 @@ class IntTestCases(unittest.TestCase):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return NonIntegral()
|
return NonIntegral()
|
||||||
try:
|
try:
|
||||||
int(TruncReturnsNonIntegral())
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
int(TruncReturnsNonIntegral())
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
self.assertEqual(str(e),
|
self.assertEqual(str(e),
|
||||||
"__trunc__ returned non-Integral"
|
"__trunc__ returned non-Integral"
|
||||||
|
@ -423,7 +428,8 @@ class IntTestCases(unittest.TestCase):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return BadInt()
|
return BadInt()
|
||||||
|
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError), \
|
||||||
|
self.assertWarns(DeprecationWarning):
|
||||||
int(TruncReturnsBadInt())
|
int(TruncReturnsBadInt())
|
||||||
|
|
||||||
def test_int_subclass_with_index(self):
|
def test_int_subclass_with_index(self):
|
||||||
|
@ -517,13 +523,16 @@ class IntTestCases(unittest.TestCase):
|
||||||
self.assertIs(type(n), int)
|
self.assertIs(type(n), int)
|
||||||
|
|
||||||
bad_int = TruncReturnsBadInt()
|
bad_int = TruncReturnsBadInt()
|
||||||
self.assertRaises(TypeError, int, bad_int)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertRaises(TypeError, int, bad_int)
|
||||||
|
|
||||||
good_int = TruncReturnsIntSubclass()
|
good_int = TruncReturnsIntSubclass()
|
||||||
n = int(good_int)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
n = int(good_int)
|
||||||
self.assertEqual(n, 1)
|
self.assertEqual(n, 1)
|
||||||
self.assertIs(type(n), int)
|
self.assertIs(type(n), int)
|
||||||
n = IntSubclass(good_int)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
n = IntSubclass(good_int)
|
||||||
self.assertEqual(n, 1)
|
self.assertEqual(n, 1)
|
||||||
self.assertIs(type(n), IntSubclass)
|
self.assertIs(type(n), IntSubclass)
|
||||||
|
|
||||||
|
|
|
@ -392,7 +392,8 @@ class LongTest(unittest.TestCase):
|
||||||
return 42
|
return 42
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return 1729
|
return 1729
|
||||||
self.assertEqual(int(LongTrunc()), 1729)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertEqual(int(LongTrunc()), 1729)
|
||||||
|
|
||||||
def check_float_conversion(self, n):
|
def check_float_conversion(self, n):
|
||||||
# Check that int -> float conversion behaviour matches
|
# Check that int -> float conversion behaviour matches
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
The delegation of :func:`int` to :meth:`__trunc__` is now deprecated.
|
||||||
|
Calling ``int(a)`` when ``type(a)`` implements :meth:`__trunc__` but not
|
||||||
|
:meth:`__int__` or :meth:`__index__` now raises a :exc:`DeprecationWarning`.
|
|
@ -1564,6 +1564,11 @@ PyNumber_Long(PyObject *o)
|
||||||
}
|
}
|
||||||
trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
|
trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
|
||||||
if (trunc_func) {
|
if (trunc_func) {
|
||||||
|
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
||||||
|
"The delegation of int() to __trunc__ is deprecated.", 1)) {
|
||||||
|
Py_DECREF(trunc_func);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
result = _PyObject_CallNoArgs(trunc_func);
|
result = _PyObject_CallNoArgs(trunc_func);
|
||||||
Py_DECREF(trunc_func);
|
Py_DECREF(trunc_func);
|
||||||
if (result == NULL || PyLong_CheckExact(result)) {
|
if (result == NULL || PyLong_CheckExact(result)) {
|
||||||
|
|
Loading…
Reference in New Issue