[Python-checkins] r51119 - in python/trunk: Lib/test/test_struct.py Misc/NEWS Modules/_struct.c
bob.ippolito
python-checkins at python.org
Sat Aug 5 01:59:22 CEST 2006
Author: bob.ippolito
Date: Sat Aug 5 01:59:21 2006
New Revision: 51119
Modified:
python/trunk/Lib/test/test_struct.py
python/trunk/Misc/NEWS
python/trunk/Modules/_struct.c
Log:
Fix #1530559, struct.pack raises TypeError where it used to convert.
Passing float arguments to struct.pack when integers are expected
now triggers a DeprecationWarning.
Modified: python/trunk/Lib/test/test_struct.py
==============================================================================
--- python/trunk/Lib/test/test_struct.py (original)
+++ python/trunk/Lib/test/test_struct.py Sat Aug 5 01:59:21 2006
@@ -15,9 +15,11 @@
except ImportError:
PY_STRUCT_RANGE_CHECKING = 0
PY_STRUCT_OVERFLOW_MASKING = 1
+ PY_STRUCT_FLOAT_COERCE = 2
else:
- PY_STRUCT_RANGE_CHECKING = _struct._PY_STRUCT_RANGE_CHECKING
- PY_STRUCT_OVERFLOW_MASKING = _struct._PY_STRUCT_OVERFLOW_MASKING
+ PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
+ PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
+ PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
def string_reverse(s):
return "".join(reversed(s))
@@ -46,33 +48,40 @@
raise TestFailed, "%s%s did not raise error" % (
func.__name__, args)
+def with_warning_restore(func):
+ def _with_warning_restore(*args, **kw):
+ # The `warnings` module doesn't have an advertised way to restore
+ # its filter list. Cheat.
+ save_warnings_filters = warnings.filters[:]
+ # Grrr, we need this function to warn every time. Without removing
+ # the warningregistry, running test_tarfile then test_struct would fail
+ # on 64-bit platforms.
+ globals = func.func_globals
+ if '__warningregistry__' in globals:
+ del globals['__warningregistry__']
+ warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
+ warnings.filterwarnings("error", r""".*format requires.*""",
+ DeprecationWarning)
+ try:
+ return func(*args, **kw)
+ finally:
+ warnings.filters[:] = save_warnings_filters[:]
+ return _with_warning_restore
+
def deprecated_err(func, *args):
- # The `warnings` module doesn't have an advertised way to restore
- # its filter list. Cheat.
- save_warnings_filters = warnings.filters[:]
- # Grrr, we need this function to warn every time. Without removing
- # the warningregistry, running test_tarfile then test_struct would fail
- # on 64-bit platforms.
- globals = func.func_globals
- if '__warningregistry__' in globals:
- del globals['__warningregistry__']
- warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
- warnings.filterwarnings("error", r""".*format requires.*""",
- DeprecationWarning)
try:
- try:
- func(*args)
- except (struct.error, TypeError):
- pass
- except DeprecationWarning:
- if not PY_STRUCT_OVERFLOW_MASKING:
- raise TestFailed, "%s%s expected to raise struct.error" % (
- func.__name__, args)
- else:
- raise TestFailed, "%s%s did not raise error" % (
+ func(*args)
+ except (struct.error, TypeError):
+ pass
+ except DeprecationWarning:
+ if not PY_STRUCT_OVERFLOW_MASKING:
+ raise TestFailed, "%s%s expected to raise struct.error" % (
func.__name__, args)
- finally:
- warnings.filters[:] = save_warnings_filters[:]
+ else:
+ raise TestFailed, "%s%s did not raise error" % (
+ func.__name__, args)
+deprecated_err = with_warning_restore(deprecated_err)
+
simple_err(struct.calcsize, 'Z')
@@ -475,6 +484,9 @@
test_705836()
+###########################################################################
+# SF bug 1229380. No struct.pack exception for some out of range integers
+
def test_1229380():
import sys
for endian in ('', '>', '<'):
@@ -491,6 +503,37 @@
if PY_STRUCT_RANGE_CHECKING:
test_1229380()
+###########################################################################
+# SF bug 1530559. struct.pack raises TypeError where it used to convert.
+
+def check_float_coerce(format, number):
+ if PY_STRUCT_FLOAT_COERCE == 2:
+ # Test for pre-2.5 struct module
+ packed = struct.pack(format, number)
+ floored = struct.unpack(format, packed)[0]
+ if floored != int(number):
+ raise TestFailed("did not correcly coerce float to int")
+ return
+ try:
+ func(*args)
+ except (struct.error, TypeError):
+ if PY_STRUCT_FLOAT_COERCE:
+ raise TestFailed("expected DeprecationWarning for float coerce")
+ except DeprecationWarning:
+ if not PY_STRUCT_FLOAT_COERCE:
+ raise TestFailed("expected to raise struct.error for float coerce")
+ else:
+ raise TestFailed("did not raise error for float coerce")
+
+check_float_coerce = with_warning_restore(deprecated_err)
+
+def test_1530559():
+ for endian in ('', '>', '<'):
+ for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
+ check_float_coerce(endian + fmt, 1.0)
+ check_float_coerce(endian + fmt, 1.5)
+
+test_1530559()
###########################################################################
# Packing and unpacking to/from buffers.
Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS (original)
+++ python/trunk/Misc/NEWS Sat Aug 5 01:59:21 2006
@@ -40,6 +40,10 @@
Extension Modules
-----------------
+- Bug #1530559, struct.pack raises TypeError where it used to convert.
+ Passing float arguments to struct.pack when integers are expected
+ now triggers a DeprecationWarning.
+
Tests
-----
Modified: python/trunk/Modules/_struct.c
==============================================================================
--- python/trunk/Modules/_struct.c (original)
+++ python/trunk/Modules/_struct.c Sat Aug 5 01:59:21 2006
@@ -31,6 +31,17 @@
static PyObject *pyint_zero = NULL;
#endif
+/* 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;
@@ -135,6 +146,21 @@
{
long x = PyInt_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_Int(v);
+ if (o == NULL)
+ return -1;
+ res = get_long(o, p);
+ Py_DECREF(o);
+ return res;
+ }
+#endif
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_SetString(StructError,
"required argument is not an integer");
@@ -225,6 +251,21 @@
PyObject *wrapped;
long x;
PyErr_Clear();
+#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_Int(v);
+ if (o == NULL)
+ return -1;
+ res = get_wrapped_long(o, p);
+ Py_DECREF(o);
+ return res;
+ }
+#endif
if (PyErr_WarnEx(PyExc_DeprecationWarning, INT_OVERFLOW, 2) < 0)
return -1;
wrapped = PyNumber_And(v, pylong_ulong_mask);
@@ -249,6 +290,21 @@
if (x == -1 && PyErr_Occurred()) {
PyObject *wrapped;
PyErr_Clear();
+#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_Int(v);
+ if (o == NULL)
+ return -1;
+ res = get_wrapped_ulong(o, p);
+ Py_DECREF(o);
+ return res;
+ }
+#endif
wrapped = PyNumber_And(v, pylong_ulong_mask);
if (wrapped == NULL)
return -1;
@@ -1815,4 +1871,8 @@
#ifdef PY_STRUCT_OVERFLOW_MASKING
PyModule_AddIntConstant(m, "_PY_STRUCT_OVERFLOW_MASKING", 1);
#endif
+#ifdef PY_STRUCT_FLOAT_COERCE
+ PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1);
+#endif
+
}
More information about the Python-checkins
mailing list