From 54cd1969eacf27405e2fe265817ee60a8ece93ab Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 21 Aug 2016 20:03:08 +0300 Subject: [PATCH] Issue #26984: int() now always returns an instance of exact int. --- Lib/test/test_int.py | 5 ++++- Misc/NEWS | 2 ++ Objects/abstract.c | 35 +++++++++++++++++++++++------------ 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index b66c5d6709b..8847f4ce972 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -430,21 +430,24 @@ class IntTestCases(unittest.TestCase): with self.assertWarns(DeprecationWarning): n = int(bad_int) self.assertEqual(n, 1) + self.assertIs(type(n), int) bad_int = BadInt2() with self.assertWarns(DeprecationWarning): n = int(bad_int) self.assertEqual(n, 1) + self.assertIs(type(n), int) bad_int = TruncReturnsBadInt() with self.assertWarns(DeprecationWarning): n = int(bad_int) self.assertEqual(n, 1) + self.assertIs(type(n), int) good_int = TruncReturnsIntSubclass() n = int(good_int) self.assertEqual(n, 1) - self.assertIs(type(n), bool) + self.assertIs(type(n), int) n = IntSubclass(good_int) self.assertEqual(n, 1) self.assertIs(type(n), IntSubclass) diff --git a/Misc/NEWS b/Misc/NEWS index 89dcaa275e3..cefe83102be 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ What's New in Python 3.6.0 beta 1 Core and Builtins ----------------- +- Issue #26984: int() now always returns an instance of exact int. + - Issue #25604: Fix a minor bug in integer true division; this bug could potentially have caused off-by-one-ulp results on platforms with unreliable ldexp implementations. diff --git a/Objects/abstract.c b/Objects/abstract.c index dcf3eb55454..32d45757887 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1281,6 +1281,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) PyObject * PyNumber_Long(PyObject *o) { + PyObject *result; PyNumberMethods *m; PyObject *trunc_func; Py_buffer view; @@ -1296,29 +1297,39 @@ PyNumber_Long(PyObject *o) } m = o->ob_type->tp_as_number; if (m && m->nb_int) { /* This should include subclasses of int */ - return (PyObject *)_PyLong_FromNbInt(o); + result = (PyObject *)_PyLong_FromNbInt(o); + if (result != NULL && !PyLong_CheckExact(result)) { + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + } + return result; } trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__); if (trunc_func) { - PyObject *truncated = PyEval_CallObject(trunc_func, NULL); - PyObject *int_instance; + result = PyEval_CallObject(trunc_func, NULL); Py_DECREF(trunc_func); - if (truncated == NULL || PyLong_Check(truncated)) - return truncated; + 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. */ - m = truncated->ob_type->tp_as_number; + m = result->ob_type->tp_as_number; if (m == NULL || m->nb_int == NULL) { PyErr_Format( PyExc_TypeError, "__trunc__ returned non-Integral (type %.200s)", - truncated->ob_type->tp_name); - Py_DECREF(truncated); + result->ob_type->tp_name); + Py_DECREF(result); return NULL; } - int_instance = (PyObject *)_PyLong_FromNbInt(truncated); - Py_DECREF(truncated); - return int_instance; + Py_SETREF(result, (PyObject *)_PyLong_FromNbInt(result)); + if (result != NULL && !PyLong_CheckExact(result)) { + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + } + return result; } if (PyErr_Occurred()) return NULL; @@ -1340,7 +1351,7 @@ PyNumber_Long(PyObject *o) PyByteArray_GET_SIZE(o), 10); if (PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) == 0) { - PyObject *result, *bytes; + PyObject *bytes; /* Copy to NUL-terminated buffer. */ bytes = PyBytes_FromStringAndSize((const char *)view.buf, view.len);