diff options
-rw-r--r-- | README.rst | 6 | ||||
-rw-r--r-- | msgpack/_msgpack.pyx | 50 | ||||
-rw-r--r-- | msgpack/exceptions.py | 23 | ||||
-rw-r--r-- | test/test_read_size.py | 6 | ||||
-rw-r--r-- | test/test_sequnpack.py | 5 |
5 files changed, 72 insertions, 18 deletions
@@ -19,9 +19,15 @@ writing MessagePack data. NOTE for msgpack 0.2.x users ---------------------------- +The msgpack 0.3 have some incompatible changes. + The default value of ``use_list`` keyword argument is ``True`` from 0.3.x. You should pass the argument explicitly for backward compatibility. +`Unpacker.unpack()` and some unpack methods now raises `OutOfData` +instead of `StopIteration`. +`StopIteration` is used for iterator protocol only. + HOW TO USE ----------- diff --git a/msgpack/_msgpack.pyx b/msgpack/_msgpack.pyx index 5c202fc..52d63cc 100644 --- a/msgpack/_msgpack.pyx +++ b/msgpack/_msgpack.pyx @@ -38,8 +38,12 @@ cdef extern from "pack.h": cdef int DEFAULT_RECURSE_LIMIT=511 -class BufferFull(Exception): - pass +from msgpack.exceptions import ( + BufferFull, + OutOfData, + UnpackValueError, + ExtraData, + ) cdef class Packer(object): @@ -102,7 +106,7 @@ cdef class Packer(object): cdef dict d if nest_limit < 0: - raise ValueError("Too deep.") + raise UnpackValueError("recursion limit exceeded.") if o is None: ret = msgpack_pack_nil(&self.pk) @@ -174,7 +178,9 @@ cdef class Packer(object): cpdef pack(self, object obj): cdef int ret ret = self._pack(obj, DEFAULT_RECURSE_LIMIT) - if ret: + if ret == -1: + raise MemoryError + elif ret: # should not happen. raise TypeError buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length) self.pk.length = 0 @@ -296,7 +302,7 @@ def unpackb(object packed, object object_hook=None, object list_hook=None, if ret == 1: obj = template_data(&ctx) if off < buf_len: - raise ValueError("Extra data.") + raise ExtraData(obj, PyBytes_FromStringAndSize(buf+off, buf_len-off)) return obj else: return None @@ -421,11 +427,12 @@ cdef class Unpacker(object): init_ctx(&self.ctx, object_hook, object_pairs_hook, list_hook, use_list, cenc, cerr) def feed(self, object next_bytes): + """Append `next_bytes` to internal buffer.""" cdef char* buf cdef Py_ssize_t buf_len if self.file_like is not None: raise AssertionError( - "unpacker.feed() is not be able to use with`file_like`.") + "unpacker.feed() is not be able to use with `file_like`.") PyObject_AsReadBuffer(next_bytes, <const_void_ptr*>&buf, &buf_len) self.append_buffer(buf, buf_len) @@ -479,7 +486,7 @@ cdef class Unpacker(object): else: self.file_like = None - cdef object _unpack(self, execute_fn execute, object write_bytes): + cdef object _unpack(self, execute_fn execute, object write_bytes, bint iter=0): cdef int ret cdef object obj cdef size_t prev_head @@ -497,7 +504,10 @@ cdef class Unpacker(object): if self.file_like is not None: self.read_from_file() continue - raise StopIteration("No more data to unpack.") + if iter: + raise StopIteration("No more data to unpack.") + else: + raise OutOfData("No more data to unpack.") else: raise ValueError("Unpack failed: error = %d" % (ret,)) @@ -515,7 +525,10 @@ cdef class Unpacker(object): """ unpack one object - If write_bytes is not None, it will be called with parts of the raw message as it is unpacked. + If write_bytes is not None, it will be called with parts of the raw + message as it is unpacked. + + Raises `OutOfData` when there are no more bytes to unpack. """ return self._unpack(template_construct, write_bytes) @@ -523,23 +536,34 @@ cdef class Unpacker(object): """ read and ignore one object, returning None - If write_bytes is not None, it will be called with parts of the raw message as it is unpacked. + If write_bytes is not None, it will be called with parts of the raw + message as it is unpacked. + + Raises `OutOfData` when there are no more bytes to unpack. """ return self._unpack(template_skip, write_bytes) def read_array_header(self, object write_bytes=None): - """assuming the next object is an array, return its size n, such that the next n unpack() calls will iterate over its contents.""" + """assuming the next object is an array, return its size n, such that + the next n unpack() calls will iterate over its contents. + + Raises `OutOfData` when there are no more bytes to unpack. + """ return self._unpack(read_array_header, write_bytes) def read_map_header(self, object write_bytes=None): - """assuming the next object is a map, return its size n, such that the next n * 2 unpack() calls will iterate over its key-value pairs.""" + """assuming the next object is a map, return its size n, such that the + next n * 2 unpack() calls will iterate over its key-value pairs. + + Raises `OutOfData` when there are no more bytes to unpack. + """ return self._unpack(read_map_header, write_bytes) def __iter__(self): return self def __next__(self): - return self._unpack(template_construct, None) + return self._unpack(template_construct, None, 1) # for debug. #def _buf(self): diff --git a/msgpack/exceptions.py b/msgpack/exceptions.py new file mode 100644 index 0000000..0a75430 --- /dev/null +++ b/msgpack/exceptions.py @@ -0,0 +1,23 @@ +class UnpackException(Exception): + pass + + +class BufferFull(UnpackException): + pass + + +class OutOfData(UnpackException): + pass + + +class UnpackValueError(UnpackException, ValueError): + pass + + +class ExtraData(ValueError): + def __init__(self, unpacked, extra): + self.unpacked = unpacked + self.extra = extra + + def __str__(self): + return "unpack(b) recieved extra data." diff --git a/test/test_read_size.py b/test/test_read_size.py index e130805..4e6c2b9 100644 --- a/test/test_read_size.py +++ b/test/test_read_size.py @@ -1,5 +1,5 @@ """Test Unpacker's read_array_header and read_map_header methods""" -from msgpack import packb, Unpacker +from msgpack import packb, Unpacker, OutOfData UnexpectedTypeException = ValueError def test_read_array_header(): @@ -12,7 +12,7 @@ def test_read_array_header(): try: unpacker.unpack() assert 0, 'should raise exception' - except StopIteration: + except OutOfData: assert 1, 'okay' @@ -25,7 +25,7 @@ def test_read_map_header(): try: unpacker.unpack() assert 0, 'should raise exception' - except StopIteration: + except OutOfData: assert 1, 'okay' def test_incorrect_type_array(): diff --git a/test/test_sequnpack.py b/test/test_sequnpack.py index 769f3ff..f767726 100644 --- a/test/test_sequnpack.py +++ b/test/test_sequnpack.py @@ -3,6 +3,7 @@ import six from msgpack import Unpacker, BufferFull +from msgpack.exceptions import OutOfData import nose def test_foobar(): @@ -17,7 +18,7 @@ def test_foobar(): try: o = unpacker.unpack() assert 0, "should raise exception" - except StopIteration: + except OutOfData: assert 1, "ok" unpacker.feed(b'foo') @@ -41,7 +42,7 @@ def test_foobar_skip(): try: o = unpacker.unpack() assert 0, "should raise exception" - except StopIteration: + except OutOfData: assert 1, "ok" def test_maxbuffersize(): |