[Python-checkins] cpython (merge 3.3 -> default): Issue #17576: Deprecation warning emitted now when __int__() or __index__()

serhiy.storchaka python-checkins at python.org
Wed Dec 11 20:28:21 CET 2013


http://hg.python.org/cpython/rev/59fb79d0411e
changeset:   87900:59fb79d0411e
parent:      87898:e961a166dc70
parent:      87899:618cca51a27e
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Wed Dec 11 21:26:36 2013 +0200
summary:
  Issue #17576: Deprecation warning emitted now when __int__() or __index__()
return not int instance.  Introduced _PyLong_FromNbInt() and refactored
PyLong_As*() functions.

files:
  Include/longobject.h      |    6 +
  Lib/test/test_getargs2.py |   70 +++++++
  Lib/test/test_index.py    |   36 +++-
  Lib/test/test_int.py      |   76 +++++--
  Misc/NEWS                 |    3 +
  Objects/abstract.c        |   92 ++++------
  Objects/longobject.c      |  229 +++++++++++++------------
  7 files changed, 319 insertions(+), 193 deletions(-)


diff --git a/Include/longobject.h b/Include/longobject.h
--- a/Include/longobject.h
+++ b/Include/longobject.h
@@ -165,6 +165,12 @@
     unsigned char* bytes, size_t n,
     int little_endian, int is_signed);
 
+/* _PyLong_FromNbInt: Convert the given object to a PyLongObject
+   using the nb_int slot, if available.  Raise TypeError if either the
+   nb_int slot is not available or the result of the call to nb_int
+   returns something not of type int.
+*/
+PyAPI_FUNC(PyLongObject *)_PyLong_FromNbInt(PyObject *);
 
 /* _PyLong_Format: Convert the long to a string object with given base,
    appending a base prefix of 0[box] if base is 2, 8 or 16. */
diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py
--- a/Lib/test/test_getargs2.py
+++ b/Lib/test/test_getargs2.py
@@ -52,12 +52,34 @@
     def __int__(self):
         return 99
 
+class IntSubclass(int):
+    def __int__(self):
+        return 99
+
+class BadInt:
+    def __int__(self):
+        return 1.0
+
+class BadInt2:
+    def __int__(self):
+        return True
+
+class BadInt3(int):
+    def __int__(self):
+        return True
+
+
 class Unsigned_TestCase(unittest.TestCase):
     def test_b(self):
         from _testcapi import getargs_b
         # b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX)
         self.assertRaises(TypeError, getargs_b, 3.14)
         self.assertEqual(99, getargs_b(Int()))
+        self.assertEqual(0, getargs_b(IntSubclass()))
+        self.assertRaises(TypeError, getargs_b, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_b(BadInt2()))
+        self.assertEqual(0, getargs_b(BadInt3()))
 
         self.assertRaises(OverflowError, getargs_b, -1)
         self.assertEqual(0, getargs_b(0))
@@ -72,6 +94,11 @@
         # B returns 'unsigned char', no range checking
         self.assertRaises(TypeError, getargs_B, 3.14)
         self.assertEqual(99, getargs_B(Int()))
+        self.assertEqual(0, getargs_B(IntSubclass()))
+        self.assertRaises(TypeError, getargs_B, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_B(BadInt2()))
+        self.assertEqual(0, getargs_B(BadInt3()))
 
         self.assertEqual(UCHAR_MAX, getargs_B(-1))
         self.assertEqual(0, getargs_B(0))
@@ -86,6 +113,11 @@
         # H returns 'unsigned short', no range checking
         self.assertRaises(TypeError, getargs_H, 3.14)
         self.assertEqual(99, getargs_H(Int()))
+        self.assertEqual(0, getargs_H(IntSubclass()))
+        self.assertRaises(TypeError, getargs_H, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_H(BadInt2()))
+        self.assertEqual(0, getargs_H(BadInt3()))
 
         self.assertEqual(USHRT_MAX, getargs_H(-1))
         self.assertEqual(0, getargs_H(0))
@@ -101,6 +133,11 @@
         # I returns 'unsigned int', no range checking
         self.assertRaises(TypeError, getargs_I, 3.14)
         self.assertEqual(99, getargs_I(Int()))
+        self.assertEqual(0, getargs_I(IntSubclass()))
+        self.assertRaises(TypeError, getargs_I, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_I(BadInt2()))
+        self.assertEqual(0, getargs_I(BadInt3()))
 
         self.assertEqual(UINT_MAX, getargs_I(-1))
         self.assertEqual(0, getargs_I(0))
@@ -117,6 +154,10 @@
         # it does not accept float, or instances with __int__
         self.assertRaises(TypeError, getargs_k, 3.14)
         self.assertRaises(TypeError, getargs_k, Int())
+        self.assertEqual(0, getargs_k(IntSubclass()))
+        self.assertRaises(TypeError, getargs_k, BadInt())
+        self.assertRaises(TypeError, getargs_k, BadInt2())
+        self.assertEqual(0, getargs_k(BadInt3()))
 
         self.assertEqual(ULONG_MAX, getargs_k(-1))
         self.assertEqual(0, getargs_k(0))
@@ -133,6 +174,11 @@
         # h returns 'short', and does range checking (SHRT_MIN ... SHRT_MAX)
         self.assertRaises(TypeError, getargs_h, 3.14)
         self.assertEqual(99, getargs_h(Int()))
+        self.assertEqual(0, getargs_h(IntSubclass()))
+        self.assertRaises(TypeError, getargs_h, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_h(BadInt2()))
+        self.assertEqual(0, getargs_h(BadInt3()))
 
         self.assertRaises(OverflowError, getargs_h, SHRT_MIN-1)
         self.assertEqual(SHRT_MIN, getargs_h(SHRT_MIN))
@@ -147,6 +193,11 @@
         # i returns 'int', and does range checking (INT_MIN ... INT_MAX)
         self.assertRaises(TypeError, getargs_i, 3.14)
         self.assertEqual(99, getargs_i(Int()))
+        self.assertEqual(0, getargs_i(IntSubclass()))
+        self.assertRaises(TypeError, getargs_i, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_i(BadInt2()))
+        self.assertEqual(0, getargs_i(BadInt3()))
 
         self.assertRaises(OverflowError, getargs_i, INT_MIN-1)
         self.assertEqual(INT_MIN, getargs_i(INT_MIN))
@@ -161,6 +212,11 @@
         # l returns 'long', and does range checking (LONG_MIN ... LONG_MAX)
         self.assertRaises(TypeError, getargs_l, 3.14)
         self.assertEqual(99, getargs_l(Int()))
+        self.assertEqual(0, getargs_l(IntSubclass()))
+        self.assertRaises(TypeError, getargs_l, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_l(BadInt2()))
+        self.assertEqual(0, getargs_l(BadInt3()))
 
         self.assertRaises(OverflowError, getargs_l, LONG_MIN-1)
         self.assertEqual(LONG_MIN, getargs_l(LONG_MIN))
@@ -176,6 +232,10 @@
         # (PY_SSIZE_T_MIN ... PY_SSIZE_T_MAX)
         self.assertRaises(TypeError, getargs_n, 3.14)
         self.assertRaises(TypeError, getargs_n, Int())
+        self.assertEqual(0, getargs_n(IntSubclass()))
+        self.assertRaises(TypeError, getargs_n, BadInt())
+        self.assertRaises(TypeError, getargs_n, BadInt2())
+        self.assertEqual(0, getargs_n(BadInt3()))
 
         self.assertRaises(OverflowError, getargs_n, PY_SSIZE_T_MIN-1)
         self.assertEqual(PY_SSIZE_T_MIN, getargs_n(PY_SSIZE_T_MIN))
@@ -195,6 +255,11 @@
         self.assertRaises(TypeError, getargs_L, 3.14)
         self.assertRaises(TypeError, getargs_L, "Hello")
         self.assertEqual(99, getargs_L(Int()))
+        self.assertEqual(0, getargs_L(IntSubclass()))
+        self.assertRaises(TypeError, getargs_L, BadInt())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_L(BadInt2()))
+        self.assertEqual(0, getargs_L(BadInt3()))
 
         self.assertRaises(OverflowError, getargs_L, LLONG_MIN-1)
         self.assertEqual(LLONG_MIN, getargs_L(LLONG_MIN))
@@ -209,6 +274,11 @@
         # K return 'unsigned long long', no range checking
         self.assertRaises(TypeError, getargs_K, 3.14)
         self.assertRaises(TypeError, getargs_K, Int())
+        self.assertEqual(0, getargs_K(IntSubclass()))
+        self.assertRaises(TypeError, getargs_K, BadInt())
+        self.assertRaises(TypeError, getargs_K, BadInt2())
+        self.assertEqual(0, getargs_K(BadInt3()))
+
         self.assertEqual(ULLONG_MAX, getargs_K(ULLONG_MAX))
         self.assertEqual(0, getargs_K(0))
         self.assertEqual(0, getargs_K(ULLONG_MAX+1))
diff --git a/Lib/test/test_index.py b/Lib/test/test_index.py
--- a/Lib/test/test_index.py
+++ b/Lib/test/test_index.py
@@ -9,7 +9,7 @@
 
 class TrapInt(int):
     def __index__(self):
-        return self
+        return int(self)
 
 class BaseTestCase(unittest.TestCase):
     def setUp(self):
@@ -55,6 +55,40 @@
         self.assertRaises(TypeError, slice(self.o).indices, 0)
         self.assertRaises(TypeError, slice(self.n).indices, 0)
 
+    def test_int_subclass_with_index(self):
+        # __index__ should be used when computing indices, even for int
+        # subclasses.  See issue #17576.
+        class MyInt(int):
+            def __index__(self):
+                return int(self) + 1
+
+        my_int = MyInt(7)
+        direct_index = my_int.__index__()
+        operator_index = operator.index(my_int)
+        self.assertEqual(direct_index, 8)
+        self.assertEqual(operator_index, 7)
+        # Both results should be of exact type int.
+        self.assertIs(type(direct_index), int)
+        #self.assertIs(type(operator_index), int)
+
+    def test_index_returns_int_subclass(self):
+        class BadInt:
+            def __index__(self):
+                return True
+
+        class BadInt2(int):
+            def __index__(self):
+                return True
+
+        bad_int = BadInt()
+        with self.assertWarns(DeprecationWarning):
+            n = operator.index(bad_int)
+        self.assertEqual(n, 1)
+
+        bad_int = BadInt2()
+        n = operator.index(bad_int)
+        self.assertEqual(n, 0)
+
 
 class SeqTestCase:
     # This test case isn't run directly. It just defines common tests
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
--- a/Lib/test/test_int.py
+++ b/Lib/test/test_int.py
@@ -304,32 +304,7 @@
             def __int__(self):
                 return 42
 
-        class Foo1(object):
-            def __int__(self):
-                return 42
-
-        class Foo2(int):
-            def __int__(self):
-                return 42
-
-        class Foo3(int):
-            def __int__(self):
-                return self
-
-        class Foo4(int):
-            def __int__(self):
-                return 42
-
-        class Foo5(int):
-            def __int__(self):
-                return 42.
-
         self.assertEqual(int(Foo0()), 42)
-        self.assertEqual(int(Foo1()), 42)
-        self.assertEqual(int(Foo2()), 42)
-        self.assertEqual(int(Foo3()), 0)
-        self.assertEqual(int(Foo4()), 42)
-        self.assertRaises(TypeError, int, Foo5())
 
         class Classic:
             pass
@@ -392,6 +367,57 @@
                 with self.assertRaises(TypeError):
                     int(TruncReturnsBadInt())
 
+    def test_int_subclass_with_int(self):
+        class MyInt(int):
+            def __int__(self):
+                return 42
+
+        class BadInt(int):
+            def __int__(self):
+                return 42.0
+
+        my_int = MyInt(7)
+        self.assertEqual(my_int, 7)
+        self.assertEqual(int(my_int), 42)
+
+        self.assertRaises(TypeError, int, BadInt())
+
+    def test_int_returns_int_subclass(self):
+        class BadInt:
+            def __int__(self):
+                return True
+
+        class BadInt2(int):
+            def __int__(self):
+                return True
+
+        class TruncReturnsBadInt:
+            def __trunc__(self):
+                return BadInt()
+
+        class TruncReturnsIntSubclass:
+            def __trunc__(self):
+                return True
+
+        bad_int = BadInt()
+        with self.assertWarns(DeprecationWarning):
+            n = int(bad_int)
+        self.assertEqual(n, 1)
+
+        bad_int = BadInt2()
+        with self.assertWarns(DeprecationWarning):
+            n = int(bad_int)
+        self.assertEqual(n, 1)
+
+        bad_int = TruncReturnsBadInt()
+        with self.assertWarns(DeprecationWarning):
+            n = int(bad_int)
+        self.assertEqual(n, 1)
+
+        good_int = TruncReturnsIntSubclass()
+        n = int(good_int)
+        self.assertEqual(n, 1)
+
     def test_error_message(self):
         def check(s, base=None):
             with self.assertRaises(ValueError,
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #17576: Deprecation warning emitted now when __int__() or __index__()
+  return not int instance.
+
 - Issue #19932: Fix typo in import.h, missing whitespaces in function prototypes.
 
 - Issue #19736: Add module-level statvfs constants defined for GNU/glibc
diff --git a/Objects/abstract.c b/Objects/abstract.c
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1155,7 +1155,7 @@
     return type_error("bad operand type for abs(): '%.200s'", o);
 }
 
-/* Return a Python int from the object item
+/* Return a Python int from the object item.
    Raise TypeError if the result is not an int
    or if the object cannot be interpreted as an index.
 */
@@ -1169,21 +1169,30 @@
         Py_INCREF(item);
         return item;
     }
-    if (PyIndex_Check(item)) {
-        result = item->ob_type->tp_as_number->nb_index(item);
-        if (result && !PyLong_Check(result)) {
-            PyErr_Format(PyExc_TypeError,
-                         "__index__ returned non-int "
-                         "(type %.200s)",
-                         result->ob_type->tp_name);
-            Py_DECREF(result);
-            return NULL;
-        }
-    }
-    else {
+    if (!PyIndex_Check(item)) {
         PyErr_Format(PyExc_TypeError,
                      "'%.200s' object cannot be interpreted "
                      "as an integer", item->ob_type->tp_name);
+        return NULL;
+    }
+    result = item->ob_type->tp_as_number->nb_index(item);
+    if (!result || PyLong_CheckExact(result))
+        return result;
+    if (!PyLong_Check(result)) {
+        PyErr_Format(PyExc_TypeError,
+                     "__index__ returned non-int (type %.200s)",
+                     result->ob_type->tp_name);
+        Py_DECREF(result);
+        return NULL;
+    }
+    /* Issue #17576: warn if 'result' not of exact type int. */
+    if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+            "__index__ returned non-int (type %.200s).  "
+            "The ability to return an instance of a strict subclass of int "
+            "is deprecated, and may be removed in a future version of Python.",
+            result->ob_type->tp_name)) {
+        Py_DECREF(result);
+        return NULL;
     }
     return result;
 }
@@ -1235,34 +1244,6 @@
 }
 
 
-/*
-  Returns the Integral instance converted to an int. The instance is expected
-  to be an int or have an __int__ method. Steals integral's
-  reference. error_format will be used to create the TypeError if integral
-  isn't actually an Integral instance. error_format should be a format string
-  that can accept a char* naming integral's type.
-*/
-static PyObject *
-convert_integral_to_int(PyObject *integral, const char *error_format)
-{
-    PyNumberMethods *nb;
-    if (PyLong_Check(integral))
-        return integral;
-    nb = Py_TYPE(integral)->tp_as_number;
-    if (nb->nb_int) {
-        PyObject *as_int = nb->nb_int(integral);
-        if (!as_int || PyLong_Check(as_int)) {
-            Py_DECREF(integral);
-            return as_int;
-        }
-        Py_DECREF(as_int);
-    }
-    PyErr_Format(PyExc_TypeError, error_format, Py_TYPE(integral)->tp_name);
-    Py_DECREF(integral);
-    return NULL;
-}
-
-
 PyObject *
 PyNumber_Long(PyObject *o)
 {
@@ -1280,29 +1261,28 @@
     }
     m = o->ob_type->tp_as_number;
     if (m && m->nb_int) { /* This should include subclasses of int */
-        PyObject *res = m->nb_int(o);
-        if (res && !PyLong_Check(res)) {
-            PyErr_Format(PyExc_TypeError,
-                         "__int__ returned non-int (type %.200s)",
-                         res->ob_type->tp_name);
-            Py_DECREF(res);
-            return NULL;
-        }
-        return res;
+        return (PyObject *)_PyLong_FromNbInt(o);
     }
-    if (PyLong_Check(o)) /* An int subclass without nb_int */
-        return _PyLong_Copy((PyLongObject *)o);
     trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
     if (trunc_func) {
         PyObject *truncated = PyEval_CallObject(trunc_func, NULL);
         PyObject *int_instance;
         Py_DECREF(trunc_func);
-        if (truncated == NULL)
-            return NULL;
+        if (truncated == NULL || PyLong_Check(truncated))
+            return truncated;
         /* __trunc__ is specified to return an Integral type,
            but int() needs to return a int. */
-        int_instance = convert_integral_to_int(truncated,
-            "__trunc__ returned non-Integral (type %.200s)");
+        m = truncated->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);
+            return NULL;
+        }
+        int_instance = (PyObject *)_PyLong_FromNbInt(truncated);
+        Py_DECREF(truncated);
         return int_instance;
     }
     if (PyErr_Occurred())
diff --git a/Objects/longobject.c b/Objects/longobject.c
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -122,6 +122,56 @@
     return v;
 }
 
+/* _PyLong_FromNbInt: Convert the given object to a PyLongObject
+   using the nb_int slot, if available.  Raise TypeError if either the
+   nb_int slot is not available or the result of the call to nb_int
+   returns something not of type int.
+*/
+PyLongObject *
+_PyLong_FromNbInt(PyObject *integral)
+{
+    PyNumberMethods *nb;
+    PyObject *result;
+
+    /* Fast path for the case that we already have an int. */
+    if (PyLong_CheckExact(integral)) {
+        Py_INCREF(integral);
+        return (PyLongObject *)integral;
+    }
+
+    nb = Py_TYPE(integral)->tp_as_number;
+    if (nb == NULL || nb->nb_int == NULL) {
+        PyErr_Format(PyExc_TypeError,
+                     "an integer is required (got type %.200s)",
+                     Py_TYPE(integral)->tp_name);
+        return NULL;
+    }
+
+    /* Convert using the nb_int slot, which should return something
+       of exact type int. */
+    result = nb->nb_int(integral);
+    if (!result || PyLong_CheckExact(result))
+        return (PyLongObject *)result;
+    if (!PyLong_Check(result)) {
+        PyErr_Format(PyExc_TypeError,
+                     "__int__ returned non-int (type %.200s)",
+                     result->ob_type->tp_name);
+        Py_DECREF(result);
+        return NULL;
+    }
+    /* Issue #17576: warn if 'result' not of exact type int. */
+    if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+            "__int__ returned non-int (type %.200s).  "
+            "The ability to return an instance of a strict subclass of int "
+            "is deprecated, and may be removed in a future version of Python.",
+            result->ob_type->tp_name)) {
+        Py_DECREF(result);
+        return NULL;
+    }
+    return (PyLongObject *)result;
+}
+
+
 /* Allocate a new int object with size digits.
    Return NULL and set exception if we run out of memory. */
 
@@ -353,28 +403,17 @@
         return -1;
     }
 
-    if (!PyLong_Check(vv)) {
-        PyNumberMethods *nb;
-        nb = vv->ob_type->tp_as_number;
-        if (nb == NULL || nb->nb_int == NULL) {
-            PyErr_SetString(PyExc_TypeError,
-                            "an integer is required");
-            return -1;
-        }
-        vv = (*nb->nb_int) (vv);
-        if (vv == NULL)
+    if (PyLong_Check(vv)) {
+        v = (PyLongObject *)vv;
+    }
+    else {
+        v = _PyLong_FromNbInt(vv);
+        if (v == NULL)
             return -1;
         do_decref = 1;
-        if (!PyLong_Check(vv)) {
-            Py_DECREF(vv);
-            PyErr_SetString(PyExc_TypeError,
-                            "nb_int should return int object");
-            return -1;
-        }
     }
 
     res = -1;
-    v = (PyLongObject *)vv;
     i = Py_SIZE(v);
 
     switch (i) {
@@ -418,7 +457,7 @@
     }
   exit:
     if (do_decref) {
-        Py_DECREF(vv);
+        Py_DECREF(v);
     }
     return res;
 }
@@ -636,36 +675,25 @@
 unsigned long
 PyLong_AsUnsignedLongMask(PyObject *op)
 {
-    PyNumberMethods *nb;
     PyLongObject *lo;
     unsigned long val;
 
-    if (op && PyLong_Check(op))
+    if (op == NULL) {
+        PyErr_BadInternalCall();
+        return (unsigned long)-1;
+    }
+
+    if (PyLong_Check(op)) {
         return _PyLong_AsUnsignedLongMask(op);
-
-    if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL ||
-        nb->nb_int == NULL) {
-        PyErr_SetString(PyExc_TypeError, "an integer is required");
-        return (unsigned long)-1;
-    }
-
-    lo = (PyLongObject*) (*nb->nb_int) (op);
+    }
+
+    lo = _PyLong_FromNbInt(op);
     if (lo == NULL)
         return (unsigned long)-1;
-    if (PyLong_Check(lo)) {
-        val = _PyLong_AsUnsignedLongMask((PyObject *)lo);
-        Py_DECREF(lo);
-        if (PyErr_Occurred())
-            return (unsigned long)-1;
-        return val;
-    }
-    else
-    {
-        Py_DECREF(lo);
-        PyErr_SetString(PyExc_TypeError,
-                        "nb_int should return int object");
-        return (unsigned long)-1;
-    }
+
+    val = _PyLong_AsUnsignedLongMask((PyObject *)lo);
+    Py_DECREF(lo);
+    return val;
 }
 
 int
@@ -1167,40 +1195,41 @@
     PyLongObject *v;
     PY_LONG_LONG bytes;
     int res;
+    int do_decref = 0; /* if nb_int was called */
 
     if (vv == NULL) {
         PyErr_BadInternalCall();
         return -1;
     }
-    if (!PyLong_Check(vv)) {
-        PyNumberMethods *nb;
-        PyObject *io;
-        if ((nb = vv->ob_type->tp_as_number) == NULL ||
-            nb->nb_int == NULL) {
-            PyErr_SetString(PyExc_TypeError, "an integer is required");
+
+    if (PyLong_Check(vv)) {
+        v = (PyLongObject *)vv;
+    }
+    else {
+        v = _PyLong_FromNbInt(vv);
+        if (v == NULL)
             return -1;
-        }
-        io = (*nb->nb_int) (vv);
-        if (io == NULL)
-            return -1;
-        if (PyLong_Check(io)) {
-            bytes = PyLong_AsLongLong(io);
-            Py_DECREF(io);
-            return bytes;
-        }
-        Py_DECREF(io);
-        PyErr_SetString(PyExc_TypeError, "integer conversion failed");
-        return -1;
-    }
-
-    v = (PyLongObject*)vv;
+        do_decref = 1;
+    }
+
+    res = 0;
     switch(Py_SIZE(v)) {
-    case -1: return -(sdigit)v->ob_digit[0];
-    case 0: return 0;
-    case 1: return v->ob_digit[0];
-    }
-    res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes,
-                              SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 1);
+    case -1:
+        bytes = -(sdigit)v->ob_digit[0];
+        break;
+    case 0:
+        bytes = 0;
+        break;
+    case 1:
+        bytes = v->ob_digit[0];
+        break;
+    default:
+        res = _PyLong_AsByteArray((PyLongObject *)v, (unsigned char *)&bytes,
+                                  SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 1);
+    }
+    if (do_decref) {
+        Py_DECREF(v);
+    }
 
     /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */
     if (res < 0)
@@ -1280,36 +1309,25 @@
 unsigned PY_LONG_LONG
 PyLong_AsUnsignedLongLongMask(PyObject *op)
 {
-    PyNumberMethods *nb;
     PyLongObject *lo;
     unsigned PY_LONG_LONG val;
 
-    if (op && PyLong_Check(op))
+    if (op == NULL) {
+        PyErr_BadInternalCall();
+        return (unsigned long)-1;
+    }
+
+    if (PyLong_Check(op)) {
         return _PyLong_AsUnsignedLongLongMask(op);
-
-    if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL ||
-        nb->nb_int == NULL) {
-        PyErr_SetString(PyExc_TypeError, "an integer is required");
-        return (unsigned PY_LONG_LONG)-1;
-    }
-
-    lo = (PyLongObject*) (*nb->nb_int) (op);
+    }
+
+    lo = _PyLong_FromNbInt(op);
     if (lo == NULL)
         return (unsigned PY_LONG_LONG)-1;
-    if (PyLong_Check(lo)) {
-        val = _PyLong_AsUnsignedLongLongMask((PyObject *)lo);
-        Py_DECREF(lo);
-        if (PyErr_Occurred())
-            return (unsigned PY_LONG_LONG)-1;
-        return val;
-    }
-    else
-    {
-        Py_DECREF(lo);
-        PyErr_SetString(PyExc_TypeError,
-                        "nb_int should return int object");
-        return (unsigned PY_LONG_LONG)-1;
-    }
+
+    val = _PyLong_AsUnsignedLongLongMask((PyObject *)lo);
+    Py_DECREF(lo);
+    return val;
 }
 
 /* Get a C long long int from an int object or any object that has an
@@ -1339,28 +1357,17 @@
         return -1;
     }
 
-    if (!PyLong_Check(vv)) {
-        PyNumberMethods *nb;
-        nb = vv->ob_type->tp_as_number;
-        if (nb == NULL || nb->nb_int == NULL) {
-            PyErr_SetString(PyExc_TypeError,
-                            "an integer is required");
-            return -1;
-        }
-        vv = (*nb->nb_int) (vv);
-        if (vv == NULL)
+    if (PyLong_Check(vv)) {
+        v = (PyLongObject *)vv;
+    }
+    else {
+        v = _PyLong_FromNbInt(vv);
+        if (v == NULL)
             return -1;
         do_decref = 1;
-        if (!PyLong_Check(vv)) {
-            Py_DECREF(vv);
-            PyErr_SetString(PyExc_TypeError,
-                            "nb_int should return int object");
-            return -1;
-        }
     }
 
     res = -1;
-    v = (PyLongObject *)vv;
     i = Py_SIZE(v);
 
     switch (i) {
@@ -1404,7 +1411,7 @@
     }
   exit:
     if (do_decref) {
-        Py_DECREF(vv);
+        Py_DECREF(v);
     }
     return res;
 }

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list