@@ -69,6 +69,13 @@ def getvalue(self):
6969DEFAULT_RECURSE_LIMIT = 511
7070
7171
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+
7279def unpack (stream , ** kwargs ):
7380 """
7481 Unpack an object from `stream`.
@@ -609,9 +616,18 @@ class Packer(object):
609616 :param bool use_bin_type:
610617 Use bin type introduced in msgpack spec 2.0 for bytes.
611618 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.
612626 """
613627 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
615631 self ._use_float = use_single_float
616632 self ._autoreset = autoreset
617633 self ._use_bin_type = use_bin_type
@@ -623,18 +639,24 @@ def __init__(self, default=None, encoding='utf-8', unicode_errors='strict',
623639 raise TypeError ("default must be callable" )
624640 self ._default = default
625641
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 ):
627644 default_used = False
645+ if self ._strict_types :
646+ check = check_type_strict
647+ list_types = list
648+ else :
649+ list_types = (list , tuple )
628650 while True :
629651 if nest_limit < 0 :
630652 raise PackValueError ("recursion limit exceeded" )
631653 if obj is None :
632654 return self ._buffer .write (b"\xc0 " )
633- if isinstance (obj , bool ):
655+ if check (obj , bool ):
634656 if obj :
635657 return self ._buffer .write (b"\xc3 " )
636658 return self ._buffer .write (b"\xc2 " )
637- if isinstance (obj , int_types ):
659+ if check (obj , int_types ):
638660 if 0 <= obj < 0x80 :
639661 return self ._buffer .write (struct .pack ("B" , obj ))
640662 if - 0x20 <= obj < 0 :
@@ -660,7 +682,7 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
660682 default_used = True
661683 continue
662684 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 ):
664686 n = len (obj )
665687 if n <= 0xff :
666688 self ._buffer .write (struct .pack ('>BB' , 0xc4 , n ))
@@ -671,8 +693,8 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
671693 else :
672694 raise PackValueError ("Bytes is too large" )
673695 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 ):
676698 if self ._encoding is None :
677699 raise TypeError (
678700 "Can't encode unicode string: "
@@ -690,11 +712,11 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
690712 else :
691713 raise PackValueError ("String is too large" )
692714 return self ._buffer .write (obj )
693- if isinstance (obj , float ):
715+ if check (obj , float ):
694716 if self ._use_float :
695717 return self ._buffer .write (struct .pack (">Bf" , 0xca , obj ))
696718 return self ._buffer .write (struct .pack (">Bd" , 0xcb , obj ))
697- if isinstance (obj , ExtType ):
719+ if check (obj , ExtType ):
698720 code = obj .code
699721 data = obj .data
700722 assert isinstance (code , int )
@@ -719,13 +741,13 @@ def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
719741 self ._buffer .write (struct .pack ("b" , code ))
720742 self ._buffer .write (data )
721743 return
722- if isinstance (obj , ( list , tuple ) ):
744+ if check (obj , list_types ):
723745 n = len (obj )
724746 self ._fb_pack_array_header (n )
725747 for i in xrange (n ):
726748 self ._pack (obj [i ], nest_limit - 1 )
727749 return
728- if isinstance (obj , dict ):
750+ if check (obj , dict ):
729751 return self ._fb_pack_map_pairs (len (obj ), dict_iteritems (obj ),
730752 nest_limit - 1 )
731753 if not default_used and self ._default is not None :
0 commit comments