From 31a655411a79b00517cdcd0a2752824d183db792 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 11 Dec 2013 21:07:54 +0200 Subject: [PATCH] Issue #17576: Deprecation warning emitted now when __int__() or __index__() return not int instance. Introduced _PyLong_FromNbInt() and refactored PyLong_As*() functions. --- 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 | 217 ++++++++++++++++++++------------------ 7 files changed, 313 insertions(+), 187 deletions(-) diff --git a/Include/longobject.h b/Include/longobject.h index fbe738cd2c8..1c1c5de8e1e 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -152,6 +152,12 @@ PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v, 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 index 48ca94ee381..79eb6399f41 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -50,12 +50,34 @@ class Int: 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)) @@ -70,6 +92,11 @@ class Unsigned_TestCase(unittest.TestCase): # 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)) @@ -84,6 +111,11 @@ class Unsigned_TestCase(unittest.TestCase): # 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)) @@ -99,6 +131,11 @@ class Unsigned_TestCase(unittest.TestCase): # 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)) @@ -115,6 +152,10 @@ class Unsigned_TestCase(unittest.TestCase): # 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)) @@ -131,6 +172,11 @@ class Signed_TestCase(unittest.TestCase): # 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)) @@ -145,6 +191,11 @@ class Signed_TestCase(unittest.TestCase): # 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)) @@ -159,6 +210,11 @@ class Signed_TestCase(unittest.TestCase): # 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)) @@ -174,6 +230,10 @@ class Signed_TestCase(unittest.TestCase): # (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)) @@ -192,6 +252,11 @@ class LongLong_TestCase(unittest.TestCase): 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)) @@ -206,6 +271,11 @@ class LongLong_TestCase(unittest.TestCase): # 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 index 66eedaaed72..a2ac32132e2 100644 --- a/Lib/test/test_index.py +++ b/Lib/test/test_index.py @@ -9,7 +9,7 @@ class newstyle: class TrapInt(int): def __index__(self): - return self + return int(self) class BaseTestCase(unittest.TestCase): def setUp(self): @@ -55,6 +55,40 @@ class BaseTestCase(unittest.TestCase): 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 index c198bcc7401..a4487bc8c45 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -263,32 +263,7 @@ class IntTestCases(unittest.TestCase): 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 @@ -351,6 +326,57 @@ class IntTestCases(unittest.TestCase): 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 index b6837f7dc50..0acfa724239 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.3.4 release candidate 1? 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 #19729: In str.format(), fix recursive expansion in format spec. diff --git a/Objects/abstract.c b/Objects/abstract.c index 1309c5158e3..f776aa97513 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1132,7 +1132,7 @@ PyNumber_Absolute(PyObject *o) 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. */ @@ -1146,21 +1146,30 @@ PyNumber_Index(PyObject *item) 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; } @@ -1212,34 +1221,6 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) } -/* - 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) { @@ -1257,29 +1238,28 @@ PyNumber_Long(PyObject *o) } 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 index 6383507a5c6..29040e60a9f 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -116,6 +116,56 @@ long_normalize(register PyLongObject *v) 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. */ @@ -347,28 +397,17 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) 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) { @@ -412,7 +451,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) } exit: if (do_decref) { - Py_DECREF(vv); + Py_DECREF(v); } return res; } @@ -630,36 +669,25 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) unsigned long PyLong_AsUnsignedLongMask(register PyObject *op) { - PyNumberMethods *nb; PyLongObject *lo; unsigned long val; - if (op && 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"); + if (op == NULL) { + PyErr_BadInternalCall(); return (unsigned long)-1; } - lo = (PyLongObject*) (*nb->nb_int) (op); + if (PyLong_Check(op)) { + return _PyLong_AsUnsignedLongMask(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 @@ -1169,40 +1197,41 @@ PyLong_AsLongLong(PyObject *vv) PY_LONG_LONG bytes; int one = 1; 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; + do_decref = 1; } - v = (PyLongObject*)vv; + 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]; + 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, IS_LITTLE_ENDIAN, 1); + } + if (do_decref) { + Py_DECREF(v); } - res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, - SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 1); /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */ if (res < 0) @@ -1283,36 +1312,25 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) unsigned PY_LONG_LONG PyLong_AsUnsignedLongLongMask(register PyObject *op) { - PyNumberMethods *nb; PyLongObject *lo; unsigned PY_LONG_LONG val; - if (op && 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; + if (op == NULL) { + PyErr_BadInternalCall(); + return (unsigned long)-1; } - lo = (PyLongObject*) (*nb->nb_int) (op); + if (PyLong_Check(op)) { + return _PyLong_AsUnsignedLongLongMask(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; } #undef IS_LITTLE_ENDIAN @@ -1343,28 +1361,17 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) 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) { @@ -1408,7 +1415,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) } exit: if (do_decref) { - Py_DECREF(vv); + Py_DECREF(v); } return res; }