summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-04-03 14:05:10 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2010-04-03 14:05:10 (GMT)
commit4846a8e828e345772de53aa410fcabe6a4aae772 (patch)
tree03d81d42998c42f59482f15001446c36ba70211e /Modules
parentae509520de5a0321f58c79afffad10ae59dae8b9 (diff)
downloadcpython-4846a8e828e345772de53aa410fcabe6a4aae772.zip
cpython-4846a8e828e345772de53aa410fcabe6a4aae772.tar.gz
cpython-4846a8e828e345772de53aa410fcabe6a4aae772.tar.bz2
Issue #8300: Let struct.pack use __index__ to convert and pack non-integers.
Based on a patch by Meador Inge.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_struct.c50
1 files changed, 39 insertions, 11 deletions
diff --git a/Modules/_struct.c b/Modules/_struct.c
index d09013f..fe54a47 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -107,25 +107,50 @@ static char *integer_codes = "bBhHiIlLqQ";
static PyObject *
get_pylong(PyObject *v)
{
- PyObject *r;
+ PyObject *r, *w;
+ int converted = 0;
assert(v != NULL);
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
+ /* Not an integer; first try to use __index__ to
+ convert to an integer. If the __index__ method
+ doesn't exist, or raises a TypeError, try __int__.
+ Use of the latter is deprecated, and will fail in
Python 3.x. */
+
m = Py_TYPE(v)->tp_as_number;
- if (m != NULL && m->nb_int != NULL) {
+ if (PyIndex_Check(v)) {
+ w = PyNumber_Index(v);
+ if (w != NULL) {
+ v = w;
+ if (!PyInt_Check(v) && !PyLong_Check(v)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__index__ method "
+ "returned non-integer");
+ return NULL;
+ }
+ /* successfully converted to an integer */
+ converted = 1;
+ }
+ else if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ PyErr_Clear();
+ }
+ else
+ return NULL;
+ }
+ if (!converted && 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))
+ if (PyErr_WarnEx(
+ PyExc_DeprecationWarning,
+ FLOAT_COERCE_WARN, 1))
return NULL;
}
else {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- NON_INTEGER_WARN, 1))
+ if (PyErr_WarnEx(
+ PyExc_DeprecationWarning,
+ NON_INTEGER_WARN, 1))
return NULL;
}
v = m->nb_int(v);
@@ -133,13 +158,16 @@ get_pylong(PyObject *v)
return NULL;
if (!PyInt_Check(v) && !PyLong_Check(v)) {
PyErr_SetString(PyExc_TypeError,
- "__int__ method returned non-integer");
+ "__int__ method returned "
+ "non-integer");
return NULL;
}
+ converted = 1;
}
- else {
+ if (!converted) {
PyErr_SetString(StructError,
- "cannot convert argument to integer");
+ "cannot convert argument "
+ "to integer");
return NULL;
}
}