Skip to content

Commit 8d32bef

Browse files
Stephen PascoeStephen Pascoe
authored andcommitted
Option to create canonical packing by sorting dictionary keys.
1 parent d72bd0c commit 8d32bef

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

msgpack/_msgpack.pyx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ cdef class Packer(object):
5050
cdef object _berrors
5151
cdef char *encoding
5252
cdef char *unicode_errors
53+
cdef bool _canonical
5354

5455
def __cinit__(self):
5556
cdef int buf_size = 1024*1024
@@ -59,7 +60,8 @@ cdef class Packer(object):
5960
self.pk.buf_size = buf_size
6061
self.pk.length = 0
6162

62-
def __init__(self, default=None, encoding='utf-8', unicode_errors='strict'):
63+
def __init__(self, default=None, encoding='utf-8', unicode_errors='strict',
64+
canonical=False):
6365
if default is not None:
6466
if not PyCallable_Check(default):
6567
raise TypeError("default must be a callable.")
@@ -79,6 +81,8 @@ cdef class Packer(object):
7981
self._berrors = unicode_errors
8082
self.unicode_errors = PyBytes_AsString(self._berrors)
8183

84+
self._canonical = canonical
85+
8286
def __dealloc__(self):
8387
free(self.pk.buf);
8488

@@ -131,11 +135,20 @@ cdef class Packer(object):
131135
d = o
132136
ret = msgpack_pack_map(&self.pk, len(d))
133137
if ret == 0:
134-
for k,v in d.items():
135-
ret = self._pack(k, nest_limit-1)
136-
if ret != 0: break
137-
ret = self._pack(v, nest_limit-1)
138-
if ret != 0: break
138+
if self._canonical:
139+
# Unfortunately can't use d.items() because a closure would
140+
# be required
141+
for k in sorted(d.keys()):
142+
ret = self._pack(k, nest_limit-1)
143+
if ret != 0: break
144+
ret = self._pack(d[k], nest_limit-1)
145+
if ret != 0: break
146+
else:
147+
for k,v in d.items():
148+
ret = self._pack(k, nest_limit-1)
149+
if ret != 0: break
150+
ret = self._pack(v, nest_limit-1)
151+
if ret != 0: break
139152
elif PySequence_Check(o):
140153
ret = msgpack_pack_array(&self.pk, len(o))
141154
if ret == 0:
@@ -159,16 +172,16 @@ cdef class Packer(object):
159172
return buf
160173

161174

162-
def pack(object o, object stream, default=None, encoding='utf-8', unicode_errors='strict'):
175+
def pack(object o, object stream, default=None, encoding='utf-8', unicode_errors='strict', canonical=False):
163176
"""
164177
pack an object `o` and write it to stream)."""
165-
packer = Packer(default=default, encoding=encoding, unicode_errors=unicode_errors)
178+
packer = Packer(default=default, encoding=encoding, unicode_errors=unicode_errors, canonical=canonical)
166179
stream.write(packer.pack(o))
167180

168-
def packb(object o, default=None, encoding='utf-8', unicode_errors='strict'):
181+
def packb(object o, default=None, encoding='utf-8', unicode_errors='strict', canonical=False):
169182
"""
170183
pack o and return packed bytes."""
171-
packer = Packer(default=default, encoding=encoding, unicode_errors=unicode_errors)
184+
packer = Packer(default=default, encoding=encoding, unicode_errors=unicode_errors, canonical=canonical)
172185
return packer.pack(o)
173186

174187

0 commit comments

Comments
 (0)