summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/functions.rst11
-rw-r--r--Doc/reference/datamodel.rst7
-rw-r--r--Doc/whatsnew/3.14.rst5
-rw-r--r--Include/internal/pycore_global_objects_fini_generated.h1
-rw-r--r--Include/internal/pycore_global_strings.h1
-rw-r--r--Include/internal/pycore_runtime_init_generated.h1
-rw-r--r--Include/internal/pycore_unicodeobject_generated.h3
-rw-r--r--Lib/test/test_int.py96
-rw-r--r--Lib/test/test_long.py9
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst2
-rw-r--r--Objects/abstract.c32
11 files changed, 16 insertions, 152 deletions
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index 7291461..4617767 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -1004,9 +1004,8 @@ are always available. They are listed here in alphabetical order.
115
If the argument defines :meth:`~object.__int__`,
- ``int(x)`` returns ``x.__int__()``. If the argument defines :meth:`~object.__index__`,
- it returns ``x.__index__()``. If the argument defines :meth:`~object.__trunc__`,
- it returns ``x.__trunc__()``.
+ ``int(x)`` returns ``x.__int__()``. If the argument defines
+ :meth:`~object.__index__`, it returns ``x.__index__()``.
For floating point numbers, this truncates towards zero.
If the argument is not a number or if *base* is given, then it must be a string,
@@ -1045,9 +1044,6 @@ are always available. They are listed here in alphabetical order.
Falls back to :meth:`~object.__index__` if :meth:`~object.__int__` is not defined.
.. versionchanged:: 3.11
- The delegation to :meth:`~object.__trunc__` is deprecated.
-
- .. versionchanged:: 3.11
:class:`int` string inputs and string representations can be limited to
help avoid denial of service attacks. A :exc:`ValueError` is raised when
the limit is exceeded while converting a string to an :class:`int` or
@@ -1055,6 +1051,9 @@ are always available. They are listed here in alphabetical order.
See the :ref:`integer string conversion length limitation
<int_max_str_digits>` documentation.
+ .. versionchanged:: 3.14
+ :func:`int` no longer delegates to the :meth:`~object.__trunc__` method.
+
.. function:: isinstance(object, classinfo)
Return ``True`` if the *object* argument is an instance of the *classinfo*
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 9110060..af4c585 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -3127,11 +3127,8 @@ left undefined.
return the value of the object truncated to an :class:`~numbers.Integral`
(typically an :class:`int`).
- 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.
+ .. versionchanged:: 3.14
+ :func:`int` no longer delegates to the :meth:`~object.__trunc__` method.
.. _context-managers:
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 45ffb28..9f471d2 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -225,6 +225,11 @@ Others
It had previously raised a :exc:`DeprecationWarning` since Python 3.9. (Contributed
by Jelle Zijlstra in :gh:`118767`.)
+* The :func:`int` built-in no longer delegates to
+ :meth:`~object.__trunc__`. Classes that want to support conversion to
+ integer must implement either :meth:`~object.__int__` or
+ :meth:`~object.__index__`. (Contributed by Mark Dickinson in :gh:`119743`.)
+
Porting to Python 3.14
======================
diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h
index a0f8fb7..b9fae11 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -732,7 +732,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__subclasscheck__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__subclasshook__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__truediv__));
- _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__trunc__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__type_params__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__typing_is_unpacked_typevartuple__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__typing_prepare_subst__));
diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h
index 57d8502..aa66b20 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -221,7 +221,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(__subclasscheck__)
STRUCT_FOR_ID(__subclasshook__)
STRUCT_FOR_ID(__truediv__)
- STRUCT_FOR_ID(__trunc__)
STRUCT_FOR_ID(__type_params__)
STRUCT_FOR_ID(__typing_is_unpacked_typevartuple__)
STRUCT_FOR_ID(__typing_prepare_subst__)
diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h
index e62ebd6..b27720e 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -730,7 +730,6 @@ extern "C" {
INIT_ID(__subclasscheck__), \
INIT_ID(__subclasshook__), \
INIT_ID(__truediv__), \
- INIT_ID(__trunc__), \
INIT_ID(__type_params__), \
INIT_ID(__typing_is_unpacked_typevartuple__), \
INIT_ID(__typing_prepare_subst__), \
diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h
index 892f580..c61c556 100644
--- a/Include/internal/pycore_unicodeobject_generated.h
+++ b/Include/internal/pycore_unicodeobject_generated.h
@@ -504,9 +504,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
string = &_Py_ID(__truediv__);
assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string);
- string = &_Py_ID(__trunc__);
- assert(_PyUnicode_CheckConsistency(string, 1));
- _PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(__type_params__);
assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string);
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
index caeccbe..ce9febd 100644
--- a/Lib/test/test_int.py
+++ b/Lib/test/test_int.py
@@ -402,68 +402,8 @@ class IntTestCases(unittest.TestCase):
class JustTrunc(base):
def __trunc__(self):
return 42
- with self.assertWarns(DeprecationWarning):
- self.assertEqual(int(JustTrunc()), 42)
-
- class ExceptionalTrunc(base):
- def __trunc__(self):
- 1 / 0
- with self.assertRaises(ZeroDivisionError), \
- self.assertWarns(DeprecationWarning):
- int(ExceptionalTrunc())
-
- for trunc_result_base in (object, Classic):
- class Index(trunc_result_base):
- def __index__(self):
- return 42
-
- class TruncReturnsNonInt(base):
- def __trunc__(self):
- return Index()
- with self.assertWarns(DeprecationWarning):
- self.assertEqual(int(TruncReturnsNonInt()), 42)
-
- class Intable(trunc_result_base):
- def __int__(self):
- return 42
-
- class TruncReturnsNonIndex(base):
- def __trunc__(self):
- return Intable()
- with self.assertWarns(DeprecationWarning):
- self.assertEqual(int(TruncReturnsNonInt()), 42)
-
- class NonIntegral(trunc_result_base):
- def __trunc__(self):
- # Check that we avoid infinite recursion.
- return NonIntegral()
-
- class TruncReturnsNonIntegral(base):
- def __trunc__(self):
- return NonIntegral()
- try:
- with self.assertWarns(DeprecationWarning):
- int(TruncReturnsNonIntegral())
- except TypeError as e:
- self.assertEqual(str(e),
- "__trunc__ returned non-Integral"
- " (type NonIntegral)")
- else:
- self.fail("Failed to raise TypeError with %s" %
- ((base, trunc_result_base),))
-
- # Regression test for bugs.python.org/issue16060.
- class BadInt(trunc_result_base):
- def __int__(self):
- return 42.0
-
- class TruncReturnsBadInt(base):
- def __trunc__(self):
- return BadInt()
-
- with self.assertRaises(TypeError), \
- self.assertWarns(DeprecationWarning):
- int(TruncReturnsBadInt())
+ with self.assertRaises(TypeError):
+ int(JustTrunc())
def test_int_subclass_with_index(self):
class MyIndex(int):
@@ -514,18 +454,6 @@ class IntTestCases(unittest.TestCase):
def __int__(self):
return True
- class TruncReturnsBadIndex:
- def __trunc__(self):
- return BadIndex()
-
- class TruncReturnsBadInt:
- def __trunc__(self):
- return BadInt()
-
- class TruncReturnsIntSubclass:
- def __trunc__(self):
- return True
-
bad_int = BadIndex()
with self.assertWarns(DeprecationWarning):
n = int(bad_int)
@@ -549,26 +477,6 @@ class IntTestCases(unittest.TestCase):
self.assertEqual(n, 1)
self.assertIs(type(n), int)
- bad_int = TruncReturnsBadIndex()
- with self.assertWarns(DeprecationWarning):
- n = int(bad_int)
- self.assertEqual(n, 1)
- self.assertIs(type(n), int)
-
- bad_int = TruncReturnsBadInt()
- with self.assertWarns(DeprecationWarning):
- self.assertRaises(TypeError, int, bad_int)
-
- good_int = TruncReturnsIntSubclass()
- with self.assertWarns(DeprecationWarning):
- n = int(good_int)
- self.assertEqual(n, 1)
- self.assertIs(type(n), int)
- with self.assertWarns(DeprecationWarning):
- n = IntSubclass(good_int)
- self.assertEqual(n, 1)
- self.assertIs(type(n), IntSubclass)
-
def test_error_message(self):
def check(s, base=None):
with self.assertRaises(ValueError,
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index 41b973d..3b2e7c4 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -386,15 +386,6 @@ class LongTest(unittest.TestCase):
return 42
self.assertRaises(TypeError, int, JustLong())
- class LongTrunc:
- # __long__ should be ignored in 3.x
- def __long__(self):
- return 42
- def __trunc__(self):
- return 1729
- with self.assertWarns(DeprecationWarning):
- self.assertEqual(int(LongTrunc()), 1729)
-
def check_float_conversion(self, n):
# Check that int -> float conversion behaviour matches
# that of the pure Python version above.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst
new file mode 100644
index 0000000..111e096
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst
@@ -0,0 +1,2 @@
+Remove the previously-deprecated delegation of :func:`int` to
+:meth:`~object.__trunc__`.
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 8357175..2008170 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1521,7 +1521,6 @@ PyNumber_Long(PyObject *o)
{
PyObject *result;
PyNumberMethods *m;
- PyObject *trunc_func;
Py_buffer view;
if (o == NULL) {
@@ -1563,37 +1562,6 @@ PyNumber_Long(PyObject *o)
if (m && m->nb_index) {
return PyNumber_Index(o);
}
- trunc_func = _PyObject_LookupSpecial(o, &_Py_ID(__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)) {
- return result;
- }
- if (PyLong_Check(result)) {
- Py_SETREF(result, _PyLong_Copy((PyLongObject *)result));
- return result;
- }
- /* __trunc__ is specified to return an Integral type,
- but int() needs to return an int. */
- if (!PyIndex_Check(result)) {
- PyErr_Format(
- PyExc_TypeError,
- "__trunc__ returned non-Integral (type %.200s)",
- Py_TYPE(result)->tp_name);
- Py_DECREF(result);
- return NULL;
- }
- Py_SETREF(result, PyNumber_Index(result));
- return result;
- }
- if (PyErr_Occurred())
- return NULL;
if (PyUnicode_Check(o))
/* The below check is done in PyLong_FromUnicodeObject(). */