@@ -69,6 +69,13 @@ def getvalue(self):
69
69
DEFAULT_RECURSE_LIMIT = 511
70
70
71
71
72
+ def _check_type_strict (obj , t , type = type , tuple = tuple ):
73
+ if type (t ) is tuple :
74
+ return type (obj ) in t
75
+ else :
76
+ return type (obj ) is t
77
+
78
+
72
79
def unpack (stream , ** kwargs ):
73
80
"""
74
81
Unpack an object from `stream`.
@@ -609,9 +616,18 @@ class Packer(object):
609
616
:param bool use_bin_type:
610
617
Use bin type introduced in msgpack spec 2.0 for bytes.
611
618
It also enable str8 type for unicode.
619
+ :param bool strict_types:
620
+ If set to true, types will be checked to be exact. Derived classes
621
+ from serializeable types will not be serialized and will be
622
+ treated as unsupported type and forwarded to default.
623
+ Additionally tuples will not be serialized as lists.
624
+ This is useful when trying to implement accurate serialization
625
+ for python types.
612
626
"""
613
627
def __init__ (self , default = None , encoding = 'utf-8' , unicode_errors = 'strict' ,
614
- use_single_float = False , autoreset = True , use_bin_type = False ):
628
+ use_single_float = False , autoreset = True , use_bin_type = False ,
629
+ strict_types = False ):
630
+ self ._strict_types = strict_types
615
631
self ._use_float = use_single_float
616
632
self ._autoreset = autoreset
617
633
self ._use_bin_type = use_bin_type
@@ -623,18 +639,24 @@ def __init__(self, default=None, encoding='utf-8', unicode_errors='strict',
623
639
raise TypeError ("default must be callable" )
624
640
self ._default = default
625
641
626
- def _pack (self , obj , nest_limit = DEFAULT_RECURSE_LIMIT , isinstance = isinstance ):
642
+ def _pack (self , obj , nest_limit = DEFAULT_RECURSE_LIMIT ,
643
+ check = isinstance , check_type_strict = _check_type_strict ):
627
644
default_used = False
645
+ if self ._strict_types :
646
+ check = check_type_strict
647
+ list_types = list
648
+ else :
649
+ list_types = (list , tuple )
628
650
while True :
629
651
if nest_limit < 0 :
630
652
raise PackValueError ("recursion limit exceeded" )
631
653
if obj is None :
632
654
return self ._buffer .write (b"\xc0 " )
633
- if isinstance (obj , bool ):
655
+ if check (obj , bool ):
634
656
if obj :
635
657
return self ._buffer .write (b"\xc3 " )
636
658
return self ._buffer .write (b"\xc2 " )
637
- if isinstance (obj , int_types ):
659
+ if check (obj , int_types ):
638
660
if 0 <= obj < 0x80 :
639
661
return self ._buffer .write (struct .pack ("B" , obj ))
640
662
if - 0x20 <= obj < 0 :
@@ -660,7 +682,7 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
660
682
default_used = True
661
683
continue
662
684
raise PackValueError ("Integer value out of range" )
663
- if self ._use_bin_type and isinstance (obj , bytes ):
685
+ if self ._use_bin_type and check (obj , bytes ):
664
686
n = len (obj )
665
687
if n <= 0xff :
666
688
self ._buffer .write (struct .pack ('>BB' , 0xc4 , n ))
@@ -671,8 +693,8 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
671
693
else :
672
694
raise PackValueError ("Bytes is too large" )
673
695
return self ._buffer .write (obj )
674
- if isinstance (obj , (Unicode , bytes )):
675
- if isinstance (obj , Unicode ):
696
+ if check (obj , (Unicode , bytes )):
697
+ if check (obj , Unicode ):
676
698
if self ._encoding is None :
677
699
raise TypeError (
678
700
"Can't encode unicode string: "
@@ -690,11 +712,11 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
690
712
else :
691
713
raise PackValueError ("String is too large" )
692
714
return self ._buffer .write (obj )
693
- if isinstance (obj , float ):
715
+ if check (obj , float ):
694
716
if self ._use_float :
695
717
return self ._buffer .write (struct .pack (">Bf" , 0xca , obj ))
696
718
return self ._buffer .write (struct .pack (">Bd" , 0xcb , obj ))
697
- if isinstance (obj , ExtType ):
719
+ if check (obj , ExtType ):
698
720
code = obj .code
699
721
data = obj .data
700
722
assert isinstance (code , int )
@@ -719,13 +741,13 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
719
741
self ._buffer .write (struct .pack ("b" , code ))
720
742
self ._buffer .write (data )
721
743
return
722
- if isinstance (obj , ( list , tuple ) ):
744
+ if check (obj , list_types ):
723
745
n = len (obj )
724
746
self ._fb_pack_array_header (n )
725
747
for i in xrange (n ):
726
748
self ._pack (obj [i ], nest_limit - 1 )
727
749
return
728
- if isinstance (obj , dict ):
750
+ if check (obj , dict ):
729
751
return self ._fb_pack_map_pairs (len (obj ), dict_iteritems (obj ),
730
752
nest_limit - 1 )
731
753
if not default_used and self ._default is not None :
0 commit comments