Issue #17576: Deprecation warning emitted now when __int__() or __index__()

return not int instance.  Introduced _PyLong_FromNbInt() and refactored
PyLong_As*() functions.
This commit is contained in:
Serhiy Storchaka 2013-12-11 21:07:54 +02:00
parent acd17304d2
commit 31a655411a
7 changed files with 313 additions and 187 deletions

View File

@ -152,6 +152,12 @@ PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v,
unsigned char* bytes, size_t n, unsigned char* bytes, size_t n,
int little_endian, int is_signed); 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, /* _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. */ appending a base prefix of 0[box] if base is 2, 8 or 16. */

View File

@ -50,12 +50,34 @@ class Int:
def __int__(self): def __int__(self):
return 99 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): class Unsigned_TestCase(unittest.TestCase):
def test_b(self): def test_b(self):
from _testcapi import getargs_b from _testcapi import getargs_b
# b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX) # b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX)
self.assertRaises(TypeError, getargs_b, 3.14) self.assertRaises(TypeError, getargs_b, 3.14)
self.assertEqual(99, getargs_b(Int())) 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.assertRaises(OverflowError, getargs_b, -1)
self.assertEqual(0, getargs_b(0)) self.assertEqual(0, getargs_b(0))
@ -70,6 +92,11 @@ class Unsigned_TestCase(unittest.TestCase):
# B returns 'unsigned char', no range checking # B returns 'unsigned char', no range checking
self.assertRaises(TypeError, getargs_B, 3.14) self.assertRaises(TypeError, getargs_B, 3.14)
self.assertEqual(99, getargs_B(Int())) 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(UCHAR_MAX, getargs_B(-1))
self.assertEqual(0, getargs_B(0)) self.assertEqual(0, getargs_B(0))
@ -84,6 +111,11 @@ class Unsigned_TestCase(unittest.TestCase):
# H returns 'unsigned short', no range checking # H returns 'unsigned short', no range checking
self.assertRaises(TypeError, getargs_H, 3.14) self.assertRaises(TypeError, getargs_H, 3.14)
self.assertEqual(99, getargs_H(Int())) 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(USHRT_MAX, getargs_H(-1))
self.assertEqual(0, getargs_H(0)) self.assertEqual(0, getargs_H(0))
@ -99,6 +131,11 @@ class Unsigned_TestCase(unittest.TestCase):
# I returns 'unsigned int', no range checking # I returns 'unsigned int', no range checking
self.assertRaises(TypeError, getargs_I, 3.14) self.assertRaises(TypeError, getargs_I, 3.14)
self.assertEqual(99, getargs_I(Int())) 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(UINT_MAX, getargs_I(-1))
self.assertEqual(0, getargs_I(0)) self.assertEqual(0, getargs_I(0))
@ -115,6 +152,10 @@ class Unsigned_TestCase(unittest.TestCase):
# it does not accept float, or instances with __int__ # it does not accept float, or instances with __int__
self.assertRaises(TypeError, getargs_k, 3.14) self.assertRaises(TypeError, getargs_k, 3.14)
self.assertRaises(TypeError, getargs_k, Int()) 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(ULONG_MAX, getargs_k(-1))
self.assertEqual(0, getargs_k(0)) 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) # h returns 'short', and does range checking (SHRT_MIN ... SHRT_MAX)
self.assertRaises(TypeError, getargs_h, 3.14) self.assertRaises(TypeError, getargs_h, 3.14)
self.assertEqual(99, getargs_h(Int())) 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.assertRaises(OverflowError, getargs_h, SHRT_MIN-1)
self.assertEqual(SHRT_MIN, getargs_h(SHRT_MIN)) 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) # i returns 'int', and does range checking (INT_MIN ... INT_MAX)
self.assertRaises(TypeError, getargs_i, 3.14) self.assertRaises(TypeError, getargs_i, 3.14)
self.assertEqual(99, getargs_i(Int())) 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.assertRaises(OverflowError, getargs_i, INT_MIN-1)
self.assertEqual(INT_MIN, getargs_i(INT_MIN)) 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) # l returns 'long', and does range checking (LONG_MIN ... LONG_MAX)
self.assertRaises(TypeError, getargs_l, 3.14) self.assertRaises(TypeError, getargs_l, 3.14)
self.assertEqual(99, getargs_l(Int())) 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.assertRaises(OverflowError, getargs_l, LONG_MIN-1)
self.assertEqual(LONG_MIN, getargs_l(LONG_MIN)) 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) # (PY_SSIZE_T_MIN ... PY_SSIZE_T_MAX)
self.assertRaises(TypeError, getargs_n, 3.14) self.assertRaises(TypeError, getargs_n, 3.14)
self.assertRaises(TypeError, getargs_n, Int()) 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.assertRaises(OverflowError, getargs_n, PY_SSIZE_T_MIN-1)
self.assertEqual(PY_SSIZE_T_MIN, getargs_n(PY_SSIZE_T_MIN)) 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, 3.14)
self.assertRaises(TypeError, getargs_L, "Hello") self.assertRaises(TypeError, getargs_L, "Hello")
self.assertEqual(99, getargs_L(Int())) 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.assertRaises(OverflowError, getargs_L, LLONG_MIN-1)
self.assertEqual(LLONG_MIN, getargs_L(LLONG_MIN)) 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 # K return 'unsigned long long', no range checking
self.assertRaises(TypeError, getargs_K, 3.14) self.assertRaises(TypeError, getargs_K, 3.14)
self.assertRaises(TypeError, getargs_K, Int()) 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(ULLONG_MAX, getargs_K(ULLONG_MAX))
self.assertEqual(0, getargs_K(0)) self.assertEqual(0, getargs_K(0))
self.assertEqual(0, getargs_K(ULLONG_MAX+1)) self.assertEqual(0, getargs_K(ULLONG_MAX+1))

View File

@ -9,7 +9,7 @@ class newstyle:
class TrapInt(int): class TrapInt(int):
def __index__(self): def __index__(self):
return self return int(self)
class BaseTestCase(unittest.TestCase): class BaseTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
@ -55,6 +55,40 @@ class BaseTestCase(unittest.TestCase):
self.assertRaises(TypeError, slice(self.o).indices, 0) self.assertRaises(TypeError, slice(self.o).indices, 0)
self.assertRaises(TypeError, slice(self.n).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: class SeqTestCase:
# This test case isn't run directly. It just defines common tests # This test case isn't run directly. It just defines common tests

View File

@ -263,32 +263,7 @@ class IntTestCases(unittest.TestCase):
def __int__(self): def __int__(self):
return 42 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(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: class Classic:
pass pass
@ -351,6 +326,57 @@ class IntTestCases(unittest.TestCase):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
int(TruncReturnsBadInt()) 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 test_error_message(self):
def check(s, base=None): def check(s, base=None):
with self.assertRaises(ValueError, with self.assertRaises(ValueError,

View File

@ -10,6 +10,9 @@ What's New in Python 3.3.4 release candidate 1?
Core and Builtins 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 #19932: Fix typo in import.h, missing whitespaces in function prototypes.
- Issue #19729: In str.format(), fix recursive expansion in format spec. - Issue #19729: In str.format(), fix recursive expansion in format spec.

View File

@ -1132,7 +1132,7 @@ PyNumber_Absolute(PyObject *o)
return type_error("bad operand type for abs(): '%.200s'", 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 Raise TypeError if the result is not an int
or if the object cannot be interpreted as an index. or if the object cannot be interpreted as an index.
*/ */
@ -1146,21 +1146,30 @@ PyNumber_Index(PyObject *item)
Py_INCREF(item); Py_INCREF(item);
return item; return item;
} }
if (PyIndex_Check(item)) { if (!PyIndex_Check(item)) {
result = item->ob_type->tp_as_number->nb_index(item);
if (result && !PyLong_Check(result)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"__index__ returned non-int " "'%.200s' object cannot be interpreted "
"(type %.200s)", "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); result->ob_type->tp_name);
Py_DECREF(result); Py_DECREF(result);
return NULL; return NULL;
} }
} /* Issue #17576: warn if 'result' not of exact type int. */
else { if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
PyErr_Format(PyExc_TypeError, "__index__ returned non-int (type %.200s). "
"'%.200s' object cannot be interpreted " "The ability to return an instance of a strict subclass of int "
"as an integer", item->ob_type->tp_name); "is deprecated, and may be removed in a future version of Python.",
result->ob_type->tp_name)) {
Py_DECREF(result);
return NULL;
} }
return result; 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 * PyObject *
PyNumber_Long(PyObject *o) PyNumber_Long(PyObject *o)
{ {
@ -1257,29 +1238,28 @@ PyNumber_Long(PyObject *o)
} }
m = o->ob_type->tp_as_number; m = o->ob_type->tp_as_number;
if (m && m->nb_int) { /* This should include subclasses of int */ if (m && m->nb_int) { /* This should include subclasses of int */
PyObject *res = m->nb_int(o); return (PyObject *)_PyLong_FromNbInt(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;
}
if (PyLong_Check(o)) /* An int subclass without nb_int */
return _PyLong_Copy((PyLongObject *)o);
trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__); trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
if (trunc_func) { if (trunc_func) {
PyObject *truncated = PyEval_CallObject(trunc_func, NULL); PyObject *truncated = PyEval_CallObject(trunc_func, NULL);
PyObject *int_instance; PyObject *int_instance;
Py_DECREF(trunc_func); Py_DECREF(trunc_func);
if (truncated == NULL) if (truncated == NULL || PyLong_Check(truncated))
return NULL; return truncated;
/* __trunc__ is specified to return an Integral type, /* __trunc__ is specified to return an Integral type,
but int() needs to return a int. */ but int() needs to return a int. */
int_instance = convert_integral_to_int(truncated, m = truncated->ob_type->tp_as_number;
"__trunc__ returned non-Integral (type %.200s)"); 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; return int_instance;
} }
if (PyErr_Occurred()) if (PyErr_Occurred())

View File

@ -116,6 +116,56 @@ long_normalize(register PyLongObject *v)
return 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. /* Allocate a new int object with size digits.
Return NULL and set exception if we run out of memory. */ Return NULL and set exception if we run out of memory. */
@ -347,28 +397,17 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
return -1; return -1;
} }
if (!PyLong_Check(vv)) { if (PyLong_Check(vv)) {
PyNumberMethods *nb; v = (PyLongObject *)vv;
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); else {
if (vv == NULL) v = _PyLong_FromNbInt(vv);
if (v == NULL)
return -1; return -1;
do_decref = 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; res = -1;
v = (PyLongObject *)vv;
i = Py_SIZE(v); i = Py_SIZE(v);
switch (i) { switch (i) {
@ -412,7 +451,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
} }
exit: exit:
if (do_decref) { if (do_decref) {
Py_DECREF(vv); Py_DECREF(v);
} }
return res; return res;
} }
@ -630,37 +669,26 @@ _PyLong_AsUnsignedLongMask(PyObject *vv)
unsigned long unsigned long
PyLong_AsUnsignedLongMask(register PyObject *op) PyLong_AsUnsignedLongMask(register PyObject *op)
{ {
PyNumberMethods *nb;
PyLongObject *lo; PyLongObject *lo;
unsigned long val; unsigned long val;
if (op && PyLong_Check(op)) if (op == NULL) {
return _PyLong_AsUnsignedLongMask(op); PyErr_BadInternalCall();
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; 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) if (lo == NULL)
return (unsigned long)-1; return (unsigned long)-1;
if (PyLong_Check(lo)) {
val = _PyLong_AsUnsignedLongMask((PyObject *)lo); val = _PyLong_AsUnsignedLongMask((PyObject *)lo);
Py_DECREF(lo); Py_DECREF(lo);
if (PyErr_Occurred())
return (unsigned long)-1;
return val; return val;
} }
else
{
Py_DECREF(lo);
PyErr_SetString(PyExc_TypeError,
"nb_int should return int object");
return (unsigned long)-1;
}
}
int int
_PyLong_Sign(PyObject *vv) _PyLong_Sign(PyObject *vv)
@ -1169,40 +1197,41 @@ PyLong_AsLongLong(PyObject *vv)
PY_LONG_LONG bytes; PY_LONG_LONG bytes;
int one = 1; int one = 1;
int res; int res;
int do_decref = 0; /* if nb_int was called */
if (vv == NULL) { if (vv == NULL) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return -1; return -1;
} }
if (!PyLong_Check(vv)) {
PyNumberMethods *nb; if (PyLong_Check(vv)) {
PyObject *io; v = (PyLongObject *)vv;
if ((nb = vv->ob_type->tp_as_number) == NULL ||
nb->nb_int == NULL) {
PyErr_SetString(PyExc_TypeError, "an integer is required");
return -1;
} }
io = (*nb->nb_int) (vv); else {
if (io == NULL) v = _PyLong_FromNbInt(vv);
return -1; if (v == NULL)
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; return -1;
do_decref = 1;
} }
v = (PyLongObject*)vv; res = 0;
switch(Py_SIZE(v)) { switch(Py_SIZE(v)) {
case -1: return -(sdigit)v->ob_digit[0]; case -1:
case 0: return 0; bytes = -(sdigit)v->ob_digit[0];
case 1: return v->ob_digit[0]; break;
} case 0:
res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, 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); SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 1);
}
if (do_decref) {
Py_DECREF(v);
}
/* Plan 9 can't handle PY_LONG_LONG in ? : expressions */ /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */
if (res < 0) if (res < 0)
@ -1283,37 +1312,26 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv)
unsigned PY_LONG_LONG unsigned PY_LONG_LONG
PyLong_AsUnsignedLongLongMask(register PyObject *op) PyLong_AsUnsignedLongLongMask(register PyObject *op)
{ {
PyNumberMethods *nb;
PyLongObject *lo; PyLongObject *lo;
unsigned PY_LONG_LONG val; unsigned PY_LONG_LONG val;
if (op && PyLong_Check(op)) if (op == NULL) {
return _PyLong_AsUnsignedLongLongMask(op); PyErr_BadInternalCall();
return (unsigned long)-1;
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); if (PyLong_Check(op)) {
return _PyLong_AsUnsignedLongLongMask(op);
}
lo = _PyLong_FromNbInt(op);
if (lo == NULL) if (lo == NULL)
return (unsigned PY_LONG_LONG)-1; return (unsigned PY_LONG_LONG)-1;
if (PyLong_Check(lo)) {
val = _PyLong_AsUnsignedLongLongMask((PyObject *)lo); val = _PyLong_AsUnsignedLongLongMask((PyObject *)lo);
Py_DECREF(lo); Py_DECREF(lo);
if (PyErr_Occurred())
return (unsigned PY_LONG_LONG)-1;
return val; return val;
} }
else
{
Py_DECREF(lo);
PyErr_SetString(PyExc_TypeError,
"nb_int should return int object");
return (unsigned PY_LONG_LONG)-1;
}
}
#undef IS_LITTLE_ENDIAN #undef IS_LITTLE_ENDIAN
/* Get a C long long int from an int object or any object that has an /* Get a C long long int from an int object or any object that has an
@ -1343,28 +1361,17 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
return -1; return -1;
} }
if (!PyLong_Check(vv)) { if (PyLong_Check(vv)) {
PyNumberMethods *nb; v = (PyLongObject *)vv;
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); else {
if (vv == NULL) v = _PyLong_FromNbInt(vv);
if (v == NULL)
return -1; return -1;
do_decref = 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; res = -1;
v = (PyLongObject *)vv;
i = Py_SIZE(v); i = Py_SIZE(v);
switch (i) { switch (i) {
@ -1408,7 +1415,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
} }
exit: exit:
if (do_decref) { if (do_decref) {
Py_DECREF(vv); Py_DECREF(v);
} }
return res; return res;
} }