summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.rst6
-rw-r--r--msgpack/_msgpack.pyx50
-rw-r--r--msgpack/exceptions.py23
-rw-r--r--test/test_read_size.py6
-rw-r--r--test/test_sequnpack.py5
5 files changed, 72 insertions, 18 deletions
diff --git a/README.rst b/README.rst
index aa447f3..270b8ff 100644
--- a/README.rst
+++ b/README.rst
@@ -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():