[pypy-svn] r46988 - in pypy/dist/pypy/module/struct: . test
arigo at codespeak.net
arigo at codespeak.net
Fri Sep 28 10:36:53 CEST 2007
Author: arigo
Date: Fri Sep 28 10:36:52 2007
New Revision: 46988
Modified:
pypy/dist/pypy/module/struct/formatiterator.py
pypy/dist/pypy/module/struct/nativefmttable.py
pypy/dist/pypy/module/struct/standardfmttable.py
pypy/dist/pypy/module/struct/test/test_struct.py
Log:
Emulate CPython 2.4 accepting broken input for struct.pack().
Modified: pypy/dist/pypy/module/struct/formatiterator.py
==============================================================================
--- pypy/dist/pypy/module/struct/formatiterator.py (original)
+++ pypy/dist/pypy/module/struct/formatiterator.py Fri Sep 28 10:36:52 2007
@@ -1,9 +1,11 @@
+from pypy.interpreter.error import OperationError
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.rarithmetic import ovfcheck
from pypy.module.struct.error import StructError
from pypy.module.struct.standardfmttable import standard_fmttable
+from pypy.module.struct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT
from pypy.module.struct.nativefmttable import native_fmttable
from pypy.module.struct.nativefmttable import native_is_bigendian
@@ -136,21 +138,63 @@
self.args_index += 1
return w_obj
- def accept_int_arg(self):
- w_obj = self.accept_obj_arg()
- return self.space.int_w(w_obj)
-
- def accept_uint_arg(self):
- w_obj = self.accept_obj_arg()
- return self.space.uint_w(w_obj)
+ if PACK_ACCEPTS_BROKEN_INPUT:
+ # permissive version - accepts float arguments too
- def accept_longlong_arg(self):
- w_obj = self.accept_obj_arg()
- return self.space.r_longlong_w(w_obj)
-
- def accept_ulonglong_arg(self):
- w_obj = self.accept_obj_arg()
- return self.space.r_ulonglong_w(w_obj)
+ def accept_int_arg(self):
+ w_obj = self.accept_obj_arg()
+ try:
+ return self.space.int_w(w_obj)
+ except OperationError, e:
+ return self.space.int_w(self._maybe_float(e, w_obj))
+
+ def accept_uint_arg(self):
+ w_obj = self.accept_obj_arg()
+ try:
+ return self.space.uint_w(w_obj)
+ except OperationError, e:
+ return self.space.uint_w(self._maybe_float(e, w_obj))
+
+ def accept_longlong_arg(self):
+ w_obj = self.accept_obj_arg()
+ try:
+ return self.space.r_longlong_w(w_obj)
+ except OperationError, e:
+ return self.space.r_longlong_w(self._maybe_float(e, w_obj))
+
+ def accept_ulonglong_arg(self):
+ w_obj = self.accept_obj_arg()
+ try:
+ return self.space.r_ulonglong_w(w_obj)
+ except OperationError, e:
+ return self.space.r_ulonglong_w(self._maybe_float(e, w_obj))
+
+ def _maybe_float(self, e, w_obj):
+ space = self.space
+ if not e.match(space, space.w_TypeError):
+ raise e
+ if not space.is_true(space.isinstance(w_obj, space.w_float)):
+ raise e
+ return space.int(w_obj) # wrapped float -> wrapped int or long
+
+ else:
+ # strict version
+
+ def accept_int_arg(self):
+ w_obj = self.accept_obj_arg()
+ return self.space.int_w(w_obj)
+
+ def accept_uint_arg(self):
+ w_obj = self.accept_obj_arg()
+ return self.space.uint_w(w_obj)
+
+ def accept_longlong_arg(self):
+ w_obj = self.accept_obj_arg()
+ return self.space.r_longlong_w(w_obj)
+
+ def accept_ulonglong_arg(self):
+ w_obj = self.accept_obj_arg()
+ return self.space.r_ulonglong_w(w_obj)
def accept_str_arg(self):
w_obj = self.accept_obj_arg()
Modified: pypy/dist/pypy/module/struct/nativefmttable.py
==============================================================================
--- pypy/dist/pypy/module/struct/nativefmttable.py (original)
+++ pypy/dist/pypy/module/struct/nativefmttable.py Fri Sep 28 10:36:52 2007
@@ -112,7 +112,8 @@
pack = pack_double
unpack = unpack_double
else:
- pack = std.make_int_packer(size, signed)
+ cpython_checks_range = fmtchar in 'bBhH'
+ pack = std.make_int_packer(size, signed, cpython_checks_range)
unpack = std.make_int_unpacker(size, signed)
native_fmttable[fmtchar] = {'size': size,
Modified: pypy/dist/pypy/module/struct/standardfmttable.py
==============================================================================
--- pypy/dist/pypy/module/struct/standardfmttable.py (original)
+++ pypy/dist/pypy/module/struct/standardfmttable.py Fri Sep 28 10:36:52 2007
@@ -11,6 +11,12 @@
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
+# In the CPython struct module, pack() unconsistently accepts inputs
+# that are out-of-range or floats instead of ints. Should we emulate
+# this? Let's use a flag for now:
+
+PACK_ACCEPTS_BROKEN_INPUT = True
+
# ____________________________________________________________
def pack_pad(fmtiter, count):
@@ -59,11 +65,17 @@
native_int_size = struct.calcsize("l")
-def make_int_packer(size, signed, _memo={}):
+def make_int_packer(size, signed, cpython_checks_range, _memo={}):
+ if cpython_checks_range:
+ check_range = True
+ else:
+ check_range = not PACK_ACCEPTS_BROKEN_INPUT
+ key = (size, signed, check_range)
try:
- return _memo[size, signed]
+ return _memo[key]
except KeyError:
pass
+
if signed:
min = -(2 ** (8*size-1))
max = (2 ** (8*size-1)) - 1
@@ -99,8 +111,9 @@
def pack_int(fmtiter):
method = getattr(fmtiter, accept_method)
value = method()
- if value < min or value > max:
- raise StructError(errormsg)
+ if check_range:
+ if value < min or value > max:
+ raise StructError(errormsg)
if fmtiter.bigendian:
for i in unroll_revrange_size:
x = (value >> (8*i)) & 0xff
@@ -110,7 +123,7 @@
fmtiter.result.append(chr(value & 0xff))
value >>= 8
- _memo[size, signed] = pack_int
+ _memo[key] = pack_int
return pack_int
# ____________________________________________________________
@@ -201,8 +214,9 @@
for c, size in [('b', 1), ('h', 2), ('i', 4), ('l', 4), ('q', 8)]:
standard_fmttable[c] = {'size': size,
- 'pack': make_int_packer(size, True),
+ 'pack': make_int_packer(size, True, False),
'unpack': make_int_unpacker(size, True)}
standard_fmttable[c.upper()] = {'size': size,
- 'pack': make_int_packer(size, False),
+ 'pack': make_int_packer(size, False,
+ False),
'unpack': make_int_unpacker(size, False)}
Modified: pypy/dist/pypy/module/struct/test/test_struct.py
==============================================================================
--- pypy/dist/pypy/module/struct/test/test_struct.py (original)
+++ pypy/dist/pypy/module/struct/test/test_struct.py Fri Sep 28 10:36:52 2007
@@ -310,3 +310,15 @@
raises(someerror, calcsize, "%dcc" % (sys.maxint,))
raises(someerror, calcsize, "c%dc" % (sys.maxint,))
raises(someerror, calcsize, "%dci" % (sys.maxint,))
+
+
+ def test_broken_input(self):
+ """
+ For compatibility: check that we also accept inputs that are
+ wrongly accepted by CPython 2.4.
+ """
+ pack = self.struct.pack
+ assert pack("!b", 0xa0) == '\xa0'
+ assert pack("!B", -1.1) == '\xff'
+ assert pack("!h", 0xa000) == '\xa0\x00'
+ assert pack("!H", -2.2) == '\xff\xfe'
More information about the Pypy-commit
mailing list