Commits

Jason Chu  committed 70bd50f

Don't accept floats in struct pack/unpack as per py3k test

Python 2 used to accept things like floats as arguments to struct.pack/unpack.
This was done away with in Python 3, for good reason.

  • Participants
  • Parent commits 4a1f056
  • Branches py3k-struct

Comments (0)

Files changed (3)

File pypy/module/struct/formatiterator.py

 from rpython.rlib.rstring import StringBuilder
 from rpython.rlib.rstruct.error import StructError
 from rpython.rlib.rstruct.formatiterator import FormatIterator
-from rpython.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT
 from pypy.interpreter.error import OperationError
 
 
         self.args_index += 1
         return w_obj
 
-    if PACK_ACCEPTS_BROKEN_INPUT:
-        # permissive version - accepts float arguments too
+    # accepts objects with __index__es
 
-        def accept_int_arg(self):
-            return self._accept_integral("int_w")
+    def accept_int_arg(self):
+        return self._accept_integral("int_w")
 
-        def accept_uint_arg(self):
-            return self._accept_integral("uint_w")
+    def accept_uint_arg(self):
+        return self._accept_integral("uint_w")
 
-        def accept_longlong_arg(self):
-            return self._accept_integral("r_longlong_w")
+    def accept_longlong_arg(self):
+        return self._accept_integral("r_longlong_w")
 
-        def accept_ulonglong_arg(self):
-            return self._accept_integral("r_ulonglong_w")
+    def accept_ulonglong_arg(self):
+        return self._accept_integral("r_ulonglong_w")
 
-        @specialize.arg(1)
-        def _accept_integral(self, meth):
-            space = self.space
-            w_obj = self.accept_obj_arg()
-            if space.isinstance_w(w_obj, space.w_int):
-                w_index = w_obj
-            else:
-                w_index = None
-                w_index_method = space.lookup(w_obj, "__index__")
-                if w_index_method is not None:
-                    try:
-                        w_index = space.index(w_obj)
-                    except OperationError, e:
-                        if not e.match(space, space.w_TypeError):
-                            raise
-                        pass
-                if w_index is None:
-                    w_index = self._maybe_float(w_obj)
-            return getattr(space, meth)(w_index)
-
-        def _maybe_float(self, w_obj):
-            space = self.space
-            if space.is_true(space.isinstance(w_obj, space.w_float)):
-                msg = "struct: integer argument expected, got float"
-            else:
-                msg = "integer argument expected, got non-integer"
-            space.warn(space.wrap(msg), space.w_DeprecationWarning)
-            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)
+    @specialize.arg(1)
+    def _accept_integral(self, meth):
+        space = self.space
+        w_obj = self.accept_obj_arg()
+        if space.isinstance_w(w_obj, space.w_int):
+            w_index = w_obj
+        else:
+            w_index = None
+            w_index_method = space.lookup(w_obj, "__index__")
+            if w_index_method is not None:
+                try:
+                    w_index = space.index(w_obj)
+                except OperationError, e:
+                    if not e.match(space, space.w_TypeError):
+                        raise
+                    pass
+            if w_index is None:
+                raise StructError("required argument is not an integer")
+        return getattr(space, meth)(w_index)
 
     def accept_bool_arg(self):
         w_obj = self.accept_obj_arg()

File pypy/module/struct/test/test_struct.py

         assert self.struct.unpack("i", self.struct.pack("i", X()))[0] == 3
 
 
-    def test_deprecation_warning(self):
-        import warnings
-        for code in 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q':
-            with warnings.catch_warnings(record=True) as w:
-                warnings.simplefilter("always")
-                raises(TypeError, self.struct.pack, code, 3j)
-            assert len(w) == 1
-            assert str(w[0].message) == "integer argument expected, got non-integer"
-            assert w[0].category is DeprecationWarning
-
-
     def test_pack_standard_little(self):
         """
         Check packing with the '<' format specifier.
                           b'spam and eggs')
         raises(self.struct.error, self.struct.unpack_from, '14s42', store, 0)
 
-
+    def test_1530559(self):
+        # Native 'q' packing isn't available on systems that don't have the C
+        # long long type.
+        try:
+            self.struct.pack('q', 5)
+        except self.struct.error:
+            HAVE_LONG_LONG = False
+        else:
+            HAVE_LONG_LONG = True
+        integer_codes = ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q')
+        for byteorder in '', '@', '=', '<', '>', '!':
+            for code in integer_codes:
+                if (byteorder in ('', '@') and code in ('q', 'Q') and
+                    not HAVE_LONG_LONG):
+                    continue
+                format = byteorder + code
+                raises(self.struct.error, self.struct.pack, format, 1.0)
+                raises(self.struct.error, self.struct.pack, format, 1.5)
+        raises(self.struct.error, self.struct.pack, 'P', 1.0)
+        raises(self.struct.error, self.struct.pack, 'P', 1.5)
 
 class AppTestStructBuffer(object):
     spaceconfig = dict(usemodules=['struct', '__pypy__'])

File rpython/rlib/rstruct/standardfmttable.py

 from rpython.rlib.rstruct.error import StructError, StructOverflowError
 from rpython.rlib.unroll import unrolling_iterable
 
-# 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):
     return min, max, accept_method
 
 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
+    check_range = True
     key = (size, signed, check_range)
     try:
         return _memo[key]