IS32BIT = sys.maxsize == 0x7fffffff
del sys
-try:
- import _struct
-except ImportError:
- PY_STRUCT_FLOAT_COERCE = 2
-else:
- PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
-
def string_reverse(s):
return s[::-1]
else:
return string_reverse(value)
-def with_warning_restore(func):
- @wraps(func)
- def decorator(*args, **kw):
- with warnings.catch_warnings():
- # We need this function to warn every time, so stick an
- # unqualifed 'always' at the head of the filter list
- warnings.simplefilter("always")
- warnings.filterwarnings("error", category=DeprecationWarning)
- return func(*args, **kw)
- return decorator
-
class StructTest(unittest.TestCase):
-
- @with_warning_restore
- def check_float_coerce(self, format, number):
- # SF bug 1530559. struct.pack raises TypeError where it used to convert.
- if PY_STRUCT_FLOAT_COERCE == 2:
- # Test for pre-2.5 struct module
- packed = struct.pack(format, number)
- floored = struct.unpack(format, packed)[0]
- self.assertEqual(floored, int(number),
- "did not correcly coerce float to int")
- return
- try:
- struct.pack(format, number)
- except (struct.error, TypeError):
- if PY_STRUCT_FLOAT_COERCE:
- self.fail("expected DeprecationWarning for float coerce")
- except DeprecationWarning:
- if not PY_STRUCT_FLOAT_COERCE:
- self.fail("expected to raise struct.error for float coerce")
- else:
- self.fail("did not raise error for float coerce")
-
def test_isbigendian(self):
self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
else:
# x is out of range -- verify pack realizes that.
- self.assertRaises((struct.error, OverflowError),
- pack, ">" + code, x)
- self.assertRaises((struct.error, OverflowError),
- pack, "<" + code, x)
+ self.assertRaises(struct.error, pack, ">" + code, x)
+ self.assertRaises(struct.error, pack, "<" + code, x)
# Much the same for unsigned.
code = self.unsigned_code
else:
# x is out of range -- verify pack realizes that.
- self.assertRaises((struct.error, OverflowError),
- pack, ">" + code, x)
- self.assertRaises((struct.error, OverflowError),
- pack, "<" + code, x)
+ self.assertRaises(struct.error, pack, ">" + code, x)
+ self.assertRaises(struct.error, pack, "<" + code, x)
def run(self):
from random import randrange
# Some error cases.
for direction in "<>":
for code in self.formatpair:
- for badobject in "a string", 3+42j, randrange:
- self.assertRaises((struct.error, TypeError),
- struct.pack, direction + code,
- badobject)
+ for badobject in "a string", 3+42j, randrange, -1729.0:
+ self.assertRaises(struct.error,
+ struct.pack, direction + code,
+ badobject)
for args in [("bB", 1),
("hH", 2),
self.assertRaises((struct.error, OverflowError), struct.pack,
endian + 'L', sys.maxsize * 4)
- def XXXtest_1530559(self):
- # XXX This is broken: see the bug report
- # SF bug 1530559. struct.pack raises TypeError where it used to convert.
+ def test_1530559(self):
for endian in ('', '>', '<'):
- for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
- self.check_float_coerce(endian + fmt, 1.0)
- self.check_float_coerce(endian + fmt, 1.5)
+ for fmt in ('B', 'H', 'I', 'L', 'Q', 'b', 'h', 'i', 'l', 'q'):
+ self.assertRaises(struct.error, struct.pack, endian + fmt, 1.0)
+ self.assertRaises(struct.error, struct.pack, endian + fmt, 1.5)
+ self.assertRaises(struct.error, struct.pack, 'P', 1.0)
+ self.assertRaises(struct.error, struct.pack, 'P', 1.5)
+
def test_unpack_from(self):
test_string = b'abcd01234'
static PyTypeObject PyStructType;
-/* If PY_STRUCT_FLOAT_COERCE is defined, the struct module will allow float
- arguments for integer formats with a warning for backwards
- compatibility. */
-
-#define PY_STRUCT_FLOAT_COERCE 1
-
-#ifdef PY_STRUCT_FLOAT_COERCE
-#define FLOAT_COERCE "integer argument expected, got float"
-#endif
-
-
/* The translation function for each format character is table driven */
typedef struct _formatdef {
char format;
#pragma options align=reset
#endif
-/* Helper to get a PyLongObject by hook or by crook. Caller should decref. */
+/* Helper to get a PyLongObject. Caller should decref. */
static PyObject *
get_pylong(PyObject *v)
{
- PyNumberMethods *m;
-
assert(v != NULL);
- if (PyLong_Check(v)) {
- Py_INCREF(v);
- return v;
- }
- m = Py_TYPE(v)->tp_as_number;
- if (m != NULL && m->nb_int != NULL) {
- v = m->nb_int(v);
- if (v == NULL)
- return NULL;
- if (PyLong_Check(v))
- return v;
- Py_DECREF(v);
+ if (!PyLong_Check(v)) {
+ PyErr_SetString(StructError,
+ "required argument is not an integer");
+ return NULL;
}
- PyErr_SetString(StructError,
- "cannot convert argument to long");
- return NULL;
+
+ Py_INCREF(v);
+ return v;
}
-/* Helper routine to get a Python integer and raise the appropriate error
- if it isn't one */
+/* Helper routine to get a C long and raise the appropriate error if it isn't
+ one */
static int
get_long(PyObject *v, long *p)
{
- long x = PyLong_AsLong(v);
+ long x;
+
+ if (!PyLong_Check(v)) {
+ PyErr_SetString(StructError,
+ "required argument is not an integer");
+ return -1;
+ }
+ x = PyLong_AsLong(v);
if (x == -1 && PyErr_Occurred()) {
-#ifdef PY_STRUCT_FLOAT_COERCE
- if (PyFloat_Check(v)) {
- PyObject *o;
- int res;
- PyErr_Clear();
- if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0)
- return -1;
- o = PyNumber_Long(v);
- if (o == NULL)
- return -1;
- res = get_long(o, p);
- Py_DECREF(o);
- return res;
- }
-#endif
- if (PyErr_ExceptionMatches(PyExc_TypeError))
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_SetString(StructError,
- "required argument is not an integer");
+ "argument out of range");
return -1;
}
*p = x;
static int
get_ulong(PyObject *v, unsigned long *p)
{
- if (PyLong_Check(v)) {
- unsigned long x = PyLong_AsUnsignedLong(v);
- if (x == (unsigned long)(-1) && PyErr_Occurred())
- return -1;
- *p = x;
- return 0;
- }
- if (get_long(v, (long *)p) < 0)
- return -1;
- if (((long)*p) < 0) {
+ unsigned long x;
+
+ if (!PyLong_Check(v)) {
PyErr_SetString(StructError,
- "unsigned argument is < 0");
+ "required argument is not an integer");
+ return -1;
+ }
+ x = PyLong_AsUnsignedLong(v);
+ if (x == (unsigned long)-1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "argument out of range");
return -1;
}
+ *p = x;
return 0;
}
get_longlong(PyObject *v, PY_LONG_LONG *p)
{
PY_LONG_LONG x;
-
- v = get_pylong(v);
- if (v == NULL)
+ if (!PyLong_Check(v)) {
+ PyErr_SetString(StructError,
+ "required argument is not an integer");
return -1;
- assert(PyLong_Check(v));
+ }
x = PyLong_AsLongLong(v);
- Py_DECREF(v);
- if (x == (PY_LONG_LONG)-1 && PyErr_Occurred())
+ if (x == -1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "argument out of range");
return -1;
+ }
*p = x;
return 0;
}
get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
{
unsigned PY_LONG_LONG x;
-
- v = get_pylong(v);
- if (v == NULL)
+ if (!PyLong_Check(v)) {
+ PyErr_SetString(StructError,
+ "required argument is not an integer");
return -1;
- assert(PyLong_Check(v));
+ }
x = PyLong_AsUnsignedLongLong(v);
- Py_DECREF(v);
- if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
+ if (x == -1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "argument out of range");
return -1;
+ }
*p = x;
return 0;
}
{
PyObject *ver, *m;
- ver = PyBytes_FromString("0.2");
+ ver = PyBytes_FromString("0.3");
if (ver == NULL)
return NULL;
PyModule_AddObject(m, "__version__", ver);
-#ifdef PY_STRUCT_FLOAT_COERCE
- PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1);
-#endif
return m;
-
}