@@ -36,7 +36,7 @@ cdef int DEFAULT_RECURSE_LIMIT=511
36
36
37
37
cdef class Packer(object ):
38
38
""" MessagePack Packer
39
-
39
+
40
40
usage:
41
41
42
42
packer = Packer()
@@ -45,6 +45,10 @@ cdef class Packer(object):
45
45
"""
46
46
cdef msgpack_packer pk
47
47
cdef object _default
48
+ cdef object _bencoding
49
+ cdef object _berrors
50
+ cdef char * encoding
51
+ cdef char * unicode_errors
48
52
49
53
def __cinit__ (self ):
50
54
cdef int buf_size = 1024 * 1024
@@ -54,11 +58,25 @@ cdef class Packer(object):
54
58
self .pk.buf_size = buf_size
55
59
self .pk.length = 0
56
60
57
- def __init__ (self , default = None ):
61
+ def __init__ (self , default = None , encoding = ' utf-8 ' , unicode_errors = ' strict ' ):
58
62
if default is not None :
59
63
if not PyCallable_Check(default):
60
64
raise TypeError (" default must be a callable." )
61
65
self ._default = default
66
+ if encoding is None :
67
+ self .encoding = NULL
68
+ self .unicode_errors = NULL
69
+ else :
70
+ if isinstance (encoding, unicode ):
71
+ self ._bencoding = encoding.encode(' ascii' )
72
+ else :
73
+ self ._bencoding = encoding
74
+ self .encoding = PyBytes_AsString(self ._bencoding)
75
+ if isinstance (unicode_errors, unicode ):
76
+ self ._berrors = unicode_errors.encode(' ascii' )
77
+ else :
78
+ self ._berrors = unicode_errors
79
+ self .unicode_errors = PyBytes_AsString(self ._berrors)
62
80
63
81
def __dealloc__ (self ):
64
82
free(self .pk.buf);
@@ -68,7 +86,7 @@ cdef class Packer(object):
68
86
cdef unsigned long long ullval
69
87
cdef long longval
70
88
cdef double fval
71
- cdef char * rawval
89
+ cdef char * rawval
72
90
cdef int ret
73
91
cdef dict d
74
92
@@ -101,7 +119,9 @@ cdef class Packer(object):
101
119
if ret == 0 :
102
120
ret = msgpack_pack_raw_body(& self .pk, rawval, len (o))
103
121
elif PyUnicode_Check(o):
104
- o = PyUnicode_AsUTF8String(o)
122
+ if not self .encoding:
123
+ raise TypeError (" Can't encode utf-8 no encoding is specified" )
124
+ o = PyUnicode_AsEncodedString(o, self .encoding, self .unicode_errors)
105
125
rawval = o
106
126
ret = msgpack_pack_raw(& self .pk, len (o))
107
127
if ret == 0 :
@@ -138,14 +158,14 @@ cdef class Packer(object):
138
158
return buf
139
159
140
160
141
- def pack (object o , object stream , default = None ):
161
+ def pack (object o , object stream , default = None , encoding = ' utf-8 ' , unicode_errors = ' strict ' ):
142
162
""" pack an object `o` and write it to stream)."""
143
- packer = Packer(default = default)
163
+ packer = Packer(default = default, encoding = encoding, unicode_errors = unicode_errors )
144
164
stream.write(packer.pack(o))
145
165
146
- def packb (object o , default = None ):
166
+ def packb (object o , default = None , encoding = ' utf-8 ' , unicode_errors = ' strict ' ):
147
167
""" pack o and return packed bytes."""
148
- packer = Packer(default = default)
168
+ packer = Packer(default = default, encoding = encoding, unicode_errors = unicode_errors )
149
169
return packer.pack(o)
150
170
151
171
dumps = packs = packb
@@ -155,6 +175,8 @@ cdef extern from "unpack.h":
155
175
int use_list
156
176
PyObject* object_hook
157
177
PyObject* list_hook
178
+ char * encoding
179
+ char * unicode_errors
158
180
159
181
ctypedef struct template_context:
160
182
msgpack_user user
@@ -164,12 +186,12 @@ cdef extern from "unpack.h":
164
186
PyObject* key
165
187
166
188
int template_execute(template_context* ctx, const_char_ptr data,
167
- size_t len , size_t* off)
189
+ size_t len , size_t* off) except - 1
168
190
void template_init(template_context* ctx)
169
191
object template_data(template_context* ctx)
170
192
171
193
172
- def unpackb (object packed , object object_hook = None , object list_hook = None , bint use_list = 0 ):
194
+ def unpackb (object packed , object object_hook = None , object list_hook = None , bint use_list = 0 , encoding = None , unicode_errors = " strict " ):
173
195
""" Unpack packed_bytes to object. Returns an unpacked object."""
174
196
cdef template_context ctx
175
197
cdef size_t off = 0
@@ -179,9 +201,25 @@ def unpackb(object packed, object object_hook=None, object list_hook=None, bint
179
201
cdef Py_ssize_t buf_len
180
202
PyObject_AsReadBuffer(packed, < const_void_ptr* > & buf, & buf_len)
181
203
204
+ if encoding is None :
205
+ enc = NULL
206
+ else :
207
+ if isinstance (encoding, unicode ):
208
+ bencoding = encoding.encode(' ascii' )
209
+ else :
210
+ bencoding = encoding
211
+ if isinstance (unicode_errors, unicode ):
212
+ berrors = unicode_errors.encode(' ascii' )
213
+ else :
214
+ berrors = unicode_errors
215
+ enc = PyBytes_AsString(bencoding)
216
+ err = PyBytes_AsString(berrors)
217
+
182
218
template_init(& ctx)
183
219
ctx.user.use_list = use_list
184
220
ctx.user.object_hook = ctx.user.list_hook = NULL
221
+ ctx.user.encoding = enc
222
+ ctx.user.unicode_errors = err
185
223
if object_hook is not None :
186
224
if not PyCallable_Check(object_hook):
187
225
raise TypeError (" object_hook must be a callable." )
@@ -191,19 +229,21 @@ def unpackb(object packed, object object_hook=None, object list_hook=None, bint
191
229
raise TypeError (" list_hook must be a callable." )
192
230
ctx.user.list_hook = < PyObject* > list_hook
193
231
_gc_disable()
194
- ret = template_execute(& ctx, buf, buf_len, & off)
195
- _gc_enable()
232
+ try :
233
+ ret = template_execute(& ctx, buf, buf_len, & off)
234
+ finally :
235
+ _gc_enable()
196
236
if ret == 1 :
197
237
return template_data(& ctx)
198
238
else :
199
239
return None
200
240
201
241
loads = unpacks = unpackb
202
242
203
- def unpack (object stream , object object_hook = None , object list_hook = None , bint use_list = 0 ):
243
+ def unpack (object stream , object object_hook = None , object list_hook = None , bint use_list = 0 , encoding = None , unicode_errors = " strict " ):
204
244
""" unpack an object from stream."""
205
245
return unpackb(stream.read(), use_list = use_list,
206
- object_hook = object_hook, list_hook = list_hook)
246
+ object_hook = object_hook, list_hook = list_hook, encoding = encoding, unicode_errors = unicode_errors )
207
247
208
248
cdef class Unpacker(object ):
209
249
""" Unpacker(read_size=1024*1024)
@@ -236,7 +276,7 @@ cdef class Unpacker(object):
236
276
self .buf = NULL ;
237
277
238
278
def __init__ (self , file_like = None , Py_ssize_t read_size = 0 , bint use_list = 0 ,
239
- object object_hook = None , object list_hook = None ):
279
+ object object_hook = None , object list_hook = None , encoding = None , unicode_errors = None ):
240
280
if read_size == 0 :
241
281
read_size = 1024 * 1024
242
282
self .use_list = use_list
@@ -292,7 +332,7 @@ cdef class Unpacker(object):
292
332
new_size = tail + _buf_len
293
333
if new_size < buf_size* 2 :
294
334
new_size = buf_size* 2
295
- buf = < char * > realloc(buf, new_size)
335
+ buf = < char * > realloc(buf, new_size)
296
336
if buf == NULL :
297
337
# self.buf still holds old buffer and will be freed during
298
338
# obj destruction
0 commit comments