diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2010-04-03 14:05:10 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2010-04-03 14:05:10 (GMT) |
commit | 4846a8e828e345772de53aa410fcabe6a4aae772 (patch) | |
tree | 03d81d42998c42f59482f15001446c36ba70211e /Modules/_struct.c | |
parent | ae509520de5a0321f58c79afffad10ae59dae8b9 (diff) | |
download | cpython-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/_struct.c')
-rw-r--r-- | Modules/_struct.c | 50 |
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; } } |