]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-44977: Deprecate delegation of int to __trunc__ (GH-31031)
authorZackery Spytz <zspytz@gmail.com>
Thu, 3 Feb 2022 09:43:25 +0000 (01:43 -0800)
committerGitHub <noreply@github.com>
Thu, 3 Feb 2022 09:43:25 +0000 (11:43 +0200)
Calling int(a) when type(a) implements __trunc__ but not __int__
or __index__ now raises a DeprecationWarning.

Doc/library/functions.rst
Doc/reference/datamodel.rst
Doc/whatsnew/3.11.rst
Lib/test/test_descr.py
Lib/test/test_int.py
Lib/test/test_long.py
Misc/NEWS.d/next/Core and Builtins/2022-01-30-18-23-08.bpo-44977.BQV_zS.rst [new file with mode: 0644]
Objects/abstract.c

index 9c061bcd8252afef47c20efcc9be518fcb84054b..eaa4d482ce3fc9100852078452c5ad729a9c6409 100644 (file)
@@ -891,6 +891,9 @@ are always available.  They are listed here in alphabetical order.
    .. versionchanged:: 3.8
       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)
 
index 48c54d729424c73b50cc4a439d1b5735b22405c2..a773b73ce32433d3d3af8c22ce3d45546045e143 100644 (file)
@@ -2760,6 +2760,9 @@ left undefined.
    The built-in function :func:`int` falls back to :meth:`__trunc__` if neither
    :meth:`__int__` nor :meth:`__index__` is defined.
 
+   .. versionchanged:: 3.11
+      The delegation of :func:`int` to :meth:`__trunc__` is deprecated.
+
 
 .. _context-managers:
 
index acb21d3ccaf17982455155c110eab1fe229a0037..18d4652fb42930d0691ebe90547264cdefb7fb60 100644 (file)
@@ -458,6 +458,11 @@ Deprecated
   as deprecated, its docstring is now corrected).
   (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.
   Their deprecation warnings have now been updated to note they will removed in
   Python 3.12:
@@ -468,6 +473,7 @@ Deprecated
 
   (Contributed by Hugo van Kemenade in :issue:`45173`.)
 
+
 Removed
 =======
 
index 791cf714d46a3e75120ef01aa261c5f14c572bc7..a0942d6a85b8125774627ee00f75866395cc98c8 100644 (file)
@@ -2061,7 +2061,6 @@ order (MRO) for bases """
             ("__format__", format, format_impl, set(), {}),
             ("__floor__", math.floor, zero, set(), {}),
             ("__trunc__", math.trunc, zero, set(), {}),
-            ("__trunc__", int, zero, set(), {}),
             ("__ceil__", math.ceil, zero, set(), {}),
             ("__dir__", dir, empty_seq, set(), {}),
             ("__round__", round, zero, set(), {}),
index d6be64e7c18a08f94d62774f1e6d7409feb6d3d8..a72699cc7506af16ccff973952ad0fa66f0355ee 100644 (file)
@@ -369,12 +369,14 @@ class IntTestCases(unittest.TestCase):
             class JustTrunc(base):
                 def __trunc__(self):
                     return 42
-            self.assertEqual(int(JustTrunc()), 42)
+            with self.assertWarns(DeprecationWarning):
+                self.assertEqual(int(JustTrunc()), 42)
 
             class ExceptionalTrunc(base):
                 def __trunc__(self):
                     1 / 0
-            with self.assertRaises(ZeroDivisionError):
+            with self.assertRaises(ZeroDivisionError), \
+                 self.assertWarns(DeprecationWarning):
                 int(ExceptionalTrunc())
 
             for trunc_result_base in (object, Classic):
@@ -385,7 +387,8 @@ class IntTestCases(unittest.TestCase):
                 class TruncReturnsNonInt(base):
                     def __trunc__(self):
                         return Index()
-                self.assertEqual(int(TruncReturnsNonInt()), 42)
+                with self.assertWarns(DeprecationWarning):
+                    self.assertEqual(int(TruncReturnsNonInt()), 42)
 
                 class Intable(trunc_result_base):
                     def __int__(self):
@@ -394,7 +397,8 @@ class IntTestCases(unittest.TestCase):
                 class TruncReturnsNonIndex(base):
                     def __trunc__(self):
                         return Intable()
-                self.assertEqual(int(TruncReturnsNonInt()), 42)
+                with self.assertWarns(DeprecationWarning):
+                    self.assertEqual(int(TruncReturnsNonInt()), 42)
 
                 class NonIntegral(trunc_result_base):
                     def __trunc__(self):
@@ -405,7 +409,8 @@ class IntTestCases(unittest.TestCase):
                     def __trunc__(self):
                         return NonIntegral()
                 try:
-                    int(TruncReturnsNonIntegral())
+                    with self.assertWarns(DeprecationWarning):
+                        int(TruncReturnsNonIntegral())
                 except TypeError as e:
                     self.assertEqual(str(e),
                                       "__trunc__ returned non-Integral"
@@ -423,7 +428,8 @@ class IntTestCases(unittest.TestCase):
                     def __trunc__(self):
                         return BadInt()
 
-                with self.assertRaises(TypeError):
+                with self.assertRaises(TypeError), \
+                     self.assertWarns(DeprecationWarning):
                     int(TruncReturnsBadInt())
 
     def test_int_subclass_with_index(self):
@@ -517,13 +523,16 @@ class IntTestCases(unittest.TestCase):
         self.assertIs(type(n), int)
 
         bad_int = TruncReturnsBadInt()
-        self.assertRaises(TypeError, int, bad_int)
+        with self.assertWarns(DeprecationWarning):
+            self.assertRaises(TypeError, int, bad_int)
 
         good_int = TruncReturnsIntSubclass()
-        n = int(good_int)
+        with self.assertWarns(DeprecationWarning):
+            n = int(good_int)
         self.assertEqual(n, 1)
         self.assertIs(type(n), int)
-        n = IntSubclass(good_int)
+        with self.assertWarns(DeprecationWarning):
+            n = IntSubclass(good_int)
         self.assertEqual(n, 1)
         self.assertIs(type(n), IntSubclass)
 
index c7dd0b274d1e372df1a1a58b6936a086c98b07fb..e68dfb4c542eae691241ef633040558c75c3bace 100644 (file)
@@ -392,7 +392,8 @@ class LongTest(unittest.TestCase):
                 return 42
             def __trunc__(self):
                 return 1729
-        self.assertEqual(int(LongTrunc()), 1729)
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(int(LongTrunc()), 1729)
 
     def check_float_conversion(self, n):
         # Check that int -> float conversion behaviour matches
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-30-18-23-08.bpo-44977.BQV_zS.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-30-18-23-08.bpo-44977.BQV_zS.rst
new file mode 100644 (file)
index 0000000..84c1191
--- /dev/null
@@ -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`.
index 6a2d5eda14079bc2c01ebf1f64801b2cb005d174..ed99fd6c5aafb3545d61909ecea318b9522c09dc 100644 (file)
@@ -1564,6 +1564,11 @@ PyNumber_Long(PyObject *o)
     }
     trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
     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);
         Py_DECREF(trunc_func);
         if (result == NULL || PyLong_CheckExact(result)) {