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

@ -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())

View file

@ -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;
}