8000 [WIP] Newspec stage 2. by methane · Pull Request #79 · msgpack/msgpack-python · GitHub
[go: up one dir, main page]

Skip to content

[WIP] Newspec stage 2. #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Oct 20, 2013
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d610975
add support for extended types: you can now pack/unpack custom python…
antocuni Oct 15, 2013
5529dfe
kill some duplicate code from unpack/unpackb and move the logic to Un…
antocuni Oct 18, 2013
522c4bf
slightly change to API
antocuni Oct 18, 2013
c727440
automatically find the best format to encode extended types
antocuni Oct 18, 2013
afa28fb
add support to unpack all ext formats
antocuni Oct 18, 2013
5467515
implement Packer.pack_extended_type also in the cython version of the…
antocuni Oct 18, 2013
a7485ec
add the hook for unknown types also to the cython Packer
antocuni Oct 18, 2013
ff85838
implement unpack_one also for the cython version, and add a test for it
antocuni Oct 18, 2013
985d4c1
add a test for unpacking extended types
antocuni Oct 19, 2013
56dd165
implement unpacking for all the fixtext formats
antocuni Oct 19, 2013
c9b97f0
implement unpacking of ext 8,16,32
antocuni Oct 19, 2013
6386481
add a note in the README
antocuni Oct 19, 2013
27f0cba
Merge branch 'master' of https://github.com/antocuni/msgpack-python i…
methane Oct 20, 2013
aa68c9b
fallback: Support pack_ext_type.
methane Oct 20, 2013
96bcd76
Packing ExtType and some cleanup
methane Oct 20, 2013
822cce8
Support unpacking new types.
methane Oct 20, 2013
0d5c58b
cleanup
methane Oct 20, 2013
84dc99c
Add ext_type example to README.
methane Oct 20, 2013
cb78959
Update README.
methane Oct 20, 2013
37c2ad6
Add tests and bugfix.
methane Oct 20, 2013
e3fee4d
fallback: support packing ExtType
methane Oct 20, 2013
d84a403
fix bugs.
methane Oct 20, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Packing ExtType and some cleanup
  • Loading branch information
methane committed Oct 20, 2013
commit 96bcd76f49afd00f5b7def1ff7cfd002a7fa477d
2 changes: 1 addition & 1 deletion msgpack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def pack(o, stream, **kwargs):
packer = Packer(**kwargs)
stream.write(packer.pack(o))


def packb(o, **kwargs):
"""
Pack object `o` and return packed bytes
Expand All @@ -40,4 +41,3 @@ def packb(o, **kwargs):

dump = pack
dumps = packb

150 changes: 78 additions & 72 deletions msgpack/_packer.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ from libc.limits cimport *
from libc.stdint cimport int8_t

from msgpack.exceptions import PackValueError
from msgpack import ExtType


cdef extern from "pack.h":
struct msgpack_packer:
Expand Down Expand Up @@ -120,80 +122,87 @@ cdef class Packer(object):
cdef int ret
cdef dict d
cdef size_t L
cdef int default_used = 0

if nest_limit < 0:
raise PackValueError("recursion limit exceeded.")

if o is None:
ret = msgpack_pack_nil(&self.pk)
elif isinstance(o, bool):
if o:
ret = msgpack_pack_true(&self.pk)
else:
ret = msgpack_pack_false(&self.pk)
elif PyLong_Check(o):
if o > 0:
ullval = o
ret = msgpack_pack_unsigned_long_long(&self.pk, ullval)
else:
llval = o
ret = msgpack_pack_long_long(&self.pk, llval)
elif PyInt_Check(o):
longval = o
ret = msgpack_pack_long(&self.pk, longval)
elif PyFloat_Check(o):
if self.use_float:
fval = o
ret = msgpack_pack_float(&self.pk, fval)
else:
dval = o
ret = msgpack_pack_double(&self.pk, dval)
elif PyBytes_Check(o):
rawval = o
L = len(o)
ret = msgpack_pack_bin(&self.pk, L)
if ret == 0:
while True:
if o is None:
ret = msgpack_pack_nil(&self.pk)
elif isinstance(o, bool):
if o:
ret = msgpack_pack_true(&self.pk)
else:
ret = msgpack_pack_false(&self.pk)
elif PyLong_Check(o):
if o > 0:
ullval = o
ret = msgpack_pack_unsigned_long_long(&self.pk, ullval)
else:
llval = o
ret = msgpack_pack_long_long(&self.pk, llval)
elif PyInt_Check(o):
longval = o
ret = msgpack_pack_long(&self.pk, longval)
elif PyFloat_Check(o):
if self.use_float:
fval = o
ret = msgpack_pack_float(&self.pk, fval)
else:
dval = o
ret = msgpack_pack_double(&self.pk, dval)
elif PyBytes_Check(o):
rawval = o
L = len(o)
ret = msgpack_pack_bin(&self.pk, L)
if ret == 0:
ret = msgpack_pack_raw_body(&self.pk, rawval, L)
elif PyUnicode_Check(o):
if not self.encoding:
raise TypeError("Can't encode unicode string: no encoding is specified")
o = PyUnicode_AsEncodedString(o, self.encoding, self.unicode_errors)
rawval = o
ret = msgpack_pack_raw(&self.pk, len(o))
if ret == 0:
ret = msgpack_pack_raw_body(&self.pk, rawval, len(o))
elif PyDict_CheckExact(o):
d = <dict>o
ret = msgpack_pack_map(&self.pk, len(d))
if ret == 0:
for k, v in d.iteritems():
ret = self._pack(k, nest_limit-1)
if ret != 0: break
ret = self._pack(v, nest_limit-1)
if ret != 0: break
elif PyDict_Check(o):
ret = msgpack_pack_map(&self.pk, len(o))
if ret == 0:
for k, v in o.items():
ret = self._pack(k, nest_limit-1)
if ret != 0: break
ret = self._pack(v, nest_limit-1)
if ret != 0: break
elif isinstance(o, ExtType):
# This should be before Tuple because ExtType is namedtuple.
longval = o[0]
rawval = o[1]
L = len(o[1])
ret = msgpack_pack_ext(&self.pk, longval, L)
ret = msgpack_pack_raw_body(&self.pk, rawval, L)
elif PyUnicode_Check(o):
if not self.encoding:
raise TypeError("Can't encode unicode string: no encoding is specified")
o = PyUnicode_AsEncodedString(o, self.encoding, self.unicode_errors)
rawval = o
ret = msgpack_pack_raw(&self.pk, len(o))
if ret == 0:
ret = msgpack_pack_raw_body(&self.pk, rawval, len(o))
elif PyDict_CheckExact(o):
d = <dict>o
ret = msgpack_pack_map(&self.pk, len(d))
if ret == 0:
for k, v in d.iteritems():
ret = self._pack(k, nest_limit-1)
if ret != 0: break
ret = self._pack(v, nest_limit-1)
if ret != 0: break
elif PyDict_Check(o):
ret = msgpack_pack_map(&self.pk, len(o))
if ret == 0:
for k, v in o.items():
ret = self._pack(k, nest_limit-1)
if ret != 0: break
ret = self._pack(v, nest_limit-1)
if ret != 0: break
elif PyTuple_Check(o) or PyList_Check(o):
ret = msgpack_pack_array(&self.pk, len(o))
if ret == 0:
for v in o:
ret = self._pack(v, nest_limit-1)
if ret != 0: break
elif self.handle_unknown_type(o):
# it means that obj was succesfully packed, so we are done
return 0
elif self._default:
o = self._default(o)
ret = self._pack(o, nest_limit-1)
else:
raise TypeError("can't serialize %r" % (o,))
return ret
elif PyTuple_Check(o) or PyList_Check(o):
ret = msgpack_pack_array(&self.pk, len(o))
if ret == 0:
for v in o:
ret = self._pack(v, nest_limit-1)
if ret != 0: break
elif not default_used and self._default:
o = self._default(o)
default_used = 1
continue
else:
raise TypeError("can't serialize %r" % (o,))
return ret

cpdef pack(self, object obj):
cdef int ret
Expand All @@ -207,9 +216,6 @@ cdef class Packer(object):
self.pk.length = 0
return buf

def handle_unknown_type(self, obj):
return None

def pack_ext_type(self, typecode, data):
msgpack_pack_ext(&self.pk, typecode, len(data))
msgpack_pack_raw_body(&self.pk, data, len(data))
Expand Down
49 changes: 13 additions & 36 deletions msgpack/_unpacker.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ from msgpack.exceptions import (
UnpackValueError,
ExtraData,
)
from msgpack import ExtType


cdef extern from "unpack.h":
Expand All @@ -24,7 +25,7 @@ cdef extern from "unpack.h":
PyObject* object_hook
bint has_pairs_hook # call object_hook with k-v pairs
PyObject* list_hook
PyObject* ext_type_hook
PyObject* ext_hook
char *encoding
char *unicode_errors

Expand All @@ -43,8 +44,8 @@ cdef extern from "unpack.h":
object unpack_data(unpack_context* ctx)

cdef inline init_ctx(unpack_context *ctx,
object object_hook, object object_pairs_hook, object list_hook,
object ext_type_hook,
object object_hook, object object_pairs_hook,
object list_hook, object ext_hook,
bint use_list, char* encoding, char* unicode_errors):
unpack_init(ctx)
ctx.user.use_list = use_list
Expand All @@ -71,10 +72,10 @@ cdef inline init_ctx(unpack_context *ctx,
raise TypeError("list_hook must be a callable.")
ctx.user.list_hook = <PyObject*>list_hook

if ext_type_hook is not None:
if not PyCallable_Check(ext_type_hook):
raise TypeError("ext_type_hook must be a callable.")
ctx.user.ext_type_hook = <PyObject*>ext_type_hook
if ext_hook is not None:
if not PyCallable_Check(ext_hook):
raise TypeError("ext_hook must be a callable.")
ctx.user.ext_hook = <PyObject*>ext_hook

ctx.user.encoding = encoding
ctx.user.unicode_errors = unicode_errors
Expand All @@ -84,8 +85,7 @@ def default_read_extended_type(typecode, data):

def unpackb(object packed, object object_hook=None, object list_hook=None,
bint use_list=1, encoding=None, unicode_errors="strict",
object_pairs_hook=None,
):
object_pairs_hook=None, ext_hook=ExtType):
"""
Unpack packed_bytes to object. Returns an unpacked object.

Expand Down Expand Up @@ -114,8 +114,8 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
unicode_errors = unicode_errors.encode('ascii')
cerr = PyBytes_AsString(unicode_errors)

init_ctx(&ctx, object_hook, object_pairs_hook, list_hook, default_read_extended_type,
use_list, cenc, cerr)
init_ctx(&ctx, object_hook, object_pairs_hook, list_hook, ext_hook,
use_list, cenc, cerr)
ret = unpack_construct(&ctx, buf, buf_len, &off)
if ret == 1:
obj = unpack_data(&ctx)
Expand Down Expand Up @@ -220,7 +220,7 @@ cdef class Unpacker(object):
def __init__(self, file_like=None, Py_ssize_t read_size=0, bint use_list=1,
object object_hook=None, object object_pairs_hook=None, object list_hook=None,
str encoding=None, str unicode_errors='strict', int max_buffer_size=0,
):
object ext_hook=ExtType):
cdef char *cenc=NULL, *cerr=NULL

self.file_like = file_like
Expand Down Expand Up @@ -257,10 +257,8 @@ cdef class Unpacker(object):
self.unicode_errors = unicode_errors
cerr = PyBytes_AsString(self.unicode_errors)

ext_type_hook = self.read_extended_type
Py_INCREF(ext_type_hook)
init_ctx(&self.ctx, object_hook, object_pairs_hook, list_hook,
ext_type_hook, use_list, cenc, cerr)
ext_hook, use_list, cenc, cerr)

def feed(self, object next_bytes):
"""Append `next_bytes` to internal buffer."""
Expand Down Expand Up @@ -370,24 +368,6 @@ cdef class Unpacker(object):
"""
return self._unpack(unpack_construct, write_bytes)

def unpack_one(self, object write_bytes=None):
"""
unpack one object

If write_bytes is not None, it will be called with parts of the raw
message as it is unpacked.

Raises `UnpackValueError` if there are no more bytes to unpack.
Raises ``ExtraData`` if there are still bytes left after the unpacking.
"""
try:
result = self.unpack()
except OutOfData:
raise UnpackValueError("Data is not enough")
if self.buf_head < self.buf_tail:
raise ExtraData(result, self.buf[self.buf_head:])
return result

def skip(self, object write_bytes=None):
"""
read and ignore one object, returning None
Expand Down Expand Up @@ -415,9 +395,6 @@ cdef class Unpacker(object):
"""
return self._unpack(read_map_header, write_bytes)

def read_extended_type(self, typecode, data):
return default_read_extended_type(typecode, data)

def __iter__(self):
return self

Expand Down
3 changes: 1 addition & 2 deletions msgpack/pack_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ static inline int msgpack_pack_raw(msgpack_packer* x, size_t l)
static inline int msgpack_pack_bin(msgpack_packer *x, size_t l)
{
if (!x->use_bin_type) {
return msgpack_pack_raw(x, l)
return msgpack_pack_raw(x, l);
}
if (l < 256) {
unsigned char buf[2] = {0xc4, (unsigned char)l};
Expand All @@ -711,7 +711,6 @@ static inline int msgpack_pack_raw_body(msgpack_packer* x, const void* b, size_t
/*
* Ext
*/

static inline int msgpack_pack_ext(msgpack_packer* x, int8_t typecode, size_t l)
{
if (l == 1) {
Expand Down
10 changes: 5 additions & 5 deletions msgpack/unpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ typedef struct unpack_user {
PyObject *object_hook;
bool has_pairs_hook;
PyObject *list_hook;
PyObject *ext_type_hook;
PyObject *ext_hook;
const char *encoding;
const char *unicode_errors;
} unpack_user;
Expand Down Expand Up @@ -241,12 +241,12 @@ static inline int unpack_callback_ext(unpack_user* u, const char* base, const ch
{
PyObject *py;
int8_t typecode = (int8_t)*pos++;
if (!u->ext_type_hook) {
PyErr_SetString(PyExc_AssertionError, "u->ext_type_hook cannot be NULL");
if (!u->ext_hook) {
PyErr_SetString(PyExc_AssertionError, "u->ext_hook cannot be NULL");
return -1;
}
// lenght also includes the typecode, so the actual data is lenght-1
py = PyEval_CallFunction(u->ext_type_hook, "(is#)", typecode, pos, lenght-1);
// length also includes the typecode, so the actual data is lenght-1
py = PyEval_CallFunction(u->ext_hook, "(is#)", typecode, pos, lenght-1);
if (!py)
return -1;
*o = py;
Expand Down
Loading
0