create portable serialized representations of python objects see module copyreg for a mechanism for registering custom picklers see module pickletools source for extensive comments classes pickler unpickler functions dumpobject file dumpsobject string loadfile object loadsbytes object misc variables version formatversion compatibleformats shortcut for use in isinstance testing these are purely informational no code uses these this is the highest protocol number we know how to read the protocol we write by default may be less than highestprotocol only bump this if the oldest still supported version of python already includes it a common base class for the other pickling exceptions pass class picklingerrorpickleerror pass class unpicklingerrorpickleerror pass an instance of stop is raised by unpickler loadstop in response to the stop opcode passing the object that is the result of unpickling class stopexception def initself value self value value pickle opcodes see pickletools py for extensive docs the listing here is in kindof alphabetical order of 1character pickle code pickletools groups them by purpose mark b push special markobject on stack stop b every pickle ends with stop pop b 0 discard topmost stack item popmark b 1 discard stack top through topmost markobject dup b 2 duplicate top stack item float b f push float object decimal string argument int b i push integer or bool decimal string argument binint b j push fourbyte signed int binint1 b k push 1byte unsigned int long b l push long decimal string argument binint2 b m push 2byte unsigned int none b n push none persid b p push persistent object id is taken from string arg binpersid b q stack reduce b r apply callable to argtuple both on stack string b s push string nlterminated string argument binstring b t push string counted binary string argument shortbinstring b u 256 bytes unicode b v push unicode string rawunicodeescaped d argument binunicode b x counted utf8 string argument append b a append stack top to list below it build b b call setstate or dict update global b c push self findclassmodname name 2 string args dict b d build a dict from stack items emptydict b push empty dict appends b e extend list on stack by topmost stack slice get b g push item from memo on stack index is string arg binget b h 1byte arg inst b i build push class instance longbinget b j push item from memo on stack index is 4byte arg list b l build list from topmost stack items emptylist b push empty list obj b o build push class instance put b p store stack top in memo index is string arg binput b q 1byte arg longbinput b r 4byte arg setitem b s add keyvalue pair to dict tuple b t build tuple from topmost stack items emptytuple b push empty tuple setitems b u modify dict by adding topmost keyvalue pairs binfloat b g push float arg is 8byte float encoding true b i01n not an opcode see int docs in pickletools py false b i00n not an opcode see int docs in pickletools py protocol 2 proto b x80 identify pickle protocol newobj b x81 build object by applying cls new to argtuple ext1 b x82 push object from extension registry 1byte index ext2 b x83 ditto but 2byte index ext4 b x84 ditto but 4byte index tuple1 b x85 build 1tuple from stack top tuple2 b x86 build 2tuple from two topmost stack items tuple3 b x87 build 3tuple from three topmost stack items newtrue b x88 push true newfalse b x89 push false long1 b x8a push long from 256 bytes long4 b x8b push really big long tuplesize2code emptytuple tuple1 tuple2 tuple3 protocol 3 python 3 x binbytes b b push bytes counted binary string argument shortbinbytes b c 256 bytes protocol 4 shortbinunicode b x8c push short string utf8 length 256 bytes binunicode8 b x8d push very long string binbytes8 b x8e push very long bytes string emptyset b x8f push empty set on the stack additems b x90 modify set by adding topmost stack items frozenset b x91 build frozenset from topmost stack items newobjex b x92 like newobj but work with keyword only arguments stackglobal b x93 same as global but using names on the stacks memoize b x94 store top of the stack in memo frame b x95 indicate the beginning of a new frame protocol 5 bytearray8 b x96 push bytearray nextbuffer b x97 push next outofband buffer readonlybuffer b x98 make top of stack readonly all extendx for x in dir if re matchazaz09 x class framer framesizemin 4 framesizetarget 64 1024 def initself filewrite self filewrite filewrite self currentframe none def startframingself self currentframe io bytesio def endframingself if self currentframe and self currentframe tell 0 self commitframeforcetrue self currentframe none def commitframeself forcefalse if self currentframe f self currentframe if f tell self framesizetarget or force data f getbuffer write self filewrite if lendata self framesizemin issue a single call to the write method of the underlying file object for the frame opcode with the size of the frame the concatenation is expected to be less expensive than issuing an additional call to write writeframe packq lendata issue a separate call to write to append the frame contents without concatenation to the above to avoid a memory copy writedata start the new frame with a new io bytesio instance so that the file object can have delayed access to the previous frame contents via an unreleased memoryview of the previous io bytesio instance self currentframe io bytesio def writeself data if self currentframe return self currentframe writedata else return self filewritedata def writelargebytesself header payload write self filewrite if self currentframe terminate the current frame and flush it to the file self commitframeforcetrue perform direct write of the header and payload of the large binary object be careful not to concatenate the header and the payload prior to calling write as we do not want to allocate a large temporary bytes object we intentionally do not insert a protocol 4 frame opcode to make it possible to optimize file read calls in the loader writeheader writepayload class unframer def initself fileread filereadline filetellnone self fileread fileread self filereadline filereadline self currentframe none def readintoself buf if self currentframe n self currentframe readintobuf if n 0 and lenbuf 0 self currentframe none n lenbuf buf self filereadn return n if n lenbuf raise unpicklingerror pickle exhausted before end of frame return n else n lenbuf buf self filereadn return n def readself n if self currentframe data self currentframe readn if not data and n 0 self currentframe none return self filereadn if lendata n raise unpicklingerror pickle exhausted before end of frame return data else return self filereadn def readlineself if self currentframe data self currentframe readline if not data self currentframe none return self filereadline if data1 b n 0 raise unpicklingerror pickle exhausted before end of frame return data else return self filereadline def loadframeself framesize if self currentframe and self currentframe read b raise unpicklingerror beginning of a new frame before end of current frame self currentframe io bytesioself filereadframesize tools used for pickling def getattributeobj name for subpath in name split if subpath locals raise attributeerrorcan t get local attribute r on r formatname obj try parent obj obj getattrobj subpath except attributeerror raise attributeerrorcan t get attribute r on r formatname obj from none return obj parent def whichmoduleobj name protect the iteration by using a list copy of sys modules against dynamic modules that trigger imports of other modules upon calls to getattr if x 0 return b nbytes x bitlength 3 1 result x tobytesnbytes byteorder little signedtrue if x 0 and nbytes 1 if result1 0xff and result2 0x80 0 result result 1 return result def decodelongdata rdecode a long from a two s complement littleendian binary string decodelongb 0 decodelongbxffx00 255 decodelongbxffx7f 32767 decodelongbx00xff 256 decodelongbx00x80 32768 decodelongbx80 128 decodelongbx7f 127 pickling machinery this takes a binary file for writing a pickle data stream the optional protocol argument tells the pickler to use the given protocol supported protocols are 0 1 2 3 4 and 5 the default protocol is 4 it was introduced in python 3 4 and is incompatible with previous versions specifying a negative protocol version selects the highest protocol version supported the higher the protocol used the more recent the version of python needed to read the pickle produced the file argument must have a write method that accepts a single bytes argument it can thus be a file object opened for binary writing an io bytesio instance or any other custom object that meets this interface if fiximports is true and protocol is less than 3 pickle will try to map the new python 3 names to the old module names used in python 2 so that the pickle data stream is readable with python 2 if buffercallback is none the default buffer views are serialized into file as part of the pickle stream if buffercallback is not none then it can be called any number of times with a buffer view if the callback returns a false value such as none the given buffer is outofband otherwise the buffer is serialized inband i e inside the pickle stream it is an error if buffercallback is not none and protocol is none or smaller than 5 clears the pickler s memo the memo is the data structure that remembers which objects the pickler has already seen so that shared or recursive objects are pickled by reference and not by value this method is useful when reusing picklers write a pickled representation of obj to the open file check whether pickler was initialized correctly this is only needed to mimic the behavior of pickle pickler dump if not hasattrself filewrite raise picklingerrorpickler init was not called by s init self class name if self proto 2 self writeproto packb self proto if self proto 4 self framer startframing self saveobj self writestop self framer endframing def memoizeself obj the pickler memo is a dictionary mapping object ids to 2tuples that contain the unpickler memo key and the object being memoized the memo key is written to the pickle and will become the key in the unpickler s memo the object is stored in the pickler memo so that transient objects are kept alive during pickling the use of the unpickler memo length as the memo key is just a convention the only requirement is that the memo values be unique but there appears no advantage to any other scheme and this scheme allows the unpickler memo to be implemented as a plain but growable array indexed by memo key return a put binput longbinput opcode string with argument i return a get binget longbinget opcode string with argument i check for persistent id defined by a subclass check the memo check the type dispatch table check private dispatch table if any or else copyreg dispatchtable check for a class with a custom metaclass treat as regular class check for a reduceex method fall back to reduce check for string returned by reduce meaning save as global assert that reduce returned a tuple assert that it returned an appropriately sized tuple save the reduce output and finally memoize the object this exists so a subclass can override it save a persistent id reference this api is called by some subclasses a reduce implementation can direct protocol 2 or newer to use the more efficient newobj opcode while still allowing protocol 0 and 1 to work normally for this to work the function returned by reduce should be called newobj and its first argument should be a class the implementation for newobj should be as follows although pickle has no way to verify this def newobjcls args return cls newcls args protocols 0 and 1 will pickle a reference to newobj while protocol 2 and above will pickle a reference to cls the remaining args tuple and the newobj code which calls cls newcls args at unpickling time see loadnewobj below if reduce returns a threetuple the state from the third tuple item will be pickled regardless of the protocol calling setstate at unpickling time see loadbuild below note that no standard newobj implementation exists you have to provide your own this is to enforce compatibility with python 2 2 pickles written using protocol 0 or 1 in python 2 3 should be unpicklable by python 2 2 if the object is already in the memo this means it is recursive in this case throw away everything we put on the stack and fetch the object back from the memo more new special cases that work with older protocols as well when reduce returns a tuple with 4 or 5 items the 4th and 5th item should be iterators that provide list items and dict items as key value tuples or none if a statesetter is specified call it instead of loadbuild to update obj s with its previous state first push statesetter and its tuple of expected arguments obj state onto the stack trigger a statesetterobj state function call the purpose of statesetter is to carryout an inplace modification of obj we do not care about what the method might return so its output is eventually removed from the stack methods below this point are dispatched through the dispatch table if the int is small enough to fit in a signed 4byte 2 scomp format we can store it more efficiently than the general case first one and twobyte unsigned ints next check for 4byte signed ints write data inband xxx the c implementation avoids a copy here write data outofband subtle same as in the big comment below proto 0 or proto 1 and tuple isn t empty or proto 1 and tuple has more than 3 elements subtle d was not in memo when we entered savetuple so the process of saving the tuple s elements must have saved the tuple itself the tuple is recursive the proper action now is to throw away everything we put on the stack and simply get the tuple it s already constructed this check could have been done in the for element loop instead but recursive tuples are a rare thing no recursion helper to batch up appends sequences else tmp is empty and we re done helper to batch up setitems sequences proto 1 only else tmp is empty and we re done if the object is already in the memo this means it is recursive in this case throw away everything we put on the stack and fetch the object back from the memo nonascii identifiers are supported only with protocols 3 unpickling machinery this takes a binary file for reading a pickle data stream the protocol version of the pickle is detected automatically so no proto argument is needed the argument file must have two methods a read method that takes an integer argument and a readline method that requires no arguments both methods should return bytes thus file can be a binary file object opened for reading an io bytesio object or any other custom object that meets this interface the filelike object must have two methods a read method that takes an integer argument and a readline method that requires no arguments both methods should return bytes thus filelike object can be a binary file object opened for reading a bytesio object or any other custom object that meets this interface if buffers is not none it should be an iterable of bufferenabled objects that is consumed each time the pickle stream references an outofband buffer view such buffers have been given in order to the buffercallback of a pickler object if buffers is none the default then the buffers are taken from the pickle stream assuming they are serialized there it is an error for buffers to be none if the pickle stream was produced with a nonnone buffercallback other optional arguments are fiximports encoding and errors which are used to control compatibility support for pickle stream generated by python 2 if fiximports is true pickle will try to map the old python 2 names to the new names used in python 3 the encoding and errors tell pickle how to decode 8bit string instances pickled by python 2 these default to ascii and strict respectively encoding can be bytes to read these 8bit string instances as bytes objects read a pickled object representation from the open file return the reconstituted object hierarchy specified in the file check whether unpickler was initialized correctly this is only needed to mimic the behavior of pickle unpickler dump return a list of items pushed in the stack after last mark instruction corrupt or hostile pickle we never write one like this used to allow strings from python 2 to be decoded either as bytes or unicode strings this should be used only with the string binstring and shortbinstring opcodes strip outermost quotes deprecated binstring uses signed 32bit length inst and obj differ only in how they get a class object it s not only sensible to do the rest in a common routine the two routines previously diverged and grew different bugs klass is the class to instantiate and k points to the topmost mark object following which are the arguments for klass init stack is markobject classobject arg1 arg2 corrupt or hostile pickle subclasses may override this even if the pep 307 requires extend and append methods fall back on append if the object has no extend method for backward compatibility shorthands use the faster pickle if possible doctest shortcut for use in isinstance testing these are purely informational no code uses these file format version we write original protocol 0 protocol 0 with inst added original protocol 1 protocol 1 with binfloat added protocol 2 protocol 3 protocol 4 protocol 5 old format versions we can read this is the highest protocol number we know how to read the protocol we write by default may be less than highest_protocol only bump this if the oldest still supported version of python already includes it a common base class for the other pickling exceptions this exception is raised when an unpicklable object is passed to the dump method this exception is raised when there is a problem unpickling an object such as a security violation note that other exceptions may also be raised during unpickling including but not necessarily limited to attributeerror eoferror importerror and indexerror an instance of _stop is raised by unpickler load_stop in response to the stop opcode passing the object that is the result of unpickling pickle opcodes see pickletools py for extensive docs the listing here is in kind of alphabetical order of 1 character pickle code pickletools groups them by purpose push special markobject on stack every pickle ends with stop discard topmost stack item discard stack top through topmost markobject duplicate top stack item push float object decimal string argument push integer or bool decimal string argument push four byte signed int push 1 byte unsigned int push long decimal string argument push 2 byte unsigned int push none push persistent object id is taken from string arg stack apply callable to argtuple both on stack push string nl terminated string argument push string counted binary string argument 256 bytes push unicode string raw unicode escaped d argument counted utf 8 string argument append stack top to list below it call __setstate__ or __dict__ update push self find_class modname name 2 string args build a dict from stack items push empty dict extend list on stack by topmost stack slice push item from memo on stack index is string arg 1 byte arg build push class instance push item from memo on stack index is 4 byte arg build list from topmost stack items push empty list build push class instance store stack top in memo index is string arg 1 byte arg 4 byte arg add key value pair to dict build tuple from topmost stack items push empty tuple modify dict by adding topmost key value pairs push float arg is 8 byte float encoding not an opcode see int docs in pickletools py not an opcode see int docs in pickletools py protocol 2 identify pickle protocol build object by applying cls __new__ to argtuple push object from extension registry 1 byte index ditto but 2 byte index ditto but 4 byte index build 1 tuple from stack top build 2 tuple from two topmost stack items build 3 tuple from three topmost stack items push true push false push long from 256 bytes push really big long protocol 3 python 3 x push bytes counted binary string argument 256 bytes protocol 4 push short string utf 8 length 256 bytes push very long string push very long bytes string push empty set on the stack modify set by adding topmost stack items build frozenset from topmost stack items like newobj but work with keyword only arguments same as global but using names on the stacks store top of the stack in memo indicate the beginning of a new frame protocol 5 push bytearray push next out of band buffer make top of stack readonly issue a single call to the write method of the underlying file object for the frame opcode with the size of the frame the concatenation is expected to be less expensive than issuing an additional call to write issue a separate call to write to append the frame contents without concatenation to the above to avoid a memory copy start the new frame with a new io bytesio instance so that the file object can have delayed access to the previous frame contents via an unreleased memoryview of the previous io bytesio instance terminate the current frame and flush it to the file perform direct write of the header and payload of the large binary object be careful not to concatenate the header and the payload prior to calling write as we do not want to allocate a large temporary bytes object we intentionally do not insert a protocol 4 frame opcode to make it possible to optimize file read calls in the loader tools used for pickling find the module an object belong to protect the iteration by using a list copy of sys modules against dynamic modules that trigger imports of other modules upon calls to getattr bpo 42406 encode a long to a two s complement little endian binary string note that 0 is a special case returning an empty string to save a byte in the long1 pickling context encode_long 0 b encode_long 255 b xff x00 encode_long 32767 b xff x7f encode_long 256 b x00 xff encode_long 32768 b x00 x80 encode_long 128 b x80 encode_long 127 b x7f decode a long from a two s complement little endian binary string decode_long b 0 decode_long b xff x00 255 decode_long b xff x7f 32767 decode_long b x00 xff 256 decode_long b x00 x80 32768 decode_long b x80 128 decode_long b x7f 127 pickling machinery this takes a binary file for writing a pickle data stream the optional protocol argument tells the pickler to use the given protocol supported protocols are 0 1 2 3 4 and 5 the default protocol is 4 it was introduced in python 3 4 and is incompatible with previous versions specifying a negative protocol version selects the highest protocol version supported the higher the protocol used the more recent the version of python needed to read the pickle produced the file argument must have a write method that accepts a single bytes argument it can thus be a file object opened for binary writing an io bytesio instance or any other custom object that meets this interface if fix_imports is true and protocol is less than 3 pickle will try to map the new python 3 names to the old module names used in python 2 so that the pickle data stream is readable with python 2 if buffer_callback is none the default buffer views are serialized into file as part of the pickle stream if buffer_callback is not none then it can be called any number of times with a buffer view if the callback returns a false value such as none the given buffer is out of band otherwise the buffer is serialized in band i e inside the pickle stream it is an error if buffer_callback is not none and protocol is none or smaller than 5 clears the pickler s memo the memo is the data structure that remembers which objects the pickler has already seen so that shared or recursive objects are pickled by reference and not by value this method is useful when re using picklers write a pickled representation of obj to the open file check whether pickler was initialized correctly this is only needed to mimic the behavior of _pickle pickler dump store an object in the memo the pickler memo is a dictionary mapping object ids to 2 tuples that contain the unpickler memo key and the object being memoized the memo key is written to the pickle and will become the key in the unpickler s memo the object is stored in the pickler memo so that transient objects are kept alive during pickling the use of the unpickler memo length as the memo key is just a convention the only requirement is that the memo values be unique but there appears no advantage to any other scheme and this scheme allows the unpickler memo to be implemented as a plain but growable array indexed by memo key return a put binput long_binput opcode string with argument i return a get binget long_binget opcode string with argument i check for persistent id defined by a subclass check the memo check the type dispatch table call unbound method with explicit self check private dispatch table if any or else copyreg dispatch_table check for a class with a custom metaclass treat as regular class check for a __reduce_ex__ method fall back to __reduce__ check for string returned by reduce meaning save as global assert that reduce returned a tuple assert that it returned an appropriately sized tuple save the reduce output and finally memoize the object this exists so a subclass can override it save a persistent id reference this api is called by some subclasses a __reduce__ implementation can direct protocol 2 or newer to use the more efficient newobj opcode while still allowing protocol 0 and 1 to work normally for this to work the function returned by __reduce__ should be called __newobj__ and its first argument should be a class the implementation for __newobj__ should be as follows although pickle has no way to verify this def __newobj__ cls args return cls __new__ cls args protocols 0 and 1 will pickle a reference to __newobj__ while protocol 2 and above will pickle a reference to cls the remaining args tuple and the newobj code which calls cls __new__ cls args at unpickling time see load_newobj below if __reduce__ returns a three tuple the state from the third tuple item will be pickled regardless of the protocol calling __setstate__ at unpickling time see load_build below note that no standard __newobj__ implementation exists you have to provide your own this is to enforce compatibility with python 2 2 pickles written using protocol 0 or 1 in python 2 3 should be unpicklable by python 2 2 if the object is already in the memo this means it is recursive in this case throw away everything we put on the stack and fetch the object back from the memo more new special cases that work with older protocols as well when __reduce__ returns a tuple with 4 or 5 items the 4th and 5th item should be iterators that provide list items and dict items as key value tuples or none if a state_setter is specified call it instead of load_build to update obj s with its previous state first push state_setter and its tuple of expected arguments obj state onto the stack simple binget opcode as obj is already memoized trigger a state_setter obj state function call the purpose of state_setter is to carry out an inplace modification of obj we do not care about what the method might return so its output is eventually removed from the stack methods below this point are dispatched through the dispatch table if the int is small enough to fit in a signed 4 byte 2 s comp format we can store it more efficiently than the general case first one and two byte unsigned ints next check for 4 byte signed ints bytes object is empty bytearray is empty write data in band xxx the c implementation avoids a copy here write data out of band eof on dos tuple is empty subtle same as in the big comment below proto 0 or proto 1 and tuple isn t empty or proto 1 and tuple has more than 3 elements subtle d was not in memo when we entered save_tuple so the process of saving the tuple s elements must have saved the tuple itself the tuple is recursive the proper action now is to throw away everything we put on the stack and simply get the tuple it s already constructed this check could have been done in the for element loop instead but recursive tuples are a rare thing proto 0 pop_mark not available no recursion proto 0 can t use empty_list helper to batch up appends sequences else tmp is empty and we re done proto 0 can t use empty_dict helper to batch up setitems sequences proto 1 only else tmp is empty and we re done if the object is already in the memo this means it is recursive in this case throw away everything we put on the stack and fetch the object back from the memo non ascii identifiers are supported only with protocols 3 unpickling machinery this takes a binary file for reading a pickle data stream the protocol version of the pickle is detected automatically so no proto argument is needed the argument file must have two methods a read method that takes an integer argument and a readline method that requires no arguments both methods should return bytes thus file can be a binary file object opened for reading an io bytesio object or any other custom object that meets this interface the file like object must have two methods a read method that takes an integer argument and a readline method that requires no arguments both methods should return bytes thus file like object can be a binary file object opened for reading a bytesio object or any other custom object that meets this interface if buffers is not none it should be an iterable of buffer enabled objects that is consumed each time the pickle stream references an out of band buffer view such buffers have been given in order to the buffer_callback of a pickler object if buffers is none the default then the buffers are taken from the pickle stream assuming they are serialized there it is an error for buffers to be none if the pickle stream was produced with a non none buffer_callback other optional arguments are fix_imports encoding and errors which are used to control compatibility support for pickle stream generated by python 2 if fix_imports is true pickle will try to map the old python 2 names to the new names used in python 3 the encoding and errors tell pickle how to decode 8 bit string instances pickled by python 2 these default to ascii and strict respectively encoding can be bytes to read these 8 bit string instances as bytes objects read a pickled object representation from the open file return the reconstituted object hierarchy specified in the file check whether unpickler was initialized correctly this is only needed to mimic the behavior of _pickle unpickler dump return a list of items pushed in the stack after last mark instruction corrupt or hostile pickle we never write one like this used to allow strings from python 2 to be decoded either as bytes or unicode strings this should be used only with the string binstring and short_binstring opcodes strip outermost quotes deprecated binstring uses signed 32 bit length inst and obj differ only in how they get a class object it s not only sensible to do the rest in a common routine the two routines previously diverged and grew different bugs klass is the class to instantiate and k points to the topmost mark object following which are the arguments for klass __init__ stack is markobject classobject arg1 arg2 note that 0 is forbidden corrupt or hostile pickle subclasses may override this even if the pep 307 requires extend and append methods fall back on append if the object has no extend method for backward compatibility shorthands use the faster _pickle if possible doctest
from types import FunctionType
from copyreg import dispatch_table
from copyreg import _extension_registry, _inverted_registry, _extension_cache
from itertools import islice
from functools import partial
import sys
from sys import maxsize
from struct import pack, unpack
import re
import io
import codecs
import _compat_pickle

__all__ = ["PickleError", "PicklingError", "UnpicklingError", "Pickler",
           "Unpickler", "dump", "dumps", "load", "loads"]

try:
    from _pickle import PickleBuffer
    __all__.append("PickleBuffer")
    _HAVE_PICKLE_BUFFER = True
except ImportError:
    _HAVE_PICKLE_BUFFER = False



bytes_types = (bytes, bytearray)


format_version = "4.0"                  
compatible_formats = ["1.0",            
                      "1.1",            
                      "1.2",            
                      "1.3",            
                      "2.0",            
                      "3.0",            
                      "4.0",            
                      "5.0",            
                      ]                 


HIGHEST_PROTOCOL = 5




DEFAULT_PROTOCOL = 4

class PickleError(Exception):
    
    pass

class PicklingError(PickleError):
    
    pass

class UnpicklingError(PickleError):
    
    pass



class _Stop(Exception):
    def __init__(self, value):
        self.value = value





MARK           = b'('   
STOP           = b'.'   
POP            = b'0'   
POP_MARK       = b'1'   
DUP            = b'2'   
FLOAT          = b'F'   
INT            = b'I'   
BININT         = b'J'   
BININT1        = b'K'   
LONG           = b'L'   
BININT2        = b'M'   
NONE           = b'N'   
PERSID         = b'P'   
BINPERSID      = b'Q'   
REDUCE         = b'R'   
STRING         = b'S'   
BINSTRING      = b'T'   
SHORT_BINSTRING= b'U'   
UNICODE        = b'V'   
BINUNICODE     = b'X'   
APPEND         = b'a'   
BUILD          = b'b'   
GLOBAL         = b'c'   
DICT           = b'd'   
EMPTY_DICT     = b'}'   
APPENDS        = b'e'   
GET            = b'g'   
BINGET         = b'h'   
INST           = b'i'   
LONG_BINGET    = b'j'   
LIST           = b'l'   
EMPTY_LIST     = b']'   
OBJ            = b'o'   
PUT            = b'p'   
BINPUT         = b'q'   
LONG_BINPUT    = b'r'   
SETITEM        = b's'   
TUPLE          = b't'   
EMPTY_TUPLE    = b')'   
SETITEMS       = b'u'   
BINFLOAT       = b'G'   

TRUE           = b'I01\n'  
FALSE          = b'I00\n'  



PROTO          = b'\x80'  
NEWOBJ         = b'\x81'  
EXT1           = b'\x82'  
EXT2           = b'\x83'  
EXT4           = b'\x84'  
TUPLE1         = b'\x85'  
TUPLE2         = b'\x86'  
TUPLE3         = b'\x87'  
NEWTRUE        = b'\x88'  
NEWFALSE       = b'\x89'  
LONG1          = b'\x8a'  
LONG4          = b'\x8b'  

_tuplesize2code = [EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3]



BINBYTES       = b'B'   
SHORT_BINBYTES = b'C'   



SHORT_BINUNICODE = b'\x8c'  
BINUNICODE8      = b'\x8d'  
BINBYTES8        = b'\x8e'  
EMPTY_SET        = b'\x8f'  
ADDITEMS         = b'\x90'  
FROZENSET        = b'\x91'  
NEWOBJ_EX        = b'\x92'  
STACK_GLOBAL     = b'\x93'  
MEMOIZE          = b'\x94'  
FRAME            = b'\x95'  



BYTEARRAY8       = b'\x96'  
NEXT_BUFFER      = b'\x97'  
READONLY_BUFFER  = b'\x98'  

__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$", x)])


class _Framer:

    _FRAME_SIZE_MIN = 4
    _FRAME_SIZE_TARGET = 64 * 1024

    def __init__(self, file_write):
        self.file_write = file_write
        self.current_frame = None

    def start_framing(self):
        self.current_frame = io.BytesIO()

    def end_framing(self):
        if self.current_frame and self.current_frame.tell() > 0:
            self.commit_frame(force=True)
            self.current_frame = None

    def commit_frame(self, force=False):
        if self.current_frame:
            f = self.current_frame
            if f.tell() >= self._FRAME_SIZE_TARGET or force:
                data = f.getbuffer()
                write = self.file_write
                if len(data) >= self._FRAME_SIZE_MIN:
                    
                    
                    
                    
                    write(FRAME + pack("<Q", len(data)))

                
                
                
                write(data)

                
                
                
                
                self.current_frame = io.BytesIO()

    def write(self, data):
        if self.current_frame:
            return self.current_frame.write(data)
        else:
            return self.file_write(data)

    def write_large_bytes(self, header, payload):
        write = self.file_write
        if self.current_frame:
            
            self.commit_frame(force=True)

        
        
        
        
        
        
        write(header)
        write(payload)


class _Unframer:

    def __init__(self, file_read, file_readline, file_tell=None):
        self.file_read = file_read
        self.file_readline = file_readline
        self.current_frame = None

    def readinto(self, buf):
        if self.current_frame:
            n = self.current_frame.readinto(buf)
            if n == 0 and len(buf) != 0:
                self.current_frame = None
                n = len(buf)
                buf[:] = self.file_read(n)
                return n
            if n < len(buf):
                raise UnpicklingError(
                    "pickle exhausted before end of frame")
            return n
        else:
            n = len(buf)
            buf[:] = self.file_read(n)
            return n

    def read(self, n):
        if self.current_frame:
            data = self.current_frame.read(n)
            if not data and n != 0:
                self.current_frame = None
                return self.file_read(n)
            if len(data) < n:
                raise UnpicklingError(
                    "pickle exhausted before end of frame")
            return data
        else:
            return self.file_read(n)

    def readline(self):
        if self.current_frame:
            data = self.current_frame.readline()
            if not data:
                self.current_frame = None
                return self.file_readline()
            if data[-1] != b'\n'[0]:
                raise UnpicklingError(
                    "pickle exhausted before end of frame")
            return data
        else:
            return self.file_readline()

    def load_frame(self, frame_size):
        if self.current_frame and self.current_frame.read() != b'':
            raise UnpicklingError(
                "beginning of a new frame before end of current frame")
        self.current_frame = io.BytesIO(self.file_read(frame_size))




def _getattribute(obj, name):
    for subpath in name.split('.'):
        if subpath == '<locals>':
            raise AttributeError("Can't get local attribute {!r} on {!r}"
                                 .format(name, obj))
        try:
            parent = obj
            obj = getattr(obj, subpath)
        except AttributeError:
            raise AttributeError("Can't get attribute {!r} on {!r}"
                                 .format(name, obj)) from None
    return obj, parent

def whichmodule(obj, name):
    
    module_name = getattr(obj, '__module__', None)
    if module_name is not None:
        return module_name
    
    
    for module_name, module in sys.modules.copy().items():
        if (module_name == '__main__'
            or module_name == '__mp_main__'  
            or module is None):
            continue
        try:
            if _getattribute(module, name)[0] is obj:
                return module_name
        except AttributeError:
            pass
    return '__main__'

def encode_long(x):
    r
    if x == 0:
        return b''
    nbytes = (x.bit_length() >> 3) + 1
    result = x.to_bytes(nbytes, byteorder='little', signed=True)
    if x < 0 and nbytes > 1:
        if result[-1] == 0xff and (result[-2] & 0x80) != 0:
            result = result[:-1]
    return result

def decode_long(data):
    r
    return int.from_bytes(data, byteorder='little', signed=True)


_NoValue = object()



class _Pickler:

    def __init__(self, file, protocol=None, *, fix_imports=True,
                 buffer_callback=None):
        
        if protocol is None:
            protocol = DEFAULT_PROTOCOL
        if protocol < 0:
            protocol = HIGHEST_PROTOCOL
        elif not 0 <= protocol <= HIGHEST_PROTOCOL:
            raise ValueError("pickle protocol must be <= %d" % HIGHEST_PROTOCOL)
        if buffer_callback is not None and protocol < 5:
            raise ValueError("buffer_callback needs protocol >= 5")
        self._buffer_callback = buffer_callback
        try:
            self._file_write = file.write
        except AttributeError:
            raise TypeError("file must have a 'write' attribute")
        self.framer = _Framer(self._file_write)
        self.write = self.framer.write
        self._write_large_bytes = self.framer.write_large_bytes
        self.memo = {}
        self.proto = int(protocol)
        self.bin = protocol >= 1
        self.fast = 0
        self.fix_imports = fix_imports and protocol < 3

    def clear_memo(self):
        
        self.memo.clear()

    def dump(self, obj):
        
        
        
        if not hasattr(self, "_file_write"):
            raise PicklingError("Pickler.__init__() was not called by "
                                "%s.__init__()" % (self.__class__.__name__,))
        if self.proto >= 2:
            self.write(PROTO + pack("<B", self.proto))
        if self.proto >= 4:
            self.framer.start_framing()
        self.save(obj)
        self.write(STOP)
        self.framer.end_framing()

    def memoize(self, obj):
        

        
        
        
        
        
        

        
        
        
        
        
        if self.fast:
            return
        assert id(obj) not in self.memo
        idx = len(self.memo)
        self.write(self.put(idx))
        self.memo[id(obj)] = idx, obj

    
    def put(self, idx):
        if self.proto >= 4:
            return MEMOIZE
        elif self.bin:
            if idx < 256:
                return BINPUT + pack("<B", idx)
            else:
                return LONG_BINPUT + pack("<I", idx)
        else:
            return PUT + repr(idx).encode("ascii") + b'\n'

    
    def get(self, i):
        if self.bin:
            if i < 256:
                return BINGET + pack("<B", i)
            else:
                return LONG_BINGET + pack("<I", i)

        return GET + repr(i).encode("ascii") + b'\n'

    def save(self, obj, save_persistent_id=True):
        self.framer.commit_frame()

        
        pid = self.persistent_id(obj)
        if pid is not None and save_persistent_id:
            self.save_pers(pid)
            return

        
        x = self.memo.get(id(obj))
        if x is not None:
            self.write(self.get(x[0]))
            return

        rv = NotImplemented
        reduce = getattr(self, "reducer_override", _NoValue)
        if reduce is not _NoValue:
            rv = reduce(obj)

        if rv is NotImplemented:
            
            t = type(obj)
            f = self.dispatch.get(t)
            if f is not None:
                f(self, obj)  
                return

            
            
            reduce = getattr(self, 'dispatch_table', dispatch_table).get(t, _NoValue)
            if reduce is not _NoValue:
                rv = reduce(obj)
            else:
                
                
                if issubclass(t, type):
                    self.save_global(obj)
                    return

                
                reduce = getattr(obj, "__reduce_ex__", _NoValue)
                if reduce is not _NoValue:
                    rv = reduce(self.proto)
                else:
                    reduce = getattr(obj, "__reduce__", _NoValue)
                    if reduce is not _NoValue:
                        rv = reduce()
                    else:
                        raise PicklingError("Can't pickle %r object: %r" %
                                            (t.__name__, obj))

        
        if isinstance(rv, str):
            self.save_global(obj, rv)
            return

        
        if not isinstance(rv, tuple):
            raise PicklingError("%s must return string or tuple" % reduce)

        
        l = len(rv)
        if not (2 <= l <= 6):
            raise PicklingError("Tuple returned by %s must have "
                                "two to six elements" % reduce)

        
        self.save_reduce(obj=obj, *rv)

    def persistent_id(self, obj):
        
        return None

    def save_pers(self, pid):
        
        if self.bin:
            self.save(pid, save_persistent_id=False)
            self.write(BINPERSID)
        else:
            try:
                self.write(PERSID + str(pid).encode("ascii") + b'\n')
            except UnicodeEncodeError:
                raise PicklingError(
                    "persistent IDs in protocol 0 must be ASCII strings")

    def save_reduce(self, func, args, state=None, listitems=None,
                    dictitems=None, state_setter=None, *, obj=None):
        

        if not isinstance(args, tuple):
            raise PicklingError("args from save_reduce() must be a tuple")
        if not callable(func):
            raise PicklingError("func from save_reduce() must be callable")

        save = self.save
        write = self.write

        func_name = getattr(func, "__name__", "")
        if self.proto >= 2 and func_name == "__newobj_ex__":
            cls, args, kwargs = args
            if not hasattr(cls, "__new__"):
                raise PicklingError("args[0] from {} args has no __new__"
                                    .format(func_name))
            if obj is not None and cls is not obj.__class__:
                raise PicklingError("args[0] from {} args has the wrong class"
                                    .format(func_name))
            if self.proto >= 4:
                save(cls)
                save(args)
                save(kwargs)
                write(NEWOBJ_EX)
            else:
                func = partial(cls.__new__, cls, *args, **kwargs)
                save(func)
                save(())
                write(REDUCE)
        elif self.proto >= 2 and func_name == "__newobj__":
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            cls = args[0]
            if not hasattr(cls, "__new__"):
                raise PicklingError(
                    "args[0] from __newobj__ args has no __new__")
            if obj is not None and cls is not obj.__class__:
                raise PicklingError(
                    "args[0] from __newobj__ args has the wrong class")
            args = args[1:]
            save(cls)
            save(args)
            write(NEWOBJ)
        else:
            save(func)
            save(args)
            write(REDUCE)

        if obj is not None:
            
            
            
            if id(obj) in self.memo:
                write(POP + self.get(self.memo[id(obj)][0]))
            else:
                self.memoize(obj)

        
        
        
        

        if listitems is not None:
            self._batch_appends(listitems)

        if dictitems is not None:
            self._batch_setitems(dictitems)

        if state is not None:
            if state_setter is None:
                save(state)
                write(BUILD)
            else:
                
                
                
                
                save(state_setter)
                save(obj)  
                save(state)
                write(TUPLE2)
                
                write(REDUCE)
                
                
                
                
                write(POP)

    

    dispatch = {}

    def save_none(self, obj):
        self.write(NONE)
    dispatch[type(None)] = save_none

    def save_bool(self, obj):
        if self.proto >= 2:
            self.write(NEWTRUE if obj else NEWFALSE)
        else:
            self.write(TRUE if obj else FALSE)
    dispatch[bool] = save_bool

    def save_long(self, obj):
        if self.bin:
            
            
            
            
            if obj >= 0:
                if obj <= 0xff:
                    self.write(BININT1 + pack("<B", obj))
                    return
                if obj <= 0xffff:
                    self.write(BININT2 + pack("<H", obj))
                    return
            
            if -0x80000000 <= obj <= 0x7fffffff:
                self.write(BININT + pack("<i", obj))
                return
        if self.proto >= 2:
            encoded = encode_long(obj)
            n = len(encoded)
            if n < 256:
                self.write(LONG1 + pack("<B", n) + encoded)
            else:
                self.write(LONG4 + pack("<i", n) + encoded)
            return
        if -0x80000000 <= obj <= 0x7fffffff:
            self.write(INT + repr(obj).encode("ascii") + b'\n')
        else:
            self.write(LONG + repr(obj).encode("ascii") + b'L\n')
    dispatch[int] = save_long

    def save_float(self, obj):
        if self.bin:
            self.write(BINFLOAT + pack('>d', obj))
        else:
            self.write(FLOAT + repr(obj).encode("ascii") + b'\n')
    dispatch[float] = save_float

    def save_bytes(self, obj):
        if self.proto < 3:
            if not obj: 
                self.save_reduce(bytes, (), obj=obj)
            else:
                self.save_reduce(codecs.encode,
                                 (str(obj, 'latin1'), 'latin1'), obj=obj)
            return
        n = len(obj)
        if n <= 0xff:
            self.write(SHORT_BINBYTES + pack("<B", n) + obj)
        elif n > 0xffffffff and self.proto >= 4:
            self._write_large_bytes(BINBYTES8 + pack("<Q", n), obj)
        elif n >= self.framer._FRAME_SIZE_TARGET:
            self._write_large_bytes(BINBYTES + pack("<I", n), obj)
        else:
            self.write(BINBYTES + pack("<I", n) + obj)
        self.memoize(obj)
    dispatch[bytes] = save_bytes

    def save_bytearray(self, obj):
        if self.proto < 5:
            if not obj:  
                self.save_reduce(bytearray, (), obj=obj)
            else:
                self.save_reduce(bytearray, (bytes(obj),), obj=obj)
            return
        n = len(obj)
        if n >= self.framer._FRAME_SIZE_TARGET:
            self._write_large_bytes(BYTEARRAY8 + pack("<Q", n), obj)
        else:
            self.write(BYTEARRAY8 + pack("<Q", n) + obj)
        self.memoize(obj)
    dispatch[bytearray] = save_bytearray

    if _HAVE_PICKLE_BUFFER:
        def save_picklebuffer(self, obj):
            if self.proto < 5:
                raise PicklingError("PickleBuffer can only pickled with "
                                    "protocol >= 5")
            with obj.raw() as m:
                if not m.contiguous:
                    raise PicklingError("PickleBuffer can not be pickled when "
                                        "pointing to a non-contiguous buffer")
                in_band = True
                if self._buffer_callback is not None:
                    in_band = bool(self._buffer_callback(obj))
                if in_band:
                    
                    
                    if m.readonly:
                        self.save_bytes(m.tobytes())
                    else:
                        self.save_bytearray(m.tobytes())
                else:
                    
                    self.write(NEXT_BUFFER)
                    if m.readonly:
                        self.write(READONLY_BUFFER)

        dispatch[PickleBuffer] = save_picklebuffer

    def save_str(self, obj):
        if self.bin:
            encoded = obj.encode('utf-8', 'surrogatepass')
            n = len(encoded)
            if n <= 0xff and self.proto >= 4:
                self.write(SHORT_BINUNICODE + pack("<B", n) + encoded)
            elif n > 0xffffffff and self.proto >= 4:
                self._write_large_bytes(BINUNICODE8 + pack("<Q", n), encoded)
            elif n >= self.framer._FRAME_SIZE_TARGET:
                self._write_large_bytes(BINUNICODE + pack("<I", n), encoded)
            else:
                self.write(BINUNICODE + pack("<I", n) + encoded)
        else:
            obj = obj.replace("\\", "\\u005c")
            obj = obj.replace("\0", "\\u0000")
            obj = obj.replace("\n", "\\u000a")
            obj = obj.replace("\r", "\\u000d")
            obj = obj.replace("\x1a", "\\u001a")  
            self.write(UNICODE + obj.encode('raw-unicode-escape') +
                       b'\n')
        self.memoize(obj)
    dispatch[str] = save_str

    def save_tuple(self, obj):
        if not obj: 
            if self.bin:
                self.write(EMPTY_TUPLE)
            else:
                self.write(MARK + TUPLE)
            return

        n = len(obj)
        save = self.save
        memo = self.memo
        if n <= 3 and self.proto >= 2:
            for element in obj:
                save(element)
            
            if id(obj) in memo:
                get = self.get(memo[id(obj)][0])
                self.write(POP * n + get)
            else:
                self.write(_tuplesize2code[n])
                self.memoize(obj)
            return

        
        
        write = self.write
        write(MARK)
        for element in obj:
            save(element)

        if id(obj) in memo:
            
            
            
            
            
            
            
            get = self.get(memo[id(obj)][0])
            if self.bin:
                write(POP_MARK + get)
            else:   
                write(POP * (n+1) + get)
            return

        
        write(TUPLE)
        self.memoize(obj)

    dispatch[tuple] = save_tuple

    def save_list(self, obj):
        if self.bin:
            self.write(EMPTY_LIST)
        else:   
            self.write(MARK + LIST)

        self.memoize(obj)
        self._batch_appends(obj)

    dispatch[list] = save_list

    _BATCHSIZE = 1000

    def _batch_appends(self, items):
        
        save = self.save
        write = self.write

        if not self.bin:
            for x in items:
                save(x)
                write(APPEND)
            return

        it = iter(items)
        while True:
            tmp = list(islice(it, self._BATCHSIZE))
            n = len(tmp)
            if n > 1:
                write(MARK)
                for x in tmp:
                    save(x)
                write(APPENDS)
            elif n:
                save(tmp[0])
                write(APPEND)
            
            if n < self._BATCHSIZE:
                return

    def save_dict(self, obj):
        if self.bin:
            self.write(EMPTY_DICT)
        else:   
            self.write(MARK + DICT)

        self.memoize(obj)
        self._batch_setitems(obj.items())

    dispatch[dict] = save_dict

    def _batch_setitems(self, items):
        
        save = self.save
        write = self.write

        if not self.bin:
            for k, v in items:
                save(k)
                save(v)
                write(SETITEM)
            return

        it = iter(items)
        while True:
            tmp = list(islice(it, self._BATCHSIZE))
            n = len(tmp)
            if n > 1:
                write(MARK)
                for k, v in tmp:
                    save(k)
                    save(v)
                write(SETITEMS)
            elif n:
                k, v = tmp[0]
                save(k)
                save(v)
                write(SETITEM)
            
            if n < self._BATCHSIZE:
                return

    def save_set(self, obj):
        save = self.save
        write = self.write

        if self.proto < 4:
            self.save_reduce(set, (list(obj),), obj=obj)
            return

        write(EMPTY_SET)
        self.memoize(obj)

        it = iter(obj)
        while True:
            batch = list(islice(it, self._BATCHSIZE))
            n = len(batch)
            if n > 0:
                write(MARK)
                for item in batch:
                    save(item)
                write(ADDITEMS)
            if n < self._BATCHSIZE:
                return
    dispatch[set] = save_set

    def save_frozenset(self, obj):
        save = self.save
        write = self.write

        if self.proto < 4:
            self.save_reduce(frozenset, (list(obj),), obj=obj)
            return

        write(MARK)
        for item in obj:
            save(item)

        if id(obj) in self.memo:
            
            
            
            write(POP_MARK + self.get(self.memo[id(obj)][0]))
            return

        write(FROZENSET)
        self.memoize(obj)
    dispatch[frozenset] = save_frozenset

    def save_global(self, obj, name=None):
        write = self.write
        memo = self.memo

        if name is None:
            name = getattr(obj, '__qualname__', None)
        if name is None:
            name = obj.__name__

        module_name = whichmodule(obj, name)
        try:
            __import__(module_name, level=0)
            module = sys.modules[module_name]
            obj2, parent = _getattribute(module, name)
        except (ImportError, KeyError, AttributeError):
            raise PicklingError(
                "Can't pickle %r: it's not found as %s.%s" %
                (obj, module_name, name)) from None
        else:
            if obj2 is not obj:
                raise PicklingError(
                    "Can't pickle %r: it's not the same object as %s.%s" %
                    (obj, module_name, name))

        if self.proto >= 2:
            code = _extension_registry.get((module_name, name))
            if code:
                assert code > 0
                if code <= 0xff:
                    write(EXT1 + pack("<B", code))
                elif code <= 0xffff:
                    write(EXT2 + pack("<H", code))
                else:
                    write(EXT4 + pack("<i", code))
                return
        lastname = name.rpartition('.')[2]
        if parent is module:
            name = lastname
        
        if self.proto >= 4:
            self.save(module_name)
            self.save(name)
            write(STACK_GLOBAL)
        elif parent is not module:
            self.save_reduce(getattr, (parent, lastname))
        elif self.proto >= 3:
            write(GLOBAL + bytes(module_name, "utf-8") + b'\n' +
                  bytes(name, "utf-8") + b'\n')
        else:
            if self.fix_imports:
                r_name_mapping = _compat_pickle.REVERSE_NAME_MAPPING
                r_import_mapping = _compat_pickle.REVERSE_IMPORT_MAPPING
                if (module_name, name) in r_name_mapping:
                    module_name, name = r_name_mapping[(module_name, name)]
                elif module_name in r_import_mapping:
                    module_name = r_import_mapping[module_name]
            try:
                write(GLOBAL + bytes(module_name, "ascii") + b'\n' +
                      bytes(name, "ascii") + b'\n')
            except UnicodeEncodeError:
                raise PicklingError(
                    "can't pickle global identifier '%s.%s' using "
                    "pickle protocol %i" % (module, name, self.proto)) from None

        self.memoize(obj)

    def save_type(self, obj):
        if obj is type(None):
            return self.save_reduce(type, (None,), obj=obj)
        elif obj is type(NotImplemented):
            return self.save_reduce(type, (NotImplemented,), obj=obj)
        elif obj is type(...):
            return self.save_reduce(type, (...,), obj=obj)
        return self.save_global(obj)

    dispatch[FunctionType] = save_global
    dispatch[type] = save_type




class _Unpickler:

    def __init__(self, file, *, fix_imports=True,
                 encoding="ASCII", errors="strict", buffers=None):
        
        self._buffers = iter(buffers) if buffers is not None else None
        self._file_readline = file.readline
        self._file_read = file.read
        self.memo = {}
        self.encoding = encoding
        self.errors = errors
        self.proto = 0
        self.fix_imports = fix_imports

    def load(self):
        
        
        
        if not hasattr(self, "_file_read"):
            raise UnpicklingError("Unpickler.__init__() was not called by "
                                  "%s.__init__()" % (self.__class__.__name__,))
        self._unframer = _Unframer(self._file_read, self._file_readline)
        self.read = self._unframer.read
        self.readinto = self._unframer.readinto
        self.readline = self._unframer.readline
        self.metastack = []
        self.stack = []
        self.append = self.stack.append
        self.proto = 0
        read = self.read
        dispatch = self.dispatch
        try:
            while True:
                key = read(1)
                if not key:
                    raise EOFError
                assert isinstance(key, bytes_types)
                dispatch[key[0]](self)
        except _Stop as stopinst:
            return stopinst.value

    
    def pop_mark(self):
        items = self.stack
        self.stack = self.metastack.pop()
        self.append = self.stack.append
        return items

    def persistent_load(self, pid):
        raise UnpicklingError("unsupported persistent id encountered")

    dispatch = {}

    def load_proto(self):
        proto = self.read(1)[0]
        if not 0 <= proto <= HIGHEST_PROTOCOL:
            raise ValueError("unsupported pickle protocol: %d" % proto)
        self.proto = proto
    dispatch[PROTO[0]] = load_proto

    def load_frame(self):
        frame_size, = unpack('<Q', self.read(8))
        if frame_size > sys.maxsize:
            raise ValueError("frame size > sys.maxsize: %d" % frame_size)
        self._unframer.load_frame(frame_size)
    dispatch[FRAME[0]] = load_frame

    def load_persid(self):
        try:
            pid = self.readline()[:-1].decode("ascii")
        except UnicodeDecodeError:
            raise UnpicklingError(
                "persistent IDs in protocol 0 must be ASCII strings")
        self.append(self.persistent_load(pid))
    dispatch[PERSID[0]] = load_persid

    def load_binpersid(self):
        pid = self.stack.pop()
        self.append(self.persistent_load(pid))
    dispatch[BINPERSID[0]] = load_binpersid

    def load_none(self):
        self.append(None)
    dispatch[NONE[0]] = load_none

    def load_false(self):
        self.append(False)
    dispatch[NEWFALSE[0]] = load_false

    def load_true(self):
        self.append(True)
    dispatch[NEWTRUE[0]] = load_true

    def load_int(self):
        data = self.readline()
        if data == FALSE[1:]:
            val = False
        elif data == TRUE[1:]:
            val = True
        else:
            val = int(data, 0)
        self.append(val)
    dispatch[INT[0]] = load_int

    def load_binint(self):
        self.append(unpack('<i', self.read(4))[0])
    dispatch[BININT[0]] = load_binint

    def load_binint1(self):
        self.append(self.read(1)[0])
    dispatch[BININT1[0]] = load_binint1

    def load_binint2(self):
        self.append(unpack('<H', self.read(2))[0])
    dispatch[BININT2[0]] = load_binint2

    def load_long(self):
        val = self.readline()[:-1]
        if val and val[-1] == b'L'[0]:
            val = val[:-1]
        self.append(int(val, 0))
    dispatch[LONG[0]] = load_long

    def load_long1(self):
        n = self.read(1)[0]
        data = self.read(n)
        self.append(decode_long(data))
    dispatch[LONG1[0]] = load_long1

    def load_long4(self):
        n, = unpack('<i', self.read(4))
        if n < 0:
            
            raise UnpicklingError("LONG pickle has negative byte count")
        data = self.read(n)
        self.append(decode_long(data))
    dispatch[LONG4[0]] = load_long4

    def load_float(self):
        self.append(float(self.readline()[:-1]))
    dispatch[FLOAT[0]] = load_float

    def load_binfloat(self):
        self.append(unpack('>d', self.read(8))[0])
    dispatch[BINFLOAT[0]] = load_binfloat

    def _decode_string(self, value):
        
        
        
        if self.encoding == "bytes":
            return value
        else:
            return value.decode(self.encoding, self.errors)

    def load_string(self):
        data = self.readline()[:-1]
        
        if len(data) >= 2 and data[0] == data[-1] and data[0] in b'"\'':
            data = data[1:-1]
        else:
            raise UnpicklingError("the STRING opcode argument must be quoted")
        self.append(self._decode_string(codecs.escape_decode(data)[0]))
    dispatch[STRING[0]] = load_string

    def load_binstring(self):
        
        len, = unpack('<i', self.read(4))
        if len < 0:
            raise UnpicklingError("BINSTRING pickle has negative byte count")
        data = self.read(len)
        self.append(self._decode_string(data))
    dispatch[BINSTRING[0]] = load_binstring

    def load_binbytes(self):
        len, = unpack('<I', self.read(4))
        if len > maxsize:
            raise UnpicklingError("BINBYTES exceeds system's maximum size "
                                  "of %d bytes" % maxsize)
        self.append(self.read(len))
    dispatch[BINBYTES[0]] = load_binbytes

    def load_unicode(self):
        self.append(str(self.readline()[:-1], 'raw-unicode-escape'))
    dispatch[UNICODE[0]] = load_unicode

    def load_binunicode(self):
        len, = unpack('<I', self.read(4))
        if len > maxsize:
            raise UnpicklingError("BINUNICODE exceeds system's maximum size "
                                  "of %d bytes" % maxsize)
        self.append(str(self.read(len), 'utf-8', 'surrogatepass'))
    dispatch[BINUNICODE[0]] = load_binunicode

    def load_binunicode8(self):
        len, = unpack('<Q', self.read(8))
        if len > maxsize:
            raise UnpicklingError("BINUNICODE8 exceeds system's maximum size "
                                  "of %d bytes" % maxsize)
        self.append(str(self.read(len), 'utf-8', 'surrogatepass'))
    dispatch[BINUNICODE8[0]] = load_binunicode8

    def load_binbytes8(self):
        len, = unpack('<Q', self.read(8))
        if len > maxsize:
            raise UnpicklingError("BINBYTES8 exceeds system's maximum size "
                                  "of %d bytes" % maxsize)
        self.append(self.read(len))
    dispatch[BINBYTES8[0]] = load_binbytes8

    def load_bytearray8(self):
        len, = unpack('<Q', self.read(8))
        if len > maxsize:
            raise UnpicklingError("BYTEARRAY8 exceeds system's maximum size "
                                  "of %d bytes" % maxsize)
        b = bytearray(len)
        self.readinto(b)
        self.append(b)
    dispatch[BYTEARRAY8[0]] = load_bytearray8

    def load_next_buffer(self):
        if self._buffers is None:
            raise UnpicklingError("pickle stream refers to out-of-band data "
                                  "but no *buffers* argument was given")
        try:
            buf = next(self._buffers)
        except StopIteration:
            raise UnpicklingError("not enough out-of-band buffers")
        self.append(buf)
    dispatch[NEXT_BUFFER[0]] = load_next_buffer

    def load_readonly_buffer(self):
        buf = self.stack[-1]
        with memoryview(buf) as m:
            if not m.readonly:
                self.stack[-1] = m.toreadonly()
    dispatch[READONLY_BUFFER[0]] = load_readonly_buffer

    def load_short_binstring(self):
        len = self.read(1)[0]
        data = self.read(len)
        self.append(self._decode_string(data))
    dispatch[SHORT_BINSTRING[0]] = load_short_binstring

    def load_short_binbytes(self):
        len = self.read(1)[0]
        self.append(self.read(len))
    dispatch[SHORT_BINBYTES[0]] = load_short_binbytes

    def load_short_binunicode(self):
        len = self.read(1)[0]
        self.append(str(self.read(len), 'utf-8', 'surrogatepass'))
    dispatch[SHORT_BINUNICODE[0]] = load_short_binunicode

    def load_tuple(self):
        items = self.pop_mark()
        self.append(tuple(items))
    dispatch[TUPLE[0]] = load_tuple

    def load_empty_tuple(self):
        self.append(())
    dispatch[EMPTY_TUPLE[0]] = load_empty_tuple

    def load_tuple1(self):
        self.stack[-1] = (self.stack[-1],)
    dispatch[TUPLE1[0]] = load_tuple1

    def load_tuple2(self):
        self.stack[-2:] = [(self.stack[-2], self.stack[-1])]
    dispatch[TUPLE2[0]] = load_tuple2

    def load_tuple3(self):
        self.stack[-3:] = [(self.stack[-3], self.stack[-2], self.stack[-1])]
    dispatch[TUPLE3[0]] = load_tuple3

    def load_empty_list(self):
        self.append([])
    dispatch[EMPTY_LIST[0]] = load_empty_list

    def load_empty_dictionary(self):
        self.append({})
    dispatch[EMPTY_DICT[0]] = load_empty_dictionary

    def load_empty_set(self):
        self.append(set())
    dispatch[EMPTY_SET[0]] = load_empty_set

    def load_frozenset(self):
        items = self.pop_mark()
        self.append(frozenset(items))
    dispatch[FROZENSET[0]] = load_frozenset

    def load_list(self):
        items = self.pop_mark()
        self.append(items)
    dispatch[LIST[0]] = load_list

    def load_dict(self):
        items = self.pop_mark()
        d = {items[i]: items[i+1]
             for i in range(0, len(items), 2)}
        self.append(d)
    dispatch[DICT[0]] = load_dict

    
    
    
    
    
    def _instantiate(self, klass, args):
        if (args or not isinstance(klass, type) or
            hasattr(klass, "__getinitargs__")):
            try:
                value = klass(*args)
            except TypeError as err:
                raise TypeError("in constructor for %s: %s" %
                                (klass.__name__, str(err)), err.__traceback__)
        else:
            value = klass.__new__(klass)
        self.append(value)

    def load_inst(self):
        module = self.readline()[:-1].decode("ascii")
        name = self.readline()[:-1].decode("ascii")
        klass = self.find_class(module, name)
        self._instantiate(klass, self.pop_mark())
    dispatch[INST[0]] = load_inst

    def load_obj(self):
        
        args = self.pop_mark()
        cls = args.pop(0)
        self._instantiate(cls, args)
    dispatch[OBJ[0]] = load_obj

    def load_newobj(self):
        args = self.stack.pop()
        cls = self.stack.pop()
        obj = cls.__new__(cls, *args)
        self.append(obj)
    dispatch[NEWOBJ[0]] = load_newobj

    def load_newobj_ex(self):
        kwargs = self.stack.pop()
        args = self.stack.pop()
        cls = self.stack.pop()
        obj = cls.__new__(cls, *args, **kwargs)
        self.append(obj)
    dispatch[NEWOBJ_EX[0]] = load_newobj_ex

    def load_global(self):
        module = self.readline()[:-1].decode("utf-8")
        name = self.readline()[:-1].decode("utf-8")
        klass = self.find_class(module, name)
        self.append(klass)
    dispatch[GLOBAL[0]] = load_global

    def load_stack_global(self):
        name = self.stack.pop()
        module = self.stack.pop()
        if type(name) is not str or type(module) is not str:
            raise UnpicklingError("STACK_GLOBAL requires str")
        self.append(self.find_class(module, name))
    dispatch[STACK_GLOBAL[0]] = load_stack_global

    def load_ext1(self):
        code = self.read(1)[0]
        self.get_extension(code)
    dispatch[EXT1[0]] = load_ext1

    def load_ext2(self):
        code, = unpack('<H', self.read(2))
        self.get_extension(code)
    dispatch[EXT2[0]] = load_ext2

    def load_ext4(self):
        code, = unpack('<i', self.read(4))
        self.get_extension(code)
    dispatch[EXT4[0]] = load_ext4

    def get_extension(self, code):
        nil = []
        obj = _extension_cache.get(code, nil)
        if obj is not nil:
            self.append(obj)
            return
        key = _inverted_registry.get(code)
        if not key:
            if code <= 0: 
                
                raise UnpicklingError("EXT specifies code <= 0")
            raise ValueError("unregistered extension code %d" % code)
        obj = self.find_class(*key)
        _extension_cache[code] = obj
        self.append(obj)

    def find_class(self, module, name):
        
        sys.audit('pickle.find_class', module, name)
        if self.proto < 3 and self.fix_imports:
            if (module, name) in _compat_pickle.NAME_MAPPING:
                module, name = _compat_pickle.NAME_MAPPING[(module, name)]
            elif module in _compat_pickle.IMPORT_MAPPING:
                module = _compat_pickle.IMPORT_MAPPING[module]
        __import__(module, level=0)
        if self.proto >= 4:
            return _getattribute(sys.modules[module], name)[0]
        else:
            return getattr(sys.modules[module], name)

    def load_reduce(self):
        stack = self.stack
        args = stack.pop()
        func = stack[-1]
        stack[-1] = func(*args)
    dispatch[REDUCE[0]] = load_reduce

    def load_pop(self):
        if self.stack:
            del self.stack[-1]
        else:
            self.pop_mark()
    dispatch[POP[0]] = load_pop

    def load_pop_mark(self):
        self.pop_mark()
    dispatch[POP_MARK[0]] = load_pop_mark

    def load_dup(self):
        self.append(self.stack[-1])
    dispatch[DUP[0]] = load_dup

    def load_get(self):
        i = int(self.readline()[:-1])
        try:
            self.append(self.memo[i])
        except KeyError:
            msg = f'Memo value not found at index {i}'
            raise UnpicklingError(msg) from None
    dispatch[GET[0]] = load_get

    def load_binget(self):
        i = self.read(1)[0]
        try:
            self.append(self.memo[i])
        except KeyError as exc:
            msg = f'Memo value not found at index {i}'
            raise UnpicklingError(msg) from None
    dispatch[BINGET[0]] = load_binget

    def load_long_binget(self):
        i, = unpack('<I', self.read(4))
        try:
            self.append(self.memo[i])
        except KeyError as exc:
            msg = f'Memo value not found at index {i}'
            raise UnpicklingError(msg) from None
    dispatch[LONG_BINGET[0]] = load_long_binget

    def load_put(self):
        i = int(self.readline()[:-1])
        if i < 0:
            raise ValueError("negative PUT argument")
        self.memo[i] = self.stack[-1]
    dispatch[PUT[0]] = load_put

    def load_binput(self):
        i = self.read(1)[0]
        if i < 0:
            raise ValueError("negative BINPUT argument")
        self.memo[i] = self.stack[-1]
    dispatch[BINPUT[0]] = load_binput

    def load_long_binput(self):
        i, = unpack('<I', self.read(4))
        if i > maxsize:
            raise ValueError("negative LONG_BINPUT argument")
        self.memo[i] = self.stack[-1]
    dispatch[LONG_BINPUT[0]] = load_long_binput

    def load_memoize(self):
        memo = self.memo
        memo[len(memo)] = self.stack[-1]
    dispatch[MEMOIZE[0]] = load_memoize

    def load_append(self):
        stack = self.stack
        value = stack.pop()
        list = stack[-1]
        list.append(value)
    dispatch[APPEND[0]] = load_append

    def load_appends(self):
        items = self.pop_mark()
        list_obj = self.stack[-1]
        try:
            extend = list_obj.extend
        except AttributeError:
            pass
        else:
            extend(items)
            return
        
        
        
        append = list_obj.append
        for item in items:
            append(item)
    dispatch[APPENDS[0]] = load_appends

    def load_setitem(self):
        stack = self.stack
        value = stack.pop()
        key = stack.pop()
        dict = stack[-1]
        dict[key] = value
    dispatch[SETITEM[0]] = load_setitem

    def load_setitems(self):
        items = self.pop_mark()
        dict = self.stack[-1]
        for i in range(0, len(items), 2):
            dict[items[i]] = items[i + 1]
    dispatch[SETITEMS[0]] = load_setitems

    def load_additems(self):
        items = self.pop_mark()
        set_obj = self.stack[-1]
        if isinstance(set_obj, set):
            set_obj.update(items)
        else:
            add = set_obj.add
            for item in items:
                add(item)
    dispatch[ADDITEMS[0]] = load_additems

    def load_build(self):
        stack = self.stack
        state = stack.pop()
        inst = stack[-1]
        setstate = getattr(inst, "__setstate__", _NoValue)
        if setstate is not _NoValue:
            setstate(state)
            return
        slotstate = None
        if isinstance(state, tuple) and len(state) == 2:
            state, slotstate = state
        if state:
            inst_dict = inst.__dict__
            intern = sys.intern
            for k, v in state.items():
                if type(k) is str:
                    inst_dict[intern(k)] = v
                else:
                    inst_dict[k] = v
        if slotstate:
            for k, v in slotstate.items():
                setattr(inst, k, v)
    dispatch[BUILD[0]] = load_build

    def load_mark(self):
        self.metastack.append(self.stack)
        self.stack = []
        self.append = self.stack.append
    dispatch[MARK[0]] = load_mark

    def load_stop(self):
        value = self.stack.pop()
        raise _Stop(value)
    dispatch[STOP[0]] = load_stop




def _dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None):
    _Pickler(file, protocol, fix_imports=fix_imports,
             buffer_callback=buffer_callback).dump(obj)

def _dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None):
    f = io.BytesIO()
    _Pickler(f, protocol, fix_imports=fix_imports,
             buffer_callback=buffer_callback).dump(obj)
    res = f.getvalue()
    assert isinstance(res, bytes_types)
    return res

def _load(file, *, fix_imports=True, encoding="ASCII", errors="strict",
          buffers=None):
    return _Unpickler(file, fix_imports=fix_imports, buffers=buffers,
                     encoding=encoding, errors=errors).load()

def _loads(s, /, *, fix_imports=True, encoding="ASCII", errors="strict",
           buffers=None):
    if isinstance(s, str):
        raise TypeError("Can't load pickle from unicode string")
    file = io.BytesIO(s)
    return _Unpickler(file, fix_imports=fix_imports, buffers=buffers,
                      encoding=encoding, errors=errors).load()


try:
    from _pickle import (
        PickleError,
        PicklingError,
        UnpicklingError,
        Pickler,
        Unpickler,
        dump,
        dumps,
        load,
        loads
    )
except ImportError:
    Pickler, Unpickler = _Pickler, _Unpickler
    dump, dumps, load, loads = _dump, _dumps, _load, _loads


def _test():
    import doctest
    return doctest.testmod()

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser(
        description='display contents of the pickle files')
    parser.add_argument(
        'pickle_file', type=argparse.FileType('br'),
        nargs='*', help='the pickle file')
    parser.add_argument(
        '-t', '--test', action='store_true',
        help='run self-test suite')
    parser.add_argument(
        '-v', action='store_true',
        help='run verbosely; only affects self-test run')
    args = parser.parse_args()
    if args.test:
        _test()
    else:
        if not args.pickle_file:
            parser.print_help()
        else:
            import pprint
            for f in args.pickle_file:
                obj = load(f)
                pprint.pprint(obj)