mirror of
https://github.com/python/cpython.git
synced 2025-08-01 15:43:13 +00:00
Issue #1530559: When packing a non-integer with any integer conversion
code using struct.pack, attempt to convert to an integer first using the argument's __int__ method (if present). Also raise a DeprecationWarning for any such usage of __int__. This fixes a regression from 2.6, where some (but not all) integer conversion codes already used __int__.
This commit is contained in:
parent
c083864fc8
commit
154b7ad07e
4 changed files with 128 additions and 35 deletions
|
@ -17,7 +17,10 @@ static PyTypeObject PyStructType;
|
|||
typedef int Py_ssize_t;
|
||||
#endif
|
||||
|
||||
#define FLOAT_COERCE "integer argument expected, got float"
|
||||
/* warning messages */
|
||||
#define FLOAT_COERCE_WARN "integer argument expected, got float"
|
||||
#define NON_INTEGER_WARN "integer argument expected, got non-integer " \
|
||||
"(implicit conversion using __int__ is deprecated)"
|
||||
|
||||
|
||||
/* The translation function for each format character is table driven */
|
||||
|
@ -104,21 +107,58 @@ static char *integer_codes = "bBhHiIlLqQ";
|
|||
static PyObject *
|
||||
get_pylong(PyObject *v)
|
||||
{
|
||||
PyObject *r;
|
||||
assert(v != NULL);
|
||||
if (PyInt_Check(v))
|
||||
return PyLong_FromLong(PyInt_AS_LONG(v));
|
||||
if (PyLong_Check(v)) {
|
||||
Py_INCREF(v);
|
||||
return v;
|
||||
}
|
||||
if (PyFloat_Check(v)) {
|
||||
if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 1)<0)
|
||||
if (!PyInt_Check(v) && !PyLong_Check(v)) {
|
||||
PyNumberMethods *m;
|
||||
/* Not an integer; try to use __int__ to convert to an
|
||||
integer. This behaviour is deprecated, and is removed in
|
||||
Python 3.x. */
|
||||
m = Py_TYPE(v)->tp_as_number;
|
||||
if (m != NULL && m->nb_int != NULL) {
|
||||
/* Special case warning message for floats, for
|
||||
backwards compatibility. */
|
||||
if (PyFloat_Check(v)) {
|
||||
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
||||
FLOAT_COERCE_WARN, 1))
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
||||
NON_INTEGER_WARN, 1))
|
||||
return NULL;
|
||||
}
|
||||
v = m->nb_int(v);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
if (!PyInt_Check(v) && !PyLong_Check(v)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__int__ method returned non-integer");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(StructError,
|
||||
"cannot convert argument to integer");
|
||||
return NULL;
|
||||
return PyNumber_Long(v);
|
||||
}
|
||||
}
|
||||
PyErr_SetString(StructError,
|
||||
"cannot convert argument to long");
|
||||
return NULL;
|
||||
else
|
||||
/* Ensure we own a reference to v. */
|
||||
Py_INCREF(v);
|
||||
|
||||
if (PyInt_Check(v)) {
|
||||
r = PyLong_FromLong(PyInt_AS_LONG(v));
|
||||
Py_DECREF(v);
|
||||
}
|
||||
else if (PyLong_Check(v)) {
|
||||
assert(PyLong_Check(v));
|
||||
r = v;
|
||||
}
|
||||
else
|
||||
assert(0); /* shouldn't ever get here */
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Helper to convert a Python object to a C long. Sets an exception
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue