[pypy-svn] r46925 - in pypy/dist/pypy/module/struct: . test

arigo at codespeak.net arigo at codespeak.net
Thu Sep 27 10:17:39 CEST 2007


Author: arigo
Date: Thu Sep 27 10:17:38 2007
New Revision: 46925

Modified:
   pypy/dist/pypy/module/struct/error.py
   pypy/dist/pypy/module/struct/formatiterator.py
   pypy/dist/pypy/module/struct/interp_struct.py
   pypy/dist/pypy/module/struct/nativefmttable.py
   pypy/dist/pypy/module/struct/test/test_struct.py
Log:
Report the error conditions at app-level.


Modified: pypy/dist/pypy/module/struct/error.py
==============================================================================
--- pypy/dist/pypy/module/struct/error.py	(original)
+++ pypy/dist/pypy/module/struct/error.py	Thu Sep 27 10:17:38 2007
@@ -1,3 +1,4 @@
+from pypy.interpreter.error import OperationError
 
 class StructError(Exception):
     "Interp-level error that gets mapped to an app-level struct.error."
@@ -7,3 +8,8 @@
 
     def __str__(self):
         return self.msg
+
+    def at_applevel(self, space):
+        w_module = space.getbuiltinmodule('struct')
+        w_error = space.getattr(w_module, space.wrap('error'))
+        return OperationError(w_error, space.wrap(self.msg))

Modified: pypy/dist/pypy/module/struct/formatiterator.py
==============================================================================
--- pypy/dist/pypy/module/struct/formatiterator.py	(original)
+++ pypy/dist/pypy/module/struct/formatiterator.py	Thu Sep 27 10:17:38 2007
@@ -56,7 +56,6 @@
                         break
                     repetitions = ovfcheck(repetitions * 10)
                     repetitions = ovfcheck(repetitions + (ord(c) - ord('0')))
-                    # XXX catch OverflowError somewhere
             else:
                 repetitions = 1
 
@@ -68,6 +67,10 @@
                     break
             else:
                 raise StructError("bad char in struct format")
+        self.finished()
+
+    def finished(self):
+        pass
 
 
 class CalcSizeFormatIterator(FormatIterator):
@@ -90,7 +93,8 @@
 
     def __init__(self, space, args_w):
         self.space = space
-        self.args_iterator = iter(args_w)
+        self.args_w = args_w
+        self.args_index = 0
         self.result = []      # list of characters
 
     def operate(self, fmtdesc, repetitions):
@@ -106,12 +110,24 @@
         for i in range(pad):
             self.result.append('\x00')
 
+    def finished(self):
+        if self.args_index != len(self.args_w):
+            raise StructError("too many arguments for struct format")
+
+    def accept_obj_arg(self):
+        try:
+            w_obj = self.args_w[self.args_index]
+        except IndexError:
+            raise StructError("struct format requires more arguments")
+        self.args_index += 1
+        return w_obj
+
     def accept_int_arg(self):
-        w_obj = self.args_iterator.next()   # XXX catch StopIteration
+        w_obj = self.accept_obj_arg()
         return self.space.int_w(w_obj)
 
     def accept_str_arg(self):
-        w_obj = self.args_iterator.next()   # XXX catch StopIteration
+        w_obj = self.accept_obj_arg()
         return self.space.str_w(w_obj)
 
 
@@ -134,10 +150,14 @@
     def align(self, mask):
         self.inputpos = (self.inputpos + mask) & ~mask
 
+    def finished(self):
+        if self.inputpos != len(self.input):
+            raise StructError("unpack str size too long for format")
+
     def read(self, count):
         end = self.inputpos + count
         if end > len(self.input):
-            raise StructError("unpack str size is too short for the format")
+            raise StructError("unpack str size too short for format")
         s = self.input[self.inputpos : end]
         self.inputpos = end
         return s

Modified: pypy/dist/pypy/module/struct/interp_struct.py
==============================================================================
--- pypy/dist/pypy/module/struct/interp_struct.py	(original)
+++ pypy/dist/pypy/module/struct/interp_struct.py	Thu Sep 27 10:17:38 2007
@@ -1,20 +1,38 @@
 from pypy.interpreter.gateway import ObjSpace
+from pypy.interpreter.error import OperationError
+from pypy.module.struct.error import StructError
 from pypy.module.struct.formatiterator import CalcSizeFormatIterator
 from pypy.module.struct.formatiterator import PackFormatIterator
 from pypy.module.struct.formatiterator import UnpackFormatIterator
 
 
+def overflow(space):
+    return OperationError(space.w_OverflowError,
+                          space.wrap("struct format too large"))
+
+
 def calcsize(space, format):
     fmtiter = CalcSizeFormatIterator()
-    fmtiter.interpret(format)
+    try:
+        fmtiter.interpret(format)
+    except StructError, e:
+        raise e.at_applevel(space)
+    except OverflowError:
+        raise overflow(space)
     return space.wrap(fmtiter.totalsize)
 calcsize.unwrap_spec = [ObjSpace, str]
 
 
 def pack(space, format, args_w):
     fmtiter = PackFormatIterator(space, args_w)
-    fmtiter.interpret(format)
+    try:
+        fmtiter.interpret(format)
+    except StructError, e:
+        raise e.at_applevel(space)
+    except OverflowError:
+        raise overflow(space)
     # XXX check that all arguments have been consumed
+    "too many arguments for struct format"
     result = ''.join(fmtiter.result)
     return space.wrap(result)
 pack.unwrap_spec = [ObjSpace, str, 'args_w']
@@ -22,7 +40,13 @@
 
 def unpack(space, format, input):
     fmtiter = UnpackFormatIterator(space, input)
-    fmtiter.interpret(format)
+    try:
+        fmtiter.interpret(format)
+    except StructError, e:
+        raise e.at_applevel(space)
+    except OverflowError:
+        raise overflow(space)
     # XXX check that the input string has been fully consumed
+    "unpack str size too long for format"
     return space.newtuple(fmtiter.result_w)
 unpack.unwrap_spec = [ObjSpace, str, str]

Modified: pypy/dist/pypy/module/struct/nativefmttable.py
==============================================================================
--- pypy/dist/pypy/module/struct/nativefmttable.py	(original)
+++ pypy/dist/pypy/module/struct/nativefmttable.py	Thu Sep 27 10:17:38 2007
@@ -1,5 +1,4 @@
 import struct
-from pypy.module.struct.error import StructError
 from pypy.module.struct import standardfmttable as std
 from pypy.rpython.tool import rffi_platform
 from pypy.rpython.lltypesystem import lltype, rffi

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	Thu Sep 27 10:17:38 2007
@@ -187,3 +187,53 @@
         assert pack("5x") == "\x00" * 5
         assert unpack("x", "?") == ()
         assert unpack("5x", "hello") == ()
+
+
+    def test_struct_error(self):
+        """
+        Check the various ways to get a struct.error.  Note that CPython
+        and PyPy might disagree on the specific exception raised in a
+        specific situation, e.g. struct.error/TypeError/OverflowError.
+        """
+        calcsize = self.struct.calcsize
+        pack = self.struct.pack
+        unpack = self.struct.unpack
+        error = self.struct.error
+        try:
+            calcsize("12")              # incomplete struct format
+        except error:                   # (but ignored on CPython)
+            pass
+        raises(error, calcsize, "[")    # bad char in struct format
+        raises(error, calcsize, "!P")   # bad char in struct format
+        raises(error, pack, "ii", 15)   # struct format requires more arguments
+        raises(error, pack, "i", 3, 4)  # too many arguments for struct format
+        raises(error, unpack, "ii", "?")# unpack str size too short for format
+        raises(error, unpack, "b", "??")# unpack str size too long for format
+        raises(error, pack, "c", "foo") # expected a string of length 1
+        try:
+            pack("0p")                  # bad '0p' in struct format
+        except error:                   # (but ignored on CPython)
+            pass
+        try:
+            unpack("0p", "")            # bad '0p' in struct format
+        except error:                   # (but ignored on CPython)
+            pass
+        raises(error, pack, "b", 150)   # argument out of range
+        # XXX the accepted ranges still differs between PyPy and CPython
+
+
+    def test_overflow_error(self):
+        """
+        Check OverflowError cases.
+        """
+        import sys
+        calcsize = self.struct.calcsize
+        pack = self.struct.pack
+        unpack = self.struct.unpack
+        someerror = (OverflowError, self.struct.error)
+        raises(someerror, calcsize, "%dc" % (sys.maxint+1,))
+        raises(someerror, calcsize, "999999999999999999999999999c")
+        raises(someerror, calcsize, "%di" % (sys.maxint,))
+        raises(someerror, calcsize, "%dcc" % (sys.maxint,))
+        raises(someerror, calcsize, "c%dc" % (sys.maxint,))
+        raises(someerror, calcsize, "%dci" % (sys.maxint,))



More information about the Pypy-commit mailing list