summaryrefslogtreecommitdiffstats
path: root/Modules/_struct.c
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-03-07 16:24:45 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2010-03-07 16:24:45 (GMT)
commit154b7ad07e775f15a0a556c7ec3ae5ab5762ae1e (patch)
tree8102aad436b0b60b7e1a98a376a1257546019898 /Modules/_struct.c
parentc083864fc8a03a045dfc0200e8456996395ad4dc (diff)
downloadcpython-154b7ad07e775f15a0a556c7ec3ae5ab5762ae1e.zip
cpython-154b7ad07e775f15a0a556c7ec3ae5ab5762ae1e.tar.gz
cpython-154b7ad07e775f15a0a556c7ec3ae5ab5762ae1e.tar.bz2
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__.
Diffstat (limited to 'Modules/_struct.c')
-rw-r--r--Modules/_struct.c64
1 files changed, 52 insertions, 12 deletions
diff --git a/Modules/_struct.c b/Modules/_struct.c
index 97f2f75..e8fe67d 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -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)) {
+ 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;
+ }
+ }
+ else
+ /* Ensure we own a reference to v. */
Py_INCREF(v);
- return v;
+
+ if (PyInt_Check(v)) {
+ r = PyLong_FromLong(PyInt_AS_LONG(v));
+ Py_DECREF(v);
}
- if (PyFloat_Check(v)) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 1)<0)
- return NULL;
- return PyNumber_Long(v);
+ else if (PyLong_Check(v)) {
+ assert(PyLong_Check(v));
+ r = v;
}
- PyErr_SetString(StructError,
- "cannot convert argument to long");
- return NULL;
+ else
+ assert(0); /* shouldn't ever get here */
+
+ return r;
}
/* Helper to convert a Python object to a C long. Sets an exception