Skip to content

Commit b4bd1e1

Browse files
authored
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.
1 parent 7ffe7ba commit b4bd1e1

File tree

8 files changed

+40
-11
lines changed

8 files changed

+40
-11
lines changed

Doc/library/functions.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,9 @@ are always available. They are listed here in alphabetical order.
891891
.. versionchanged:: 3.8
892892
Falls back to :meth:`__index__` if :meth:`__int__` is not defined.
893893

894+
.. versionchanged:: 3.11
895+
The delegation to :meth:`__trunc__` is deprecated.
896+
894897

895898
.. function:: isinstance(object, classinfo)
896899

Doc/reference/datamodel.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,6 +2760,9 @@ left undefined.
27602760
The built-in function :func:`int` falls back to :meth:`__trunc__` if neither
27612761
:meth:`__int__` nor :meth:`__index__` is defined.
27622762

2763+
.. versionchanged:: 3.11
2764+
The delegation of :func:`int` to :meth:`__trunc__` is deprecated.
2765+
27632766

27642767
.. _context-managers:
27652768

Doc/whatsnew/3.11.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,11 @@ Deprecated
458458
as deprecated, its docstring is now corrected).
459459
(Contributed by Hugo van Kemenade in :issue:`45837`.)
460460

461+
* The delegation of :func:`int` to :meth:`__trunc__` is now deprecated. Calling
462+
``int(a)`` when ``type(a)`` implements :meth:`__trunc__` but not
463+
:meth:`__int__` or :meth:`__index__` now raises a :exc:`DeprecationWarning`.
464+
(Contributed by Zackery Spytz in :issue:`44977`.)
465+
461466
* The following have been deprecated in :mod:`configparser` since Python 3.2.
462467
Their deprecation warnings have now been updated to note they will removed in
463468
Python 3.12:
@@ -468,6 +473,7 @@ Deprecated
468473

469474
(Contributed by Hugo van Kemenade in :issue:`45173`.)
470475

476+
471477
Removed
472478
=======
473479

Lib/test/test_descr.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2061,7 +2061,6 @@ def format_impl(self, spec):
20612061
("__format__", format, format_impl, set(), {}),
20622062
("__floor__", math.floor, zero, set(), {}),
20632063
("__trunc__", math.trunc, zero, set(), {}),
2064-
("__trunc__", int, zero, set(), {}),
20652064
("__ceil__", math.ceil, zero, set(), {}),
20662065
("__dir__", dir, empty_seq, set(), {}),
20672066
("__round__", round, zero, set(), {}),

Lib/test/test_int.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,14 @@ def __trunc__(self):
369369
class JustTrunc(base):
370370
def __trunc__(self):
371371
return 42
372-
self.assertEqual(int(JustTrunc()), 42)
372+
with self.assertWarns(DeprecationWarning):
373+
self.assertEqual(int(JustTrunc()), 42)
373374

374375
class ExceptionalTrunc(base):
375376
def __trunc__(self):
376377
1 / 0
377-
with self.assertRaises(ZeroDivisionError):
378+
with self.assertRaises(ZeroDivisionError), \
379+
self.assertWarns(DeprecationWarning):
378380
int(ExceptionalTrunc())
379381

380382
for trunc_result_base in (object, Classic):
@@ -385,7 +387,8 @@ def __index__(self):
385387
class TruncReturnsNonInt(base):
386388
def __trunc__(self):
387389
return Index()
388-
self.assertEqual(int(TruncReturnsNonInt()), 42)
390+
with self.assertWarns(DeprecationWarning):
391+
self.assertEqual(int(TruncReturnsNonInt()), 42)
389392

390393
class Intable(trunc_result_base):
391394
def __int__(self):
@@ -394,7 +397,8 @@ def __int__(self):
394397
class TruncReturnsNonIndex(base):
395398
def __trunc__(self):
396399
return Intable()
397-
self.assertEqual(int(TruncReturnsNonInt()), 42)
400+
with self.assertWarns(DeprecationWarning):
401+
self.assertEqual(int(TruncReturnsNonInt()), 42)
398402

399403
class NonIntegral(trunc_result_base):
400404
def __trunc__(self):
@@ -405,7 +409,8 @@ class TruncReturnsNonIntegral(base):
405409
def __trunc__(self):
406410
return NonIntegral()
407411
try:
408-
int(TruncReturnsNonIntegral())
412+
with self.assertWarns(DeprecationWarning):
413+
int(TruncReturnsNonIntegral())
409414
except TypeError as e:
410415
self.assertEqual(str(e),
411416
"__trunc__ returned non-Integral"
@@ -423,7 +428,8 @@ class TruncReturnsBadInt(base):
423428
def __trunc__(self):
424429
return BadInt()
425430

426-
with self.assertRaises(TypeError):
431+
with self.assertRaises(TypeError), \
432+
self.assertWarns(DeprecationWarning):
427433
int(TruncReturnsBadInt())
428434

429435
def test_int_subclass_with_index(self):
@@ -517,13 +523,16 @@ def __trunc__(self):
517523
self.assertIs(type(n), int)
518524

519525
bad_int = TruncReturnsBadInt()
520-
self.assertRaises(TypeError, int, bad_int)
526+
with self.assertWarns(DeprecationWarning):
527+
self.assertRaises(TypeError, int, bad_int)
521528

522529
good_int = TruncReturnsIntSubclass()
523-
n = int(good_int)
530+
with self.assertWarns(DeprecationWarning):
531+
n = int(good_int)
524532
self.assertEqual(n, 1)
525533
self.assertIs(type(n), int)
526-
n = IntSubclass(good_int)
534+
with self.assertWarns(DeprecationWarning):
535+
n = IntSubclass(good_int)
527536
self.assertEqual(n, 1)
528537
self.assertIs(type(n), IntSubclass)
529538

Lib/test/test_long.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ def __long__(self):
392392
return 42
393393
def __trunc__(self):
394394
return 1729
395-
self.assertEqual(int(LongTrunc()), 1729)
395+
with self.assertWarns(DeprecationWarning):
396+
self.assertEqual(int(LongTrunc()), 1729)
396397

397398
def check_float_conversion(self, n):
398399
# Check that int -> float conversion behaviour matches
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The delegation of :func:`int` to :meth:`__trunc__` is now deprecated.
2+
Calling ``int(a)`` when ``type(a)`` implements :meth:`__trunc__` but not
3+
:meth:`__int__` or :meth:`__index__` now raises a :exc:`DeprecationWarning`.

Objects/abstract.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,11 @@ PyNumber_Long(PyObject *o)
15641564
}
15651565
trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
15661566
if (trunc_func) {
1567+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
1568+
"The delegation of int() to __trunc__ is deprecated.", 1)) {
1569+
Py_DECREF(trunc_func);
1570+
return NULL;
1571+
}
15671572
result = _PyObject_CallNoArgs(trunc_func);
15681573
Py_DECREF(trunc_func);
15691574
if (result == NULL || PyLong_CheckExact(result)) {

0 commit comments

Comments
 (0)