home *** CD-ROM | disk | FTP | other *** search
/ linuxmafia.com 2016 / linuxmafia.com.tar / linuxmafia.com / pub / palmos / pippy-0.6beta-src.tar.gz / pippy-0.6beta-src.tar / pippy-0.6beta-src / src / Lib / pickle.py < prev    next >
Text File  |  2000-12-21  |  22KB  |  867 lines

  1. """Create portable serialized representations of Python objects.
  2.  
  3. See module cPickle for a (much) faster implementation.
  4. See module copy_reg for a mechanism for registering custom picklers.
  5.  
  6. Classes:
  7.  
  8.     Pickler
  9.     Unpickler
  10.  
  11. Functions:
  12.  
  13.     dump(object, file)
  14.     dumps(object) -> string
  15.     load(file) -> object
  16.     loads(string) -> object
  17.  
  18. Misc variables:
  19.  
  20.     __version__
  21.     format_version
  22.     compatible_formats
  23.  
  24. """
  25.  
  26. __version__ = "$Revision: 1.1.1.1 $"       # Code version
  27.  
  28. from types import *
  29. from copy_reg import dispatch_table, safe_constructors
  30. import string
  31. import marshal
  32. import sys
  33. import struct
  34.  
  35. format_version = "1.3"                     # File format version we write
  36. compatible_formats = ["1.0", "1.1", "1.2"] # Old format versions we can read
  37.  
  38. mdumps = marshal.dumps
  39. mloads = marshal.loads
  40.  
  41. PicklingError = "pickle.PicklingError"
  42. UnpicklingError = "pickle.UnpicklingError"
  43.  
  44. try:
  45.     from org.python.core import PyStringMap
  46. except ImportError:
  47.     PyStringMap = None
  48.  
  49. MARK            = '('
  50. STOP            = '.'
  51. POP             = '0'
  52. POP_MARK        = '1'
  53. DUP             = '2'
  54. FLOAT           = 'F'
  55. INT             = 'I'
  56. BININT          = 'J'
  57. BININT1         = 'K'
  58. LONG            = 'L'
  59. BININT2         = 'M'
  60. NONE            = 'N'
  61. PERSID          = 'P'
  62. BINPERSID       = 'Q'
  63. REDUCE          = 'R'
  64. STRING          = 'S'
  65. BINSTRING       = 'T'
  66. SHORT_BINSTRING = 'U'
  67. APPEND          = 'a'
  68. BUILD           = 'b'
  69. GLOBAL          = 'c'
  70. DICT            = 'd'
  71. EMPTY_DICT      = '}'
  72. APPENDS         = 'e'
  73. GET             = 'g'
  74. BINGET          = 'h'
  75. INST            = 'i'
  76. LONG_BINGET     = 'j'
  77. LIST            = 'l'
  78. EMPTY_LIST      = ']'
  79. OBJ             = 'o'
  80. PUT             = 'p'
  81. BINPUT          = 'q'
  82. LONG_BINPUT     = 'r'
  83. SETITEM         = 's'
  84. TUPLE           = 't'
  85. EMPTY_TUPLE     = ')'
  86. SETITEMS        = 'u'
  87. BINFLOAT        = 'G'
  88.  
  89. class Pickler:
  90.  
  91.     def __init__(self, file, bin = 0):
  92.         self.write = file.write
  93.         self.memo = {}
  94.         self.bin = bin
  95.  
  96.     def dump(self, object):
  97.         self.save(object)
  98.         self.write(STOP)
  99.  
  100.     def put(self, i):
  101.         if (self.bin):
  102.             s = mdumps(i)[1:]
  103.             if (i < 256):
  104.                 return BINPUT + s[0]
  105.  
  106.             return LONG_BINPUT + s
  107.  
  108.         return PUT + `i` + '\n'
  109.  
  110.     def get(self, i):
  111.         if (self.bin):
  112.             s = mdumps(i)[1:]
  113.  
  114.             if (i < 256):
  115.                 return BINGET + s[0]
  116.  
  117.             return LONG_BINGET + s
  118.  
  119.         return GET + `i` + '\n'
  120.         
  121.     def save(self, object, pers_save = 0):
  122.         memo = self.memo
  123.  
  124.         if (not pers_save):
  125.             pid = self.persistent_id(object)
  126.             if (pid is not None):
  127.                 self.save_pers(pid)
  128.                 return
  129.  
  130.         d = id(object)
  131.  
  132.         t = type(object)
  133.  
  134.         if ((t is TupleType) and (len(object) == 0)):
  135.             if (self.bin):
  136.                 self.save_empty_tuple(object)
  137.             else:
  138.                 self.save_tuple(object)
  139.             return
  140.  
  141.         if memo.has_key(d):
  142.             self.write(self.get(memo[d][0]))
  143.             return
  144.  
  145.         try:
  146.             f = self.dispatch[t]
  147.         except KeyError:
  148.             pid = self.inst_persistent_id(object)
  149.             if pid is not None:
  150.                 self.save_pers(pid)
  151.                 return
  152.  
  153.             try:
  154.                 reduce = dispatch_table[t]
  155.             except KeyError:
  156.                 try:
  157.                     reduce = object.__reduce__
  158.                 except AttributeError:
  159.                     raise PicklingError, \
  160.                         "can't pickle %s object: %s" % (`t.__name__`,
  161.                                                          `object`)
  162.                 else:
  163.                     tup = reduce()
  164.             else:
  165.                 tup = reduce(object)
  166.  
  167.             if type(tup) is StringType:
  168.                 self.save_global(object, tup)
  169.                 return
  170.  
  171.             if (type(tup) is not TupleType):
  172.                 raise PicklingError, "Value returned by %s must be a " \
  173.                                      "tuple" % reduce
  174.  
  175.             l = len(tup)
  176.    
  177.             if ((l != 2) and (l != 3)):
  178.                 raise PicklingError, "tuple returned by %s must contain " \
  179.                                      "only two or three elements" % reduce
  180.  
  181.             callable = tup[0]
  182.             arg_tup  = tup[1]
  183.           
  184.             if (l > 2):
  185.                 state = tup[2]
  186.             else:
  187.                 state = None
  188.  
  189.             if type(arg_tup) is not TupleType and arg_tup is not None:
  190.                 raise PicklingError, "Second element of tuple returned " \
  191.                                      "by %s must be a tuple" % reduce
  192.  
  193.             self.save_reduce(callable, arg_tup, state) 
  194.             memo_len = len(memo)
  195.             self.write(self.put(memo_len))
  196.             memo[d] = (memo_len, object)
  197.             return
  198.  
  199.         f(self, object)
  200.  
  201.     def persistent_id(self, object):
  202.         return None
  203.  
  204.     def inst_persistent_id(self, object):
  205.         return None
  206.  
  207.     def save_pers(self, pid):
  208.         if (not self.bin):
  209.             self.write(PERSID + str(pid) + '\n')
  210.         else:
  211.             self.save(pid, 1)
  212.             self.write(BINPERSID)
  213.  
  214.     def save_reduce(self, callable, arg_tup, state = None):
  215.         write = self.write
  216.         save = self.save
  217.  
  218.         save(callable)
  219.         save(arg_tup)
  220.         write(REDUCE)
  221.         
  222.         if (state is not None):
  223.             save(state)
  224.             write(BUILD)
  225.  
  226.     dispatch = {}
  227.  
  228.     def save_none(self, object):
  229.         self.write(NONE)
  230.     dispatch[NoneType] = save_none
  231.  
  232.     def save_int(self, object):
  233.         if (self.bin):
  234.             i = mdumps(object)[1:]
  235.             if (i[-2:] == '\000\000'):
  236.                 if (i[-3] == '\000'):
  237.                     self.write(BININT1 + i[:-3])
  238.                     return
  239.  
  240.                 self.write(BININT2 + i[:-2])
  241.                 return
  242.  
  243.             self.write(BININT + i)
  244.         else:
  245.             self.write(INT + `object` + '\n')
  246.     dispatch[IntType] = save_int
  247.  
  248.     def save_long(self, object):
  249.         self.write(LONG + `object` + '\n')
  250.     dispatch[LongType] = save_long
  251.  
  252.     def save_float(self, object, pack=struct.pack):
  253.         if self.bin:
  254.             self.write(BINFLOAT + pack('>d', object))
  255.         else:
  256.             self.write(FLOAT + `object` + '\n')
  257.     dispatch[FloatType] = save_float
  258.  
  259.     def save_string(self, object):
  260.         d = id(object)
  261.         memo = self.memo
  262.  
  263.         if (self.bin):
  264.             l = len(object)
  265.             s = mdumps(l)[1:]
  266.             if (l < 256):
  267.                 self.write(SHORT_BINSTRING + s[0] + object)
  268.             else:
  269.                 self.write(BINSTRING + s + object)
  270.         else:
  271.             self.write(STRING + `object` + '\n')
  272.  
  273.         memo_len = len(memo)
  274.         self.write(self.put(memo_len))
  275.         memo[d] = (memo_len, object)
  276.     dispatch[StringType] = save_string
  277.  
  278.     def save_tuple(self, object):
  279.  
  280.         write = self.write
  281.         save  = self.save
  282.         memo  = self.memo
  283.  
  284.         d = id(object)
  285.  
  286.         write(MARK)
  287.  
  288.         for element in object:
  289.             save(element)
  290.  
  291.         if (len(object) and memo.has_key(d)):
  292.             if (self.bin):
  293.                 write(POP_MARK + self.get(memo[d][0]))
  294.                 return
  295.            
  296.             write(POP * (len(object) + 1) + self.get(memo[d][0]))
  297.             return
  298.  
  299.         memo_len = len(memo)
  300.         self.write(TUPLE + self.put(memo_len))
  301.         memo[d] = (memo_len, object)
  302.     dispatch[TupleType] = save_tuple
  303.  
  304.     def save_empty_tuple(self, object):
  305.         self.write(EMPTY_TUPLE)
  306.  
  307.     def save_list(self, object):
  308.         d = id(object)
  309.  
  310.         write = self.write
  311.         save  = self.save
  312.         memo  = self.memo
  313.  
  314.         if (self.bin):
  315.             write(EMPTY_LIST)
  316.         else:
  317.             write(MARK + LIST)
  318.  
  319.         memo_len = len(memo)
  320.         write(self.put(memo_len))
  321.         memo[d] = (memo_len, object)
  322.  
  323.         using_appends = (self.bin and (len(object) > 1))
  324.  
  325.         if (using_appends):
  326.             write(MARK)
  327.  
  328.         for element in object:
  329.             save(element)
  330.   
  331.             if (not using_appends):
  332.                 write(APPEND)
  333.  
  334.         if (using_appends):
  335.             write(APPENDS)
  336.     dispatch[ListType] = save_list
  337.  
  338.     def save_dict(self, object):
  339.         d = id(object)
  340.  
  341.         write = self.write
  342.         save  = self.save
  343.         memo  = self.memo
  344.  
  345.         if (self.bin):
  346.             write(EMPTY_DICT)
  347.         else:
  348.             write(MARK + DICT)
  349.  
  350.         memo_len = len(memo)
  351.         self.write(self.put(memo_len))
  352.         memo[d] = (memo_len, object)
  353.  
  354.         using_setitems = (self.bin and (len(object) > 1))
  355.  
  356.         if (using_setitems):
  357.             write(MARK)
  358.  
  359.         items = object.items()
  360.         for key, value in items:
  361.             save(key)
  362.             save(value)
  363.  
  364.             if (not using_setitems):
  365.                 write(SETITEM)
  366.  
  367.         if (using_setitems):
  368.             write(SETITEMS)
  369.  
  370.     dispatch[DictionaryType] = save_dict
  371.     if not PyStringMap is None:
  372.         dispatch[PyStringMap] = save_dict
  373.  
  374.     def save_inst(self, object):
  375.         d = id(object)
  376.         cls = object.__class__
  377.  
  378.         memo  = self.memo
  379.         write = self.write
  380.         save  = self.save
  381.  
  382.         if hasattr(object, '__getinitargs__'):
  383.             args = object.__getinitargs__()
  384.             len(args) # XXX Assert it's a sequence
  385.             _keep_alive(args, memo)
  386.         else:
  387.             args = ()
  388.  
  389.         write(MARK)
  390.  
  391.         if (self.bin):
  392.             save(cls)
  393.  
  394.         for arg in args:
  395.             save(arg)
  396.  
  397.         memo_len = len(memo)
  398.         if (self.bin):
  399.             write(OBJ + self.put(memo_len))
  400.         else:
  401.             write(INST + cls.__module__ + '\n' + cls.__name__ + '\n' +
  402.                 self.put(memo_len))
  403.  
  404.         memo[d] = (memo_len, object)
  405.  
  406.         try:
  407.             getstate = object.__getstate__
  408.         except AttributeError:
  409.             stuff = object.__dict__
  410.         else:
  411.             stuff = getstate()
  412.             _keep_alive(stuff, memo)
  413.         save(stuff)
  414.         write(BUILD)
  415.     dispatch[InstanceType] = save_inst
  416.  
  417.     def save_global(self, object, name = None):
  418.         write = self.write
  419.         memo = self.memo
  420.  
  421.         if (name is None):
  422.             name = object.__name__
  423.  
  424.         try:
  425.             module = object.__module__
  426.         except AttributeError:
  427.             module = whichmodule(object, name)
  428.  
  429.         memo_len = len(memo)
  430.         write(GLOBAL + module + '\n' + name + '\n' +
  431.             self.put(memo_len))
  432.         memo[id(object)] = (memo_len, object)
  433.     dispatch[ClassType] = save_global
  434.     dispatch[FunctionType] = save_global
  435.     dispatch[BuiltinFunctionType] = save_global
  436.  
  437.  
  438. def _keep_alive(x, memo):
  439.     """Keeps a reference to the object x in the memo.
  440.  
  441.     Because we remember objects by their id, we have
  442.     to assure that possibly temporary objects are kept
  443.     alive by referencing them.
  444.     We store a reference at the id of the memo, which should
  445.     normally not be used unless someone tries to deepcopy
  446.     the memo itself...
  447.     """
  448.     try:
  449.         memo[id(memo)].append(x)
  450.     except KeyError:
  451.         # aha, this is the first one :-)
  452.         memo[id(memo)]=[x]
  453.  
  454.  
  455. classmap = {}
  456.  
  457. # This is no longer used to find classes, but still for functions
  458. def whichmodule(cls, clsname):
  459.     """Figure out the module in which a class occurs.
  460.  
  461.     Search sys.modules for the module.
  462.     Cache in classmap.
  463.     Return a module name.
  464.     If the class cannot be found, return __main__.
  465.     """
  466.     if classmap.has_key(cls):
  467.         return classmap[cls]
  468.  
  469.     for name, module in sys.modules.items():
  470.         if name != '__main__' and \
  471.             hasattr(module, clsname) and \
  472.             getattr(module, clsname) is cls:
  473.             break
  474.     else:
  475.         name = '__main__'
  476.     classmap[cls] = name
  477.     return name
  478.  
  479.  
  480. class Unpickler:
  481.  
  482.     def __init__(self, file):
  483.         self.readline = file.readline
  484.         self.read = file.read
  485.         self.memo = {}
  486.  
  487.     def load(self):
  488.         self.mark = ['spam'] # Any new unique object
  489.         self.stack = []
  490.         self.append = self.stack.append
  491.         read = self.read
  492.         dispatch = self.dispatch
  493.         try:
  494.             while 1:
  495.                 key = read(1)
  496.                 dispatch[key](self)
  497.         except STOP, value:
  498.             return value
  499.  
  500.     def marker(self):
  501.         stack = self.stack
  502.         mark = self.mark
  503.         k = len(stack)-1
  504.         while stack[k] is not mark: k = k-1
  505.         return k
  506.  
  507.     dispatch = {}
  508.  
  509.     def load_eof(self):
  510.         raise EOFError
  511.     dispatch[''] = load_eof
  512.  
  513.     def load_persid(self):
  514.         pid = self.readline()[:-1]
  515.         self.append(self.persistent_load(pid))
  516.     dispatch[PERSID] = load_persid
  517.  
  518.     def load_binpersid(self):
  519.         stack = self.stack
  520.          
  521.         pid = stack[-1]
  522.         del stack[-1]
  523.  
  524.         self.append(self.persistent_load(pid))
  525.     dispatch[BINPERSID] = load_binpersid
  526.  
  527.     def load_none(self):
  528.         self.append(None)
  529.     dispatch[NONE] = load_none
  530.  
  531.     def load_int(self):
  532.         self.append(string.atoi(self.readline()[:-1]))
  533.     dispatch[INT] = load_int
  534.  
  535.     def load_binint(self):
  536.         self.append(mloads('i' + self.read(4)))
  537.     dispatch[BININT] = load_binint
  538.  
  539.     def load_binint1(self):
  540.         self.append(mloads('i' + self.read(1) + '\000\000\000'))
  541.     dispatch[BININT1] = load_binint1
  542.  
  543.     def load_binint2(self):
  544.         self.append(mloads('i' + self.read(2) + '\000\000'))
  545.     dispatch[BININT2] = load_binint2
  546.  
  547.     def load_long(self):
  548.         self.append(string.atol(self.readline()[:-1], 0))
  549.     dispatch[LONG] = load_long
  550.  
  551.     def load_float(self):
  552.         self.append(string.atof(self.readline()[:-1]))
  553.     dispatch[FLOAT] = load_float
  554.  
  555.     def load_binfloat(self, unpack=struct.unpack):
  556.         self.append(unpack('>d', self.read(8))[0])
  557.     dispatch[BINFLOAT] = load_binfloat
  558.  
  559.     def load_string(self):
  560.         self.append(eval(self.readline()[:-1],
  561.                          {'__builtins__': {}})) # Let's be careful
  562.     dispatch[STRING] = load_string
  563.  
  564.     def load_binstring(self):
  565.         len = mloads('i' + self.read(4))
  566.         self.append(self.read(len))
  567.     dispatch[BINSTRING] = load_binstring
  568.  
  569.     def load_short_binstring(self):
  570.         len = mloads('i' + self.read(1) + '\000\000\000')
  571.         self.append(self.read(len))
  572.     dispatch[SHORT_BINSTRING] = load_short_binstring
  573.  
  574.     def load_tuple(self):
  575.         k = self.marker()
  576.         self.stack[k:] = [tuple(self.stack[k+1:])]
  577.     dispatch[TUPLE] = load_tuple
  578.  
  579.     def load_empty_tuple(self):
  580.         self.stack.append(())
  581.     dispatch[EMPTY_TUPLE] = load_empty_tuple
  582.  
  583.     def load_empty_list(self):
  584.         self.stack.append([])
  585.     dispatch[EMPTY_LIST] = load_empty_list
  586.  
  587.     def load_empty_dictionary(self):
  588.         self.stack.append({})
  589.     dispatch[EMPTY_DICT] = load_empty_dictionary
  590.  
  591.     def load_list(self):
  592.         k = self.marker()
  593.         self.stack[k:] = [self.stack[k+1:]]
  594.     dispatch[LIST] = load_list
  595.  
  596.     def load_dict(self):
  597.         k = self.marker()
  598.         d = {}
  599.         items = self.stack[k+1:]
  600.         for i in range(0, len(items), 2):
  601.             key = items[i]
  602.             value = items[i+1]
  603.             d[key] = value
  604.         self.stack[k:] = [d]
  605.     dispatch[DICT] = load_dict
  606.  
  607.     def load_inst(self):
  608.         k = self.marker()
  609.         args = tuple(self.stack[k+1:])
  610.         del self.stack[k:]
  611.         module = self.readline()[:-1]
  612.         name = self.readline()[:-1]
  613.         klass = self.find_class(module, name)
  614.         instantiated = 0
  615.         if (not args and type(klass) is ClassType and
  616.             not hasattr(klass, "__getinitargs__")):
  617.             try:
  618.                 value = _EmptyClass()
  619.                 value.__class__ = klass
  620.                 instantiated = 1
  621.             except RuntimeError:
  622.                 # In restricted execution, assignment to inst.__class__ is
  623.                 # prohibited
  624.                 pass
  625.         if not instantiated:
  626.             try:
  627.                 value = apply(klass, args)
  628.             except TypeError, err:
  629.                 raise TypeError, "in constructor for %s: %s" % (
  630.                     klass.__name__, str(err)), sys.exc_info()[2]
  631.         self.append(value)
  632.     dispatch[INST] = load_inst
  633.  
  634.     def load_obj(self):
  635.         stack = self.stack
  636.         k = self.marker()
  637.         klass = stack[k + 1]
  638.         del stack[k + 1]
  639.         args = tuple(stack[k + 1:]) 
  640.         del stack[k:]
  641.         instantiated = 0
  642.         if (not args and type(klass) is ClassType and
  643.             not hasattr(klass, "__getinitargs__")):
  644.             try:
  645.                 value = _EmptyClass()
  646.                 value.__class__ = klass
  647.                 instantiated = 1
  648.             except RuntimeError:
  649.                 # In restricted execution, assignment to inst.__class__ is
  650.                 # prohibited
  651.                 pass
  652.         if not instantiated:
  653.             value = apply(klass, args)
  654.         self.append(value)
  655.     dispatch[OBJ] = load_obj                
  656.  
  657.     def load_global(self):
  658.         module = self.readline()[:-1]
  659.         name = self.readline()[:-1]
  660.         klass = self.find_class(module, name)
  661.         self.append(klass)
  662.     dispatch[GLOBAL] = load_global
  663.  
  664.     def find_class(self, module, name):
  665.         try:
  666.             __import__(module)
  667.             mod = sys.modules[module]
  668.             klass = getattr(mod, name)
  669.         except (ImportError, KeyError, AttributeError):
  670.             raise SystemError, \
  671.                   "Failed to import class %s from module %s" % \
  672.                   (name, module)
  673.         return klass
  674.  
  675.     def load_reduce(self):
  676.         stack = self.stack
  677.  
  678.         callable = stack[-2]
  679.         arg_tup  = stack[-1]
  680.         del stack[-2:]
  681.  
  682.         if type(callable) is not ClassType:
  683.             if not safe_constructors.has_key(callable):
  684.                 try:
  685.                     safe = callable.__safe_for_unpickling__
  686.                 except AttributeError:
  687.                     safe = None
  688.  
  689.                 if (not safe):
  690.                    raise UnpicklingError, "%s is not safe for " \
  691.                                           "unpickling" % callable
  692.  
  693.         if arg_tup is None:
  694.             value = callable.__basicnew__()
  695.         else:
  696.             value = apply(callable, arg_tup)
  697.         self.append(value)
  698.     dispatch[REDUCE] = load_reduce
  699.  
  700.     def load_pop(self):
  701.         del self.stack[-1]
  702.     dispatch[POP] = load_pop
  703.  
  704.     def load_pop_mark(self):
  705.         k = self.marker()
  706.         del self.stack[k:]
  707.     dispatch[POP_MARK] = load_pop_mark
  708.  
  709.     def load_dup(self):
  710.         self.append(self.stack[-1])
  711.     dispatch[DUP] = load_dup
  712.  
  713.     def load_get(self):
  714.         self.append(self.memo[self.readline()[:-1]])
  715.     dispatch[GET] = load_get
  716.  
  717.     def load_binget(self):
  718.         i = mloads('i' + self.read(1) + '\000\000\000')
  719.         self.append(self.memo[`i`])
  720.     dispatch[BINGET] = load_binget
  721.  
  722.     def load_long_binget(self):
  723.         i = mloads('i' + self.read(4))
  724.         self.append(self.memo[`i`])
  725.     dispatch[LONG_BINGET] = load_long_binget
  726.  
  727.     def load_put(self):
  728.         self.memo[self.readline()[:-1]] = self.stack[-1]
  729.     dispatch[PUT] = load_put
  730.  
  731.     def load_binput(self):
  732.         i = mloads('i' + self.read(1) + '\000\000\000')
  733.         self.memo[`i`] = self.stack[-1]
  734.     dispatch[BINPUT] = load_binput
  735.  
  736.     def load_long_binput(self):
  737.         i = mloads('i' + self.read(4))
  738.         self.memo[`i`] = self.stack[-1]
  739.     dispatch[LONG_BINPUT] = load_long_binput
  740.  
  741.     def load_append(self):
  742.         stack = self.stack
  743.         value = stack[-1]
  744.         del stack[-1]
  745.         list = stack[-1]
  746.         list.append(value)
  747.     dispatch[APPEND] = load_append
  748.  
  749.     def load_appends(self):
  750.         stack = self.stack
  751.         mark = self.marker()
  752.         list = stack[mark - 1]
  753.         for i in range(mark + 1, len(stack)):
  754.             list.append(stack[i])
  755.  
  756.         del stack[mark:]
  757.     dispatch[APPENDS] = load_appends
  758.            
  759.     def load_setitem(self):
  760.         stack = self.stack
  761.         value = stack[-1]
  762.         key = stack[-2]
  763.         del stack[-2:]
  764.         dict = stack[-1]
  765.         dict[key] = value
  766.     dispatch[SETITEM] = load_setitem
  767.  
  768.     def load_setitems(self):
  769.         stack = self.stack
  770.         mark = self.marker()
  771.         dict = stack[mark - 1]
  772.         for i in range(mark + 1, len(stack), 2):
  773.             dict[stack[i]] = stack[i + 1]
  774.  
  775.         del stack[mark:]
  776.     dispatch[SETITEMS] = load_setitems
  777.  
  778.     def load_build(self):
  779.         stack = self.stack
  780.         value = stack[-1]
  781.         del stack[-1]
  782.         inst = stack[-1]
  783.         try:
  784.             setstate = inst.__setstate__
  785.         except AttributeError:
  786.             try:
  787.                 inst.__dict__.update(value)
  788.             except RuntimeError:
  789.                 # XXX In restricted execution, the instance's __dict__ is not
  790.                 # accessible.  Use the old way of unpickling the instance
  791.                 # variables.  This is a semantic different when unpickling in
  792.                 # restricted vs. unrestricted modes.
  793.                 for k, v in value.items():
  794.                     setattr(inst, k, v)
  795.         else:
  796.             setstate(value)
  797.     dispatch[BUILD] = load_build
  798.  
  799.     def load_mark(self):
  800.         self.append(self.mark)
  801.     dispatch[MARK] = load_mark
  802.  
  803.     def load_stop(self):
  804.         value = self.stack[-1]
  805.         del self.stack[-1]
  806.         raise STOP, value
  807.     dispatch[STOP] = load_stop
  808.  
  809. # Helper class for load_inst/load_obj
  810.  
  811. class _EmptyClass:
  812.     pass
  813.  
  814. # Shorthands
  815.  
  816. from StringIO import StringIO
  817.  
  818. def dump(object, file, bin = 0):
  819.     Pickler(file, bin).dump(object)
  820.  
  821. def dumps(object, bin = 0):
  822.     file = StringIO()
  823.     Pickler(file, bin).dump(object)
  824.     return file.getvalue()
  825.  
  826. def load(file):
  827.     return Unpickler(file).load()
  828.  
  829. def loads(str):
  830.     file = StringIO(str)
  831.     return Unpickler(file).load()
  832.  
  833.  
  834. # The rest is used for testing only
  835.  
  836. class C:
  837.     def __cmp__(self, other):
  838.         return cmp(self.__dict__, other.__dict__)
  839.  
  840. def test():
  841.     fn = 'out'
  842.     c = C()
  843.     c.foo = 1
  844.     c.bar = 2
  845.     x = [0, 1, 2, 3]
  846.     y = ('abc', 'abc', c, c)
  847.     x.append(y)
  848.     x.append(y)
  849.     x.append(5)
  850.     f = open(fn, 'w')
  851.     F = Pickler(f)
  852.     F.dump(x)
  853.     f.close()
  854.     f = open(fn, 'r')
  855.     U = Unpickler(f)
  856.     x2 = U.load()
  857.     print x
  858.     print x2
  859.     print x == x2
  860.     print map(id, x)
  861.     print map(id, x2)
  862.     print F.memo
  863.     print U.memo
  864.  
  865. if __name__ == '__main__':
  866.     test()
  867.