@@ -201,6 +201,7 @@ cdef extern from "unpack.h":
201
201
ctypedef struct msgpack_user:
202
202
bint use_list
203
203
PyObject* object_hook
204
+ bint has_pairs_hook # call object_hook with k-v pairs
204
205
PyObject* list_hook
205
206
char * encoding
206
207
char * unicode_errors
@@ -213,13 +214,54 @@ cdef extern from "unpack.h":
213
214
PyObject* key
214
215
215
216
int template_execute(template_context* ctx, const_char_ptr data,
216
- size_t len , size_t* off) except - 1
217
+ size_t len , size_t* off, bint construct ) except - 1
217
218
void template_init(template_context* ctx)
218
219
object template_data(template_context* ctx)
219
220
221
+ cdef inline init_ctx(template_context * ctx, object object_hook, object object_pairs_hook, object list_hook, bint use_list, encoding, unicode_errors):
222
+ template_init(ctx)
223
+ ctx.user.use_list = use_list
224
+ ctx.user.object_hook = ctx.user.list_hook = < PyObject* > NULL
225
+
226
+ if object_hook is not None and object_pairs_hook is not None :
227
+ raise ValueError (" object_pairs_hook and object_hook are mutually exclusive." )
228
+
229
+ if object_hook is not None :
230
+ if not PyCallable_Check(object_hook):
231
+ raise TypeError (" object_hook must be a callable." )
232
+ ctx.user.object_hook = < PyObject* > object_hook
233
+
234
+ if object_pairs_hook is None :
235
+ ctx.user.has_pairs_hook = False
236
+ else :
237
+ if not PyCallable_Check(object_pairs_hook):
238
+ raise TypeError (" object_pairs_hook must be a callable." )
239
+ ctx.user.object_hook = < PyObject* > object_pairs_hook
240
+ ctx.user.has_pairs_hook = True
241
+
242
+ if list_hook is not None :
243
+ if not PyCallable_Check(list_hook):
244
+ raise TypeError (" list_hook must be a callable." )
245
+ ctx.user.list_hook = < PyObject* > list_hook
246
+
247
+ if encoding is None :
248
+ ctx.user.encoding = NULL
249
+ ctx.user.unicode_errors = NULL
250
+ else :
251
+ if isinstance (encoding, unicode ):
252
+ _bencoding = encoding.encode(' ascii' )
253
+ else :
254
+ _bencoding = encoding
255
+ ctx.user.encoding = PyBytes_AsString(_bencoding)
256
+ if isinstance (unicode_errors, unicode ):
257
+ _berrors = unicode_errors.encode(' ascii' )
258
+ else :
259
+ _berrors = unicode_errors
260
+ ctx.user.unicode_errors = PyBytes_AsString(_berrors)
220
261
221
262
def unpackb (object packed , object object_hook = None , object list_hook = None ,
222
263
use_list = None , encoding = None , unicode_errors = " strict" ,
264
+ object_pairs_hook = None ,
223
265
):
224
266
""" Unpack packed_bytes to object. Returns an unpacked object.
225
267
@@ -234,39 +276,11 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
234
276
235
277
PyObject_AsReadBuffer(packed, < const_void_ptr* > & buf, & buf_len)
236
278
237
- if encoding is None :
238
- enc = NULL
239
- err = NULL
240
- else :
241
- if isinstance (encoding, unicode ):
242
- bencoding = encoding.encode(' ascii' )
243
- else :
244
- bencoding = encoding
245
- if isinstance (unicode_errors, unicode ):
246
- berrors = unicode_errors.encode(' ascii' )
247
- else :
248
- berrors = unicode_errors
249
- enc = PyBytes_AsString(bencoding)
250
- err = PyBytes_AsString(berrors)
251
-
252
- template_init(& ctx)
253
279
if use_list is None :
254
280
warnings.warn(" Set use_list explicitly." , category = DeprecationWarning , stacklevel = 1 )
255
- ctx.user.use_list = 0
256
- else :
257
- ctx.user.use_list = use_list
258
- ctx.user.object_hook = ctx.user.list_hook = NULL
259
- ctx.user.encoding = < const_char_ptr> enc
260
- ctx.user.unicode_errors = < const_char_ptr> err
261
- if object_hook is not None :
262
- if not PyCallable_Check(object_hook):
263
- raise TypeError (" object_hook must be a callable." )
264
- ctx.user.object_hook = < PyObject* > object_hook
265
- if list_hook is not None :
266
- if not PyCallable_Check(list_hook):
267
- raise TypeError (" list_hook must be a callable." )
268
- ctx.user.list_hook = < PyObject* > list_hook
269
- ret = template_execute(& ctx, buf, buf_len, & off)
281
+ use_list = 0
282
+ init_ctx(& ctx, object_hook, object_pairs_hook, list_hook, use_list, encoding, unicode_errors)
283
+ ret = template_execute(& ctx, buf, buf_len, & off, 1 )
270
284
if ret == 1 :
271
285
obj = template_data(& ctx)
272
286
if off < buf_len:
@@ -278,6 +292,7 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
278
292
279
293
def unpack (object stream , object object_hook = None , object list_hook = None ,
280
294
use_list = None , encoding = None , unicode_errors = " strict" ,
295
+ object_pairs_hook = None ,
281
296
):
282
297
""" Unpack an object from `stream`.
283
298
@@ -287,7 +302,7 @@ def unpack(object stream, object object_hook=None, object list_hook=None,
287
302
warnings.warn(" Set use_list explicitly." , category = DeprecationWarning , stacklevel = 1 )
288
303
use_list = 0
289
304
return unpackb(stream.read(), use_list = use_list,
290
- object_hook = object_hook, list_hook = list_hook,
305
+ object_hook = object_hook, object_pairs_hook = object_pairs_hook, list_hook = list_hook,
291
306
encoding = encoding, unicode_errors = unicode_errors,
292
307
)
293
308
@@ -307,7 +322,10 @@ cdef class Unpacker(object):
307
322
Otherwise, it is deserialized to Python tuple.
308
323
309
324
`object_hook` is same to simplejson. If it is not None, it should be callable
310
- and Unpacker calls it when deserializing key-value.
325
+ and Unpacker calls it with a dict argument after deserializing a map.
326
+
327
+ `object_pairs_hook` is same to simplejson. If it is not None, it should be callable
328
+ and Unpacker calls it with a list of key-value pairs after deserializing a map.
311
329
312
330
`encoding` is encoding used for decoding msgpack bytes. If it is None (default),
313
331
msgpack bytes is deserialized to Python bytes.
@@ -357,9 +375,8 @@ cdef class Unpacker(object):
357
375
self .buf = NULL
358
376
359
377
def __init__ (self , file_like = None , Py_ssize_t read_size = 0 , use_list = None ,
360
- object object_hook = None , object list_hook = None ,
378
+ object object_hook = None , object object_pairs_hook = None , object list_hook = None ,
361
379
encoding = None , unicode_errors = ' strict' , int max_buffer_size = 0 ,
362
- object object_pairs_hook = None ,
363
380
):
364
381
if use_list is None :
365
382
warnings.warn(" Set use_list explicitly." , category = DeprecationWarning , stacklevel = 1 )
@@ -384,31 +401,7 @@ cdef class Unpacker(object):
384
401
self .buf_size = read_size
385
402
self .buf_head = 0
386
403
self .buf_tail = 0
387
- template_init(& self .ctx)
388
- self .ctx.user.use_list = use_list
389
- self .ctx.user.object_hook = self .ctx.user.list_hook = < PyObject* > NULL
390
- if object_hook is not None :
391
- if not PyCallable_Check(object_hook):
392
- raise TypeError (" object_hook must be a callable." )
393
- self .ctx.user.object_hook = < PyObject* > object_hook
394
- if list_hook is not None :
395
- if not PyCallable_Check(list_hook):
396
- raise TypeError (" list_hook must be a callable." )
397
- self .ctx.user.list_hook = < PyObject* > list_hook
398
- if encoding is None :
399
- self .ctx.user.encoding = NULL
400
- self .ctx.user.unicode_errors = NULL
401
- else :
402
- if isinstance (encoding, unicode ):
403
- self ._bencoding = encoding.encode(' ascii' )
404
- else :
405
- self ._bencoding = encoding
406
- self .ctx.user.encoding = PyBytes_AsString(self ._bencoding)
407
- if isinstance (unicode_errors, unicode ):
408
- self ._berrors = unicode_errors.encode(' ascii' )
409
- else :
410
- self ._berrors = unicode_errors
411
- self .ctx.user.unicode_errors = PyBytes_AsString(self ._berrors)
404
+ init_ctx(& self .ctx, object_hook, object_pairs_hook, list_hook, use_list, encoding, unicode_errors)
412
405
413
406
def feed (self , object next_bytes ):
414
407
cdef char * buf
@@ -469,15 +462,18 @@ cdef class Unpacker(object):
469
462
else :
470
463
self .file_like = None
471
464
472
- cpdef unpack(self ):
473
- """ unpack one object"""
465
+ cdef object _unpack(self , bint construct):
474
466
cdef int ret
467
+ cdef object obj
475
468
while 1 :
476
- ret = template_execute(& self .ctx, self .buf, self .buf_tail, & self .buf_head)
469
+ ret = template_execute(& self .ctx, self .buf, self .buf_tail, & self .buf_head, construct )
477
470
if ret == 1 :
478
- o = template_data(& self .ctx)
471
+ if construct:
472
+ obj = template_data(& self .ctx)
473
+ else :
474
+ obj = None
479
475
template_init(& self .ctx)
480
- return o
476
+ return obj
481
477
elif ret == 0 :
482
478
if self .file_like is not None :
483
479
self .read_from_file()
@@ -486,11 +482,19 @@ cdef class Unpacker(object):
486
482
else :
487
483
raise ValueError (" Unpack failed: error = %d " % (ret,))
488
484
485
+ def unpack (self ):
486
+ """ unpack one object"""
487
+ return self ._unpack(1 )
488
+
489
+ def skip (self ):
490
+ """ read and ignore one object, returning None"""
491
+ return self ._unpack(0 )
492
+
489
493
def __iter__ (self ):
490
494
return self
491
495
492
496
def __next__ (self ):
493
- return self .unpack( )
497
+ return self ._unpack( 1 )
494
498
495
499
# for debug.
496
500
# def _buf(self):
0 commit comments