]> granicus.if.org Git - python/commitdiff
New version by Digital Creations, supports binary format compatible
authorGuido van Rossum <guido@python.org>
Wed, 9 Apr 1997 17:32:51 +0000 (17:32 +0000)
committerGuido van Rossum <guido@python.org>
Wed, 9 Apr 1997 17:32:51 +0000 (17:32 +0000)
with cPickle.

Lib/pickle.py

index bfe49f91295743e76c483e30f320553acd8c04ce..2a4357d7244c915e7463b79f780bd7245ca17c7b 100644 (file)
@@ -1,3 +1,56 @@
+#     $Id$
+#
+#     Copyright 
+#
+#       Copyright 1996 Digital Creations, L.C., 910 Princess Anne
+#       Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
+#       rights reserved.  Copyright in this software is owned by DCLC,
+#       unless otherwise indicated. Permission to use, copy and
+#       distribute this software is hereby granted, provided that the
+#       above copyright notice appear in all copies and that both that
+#       copyright notice and this permission notice appear. Note that
+#       any product, process or technology described in this software
+#       may be the subject of other Intellectual Property rights
+#       reserved by Digital Creations, L.C. and are not licensed
+#       hereunder.
+#
+#     Trademarks 
+#
+#       Digital Creations & DCLC, are trademarks of Digital Creations, L.C..
+#       All other trademarks are owned by their respective companies. 
+#
+#     No Warranty 
+#
+#       The software is provided "as is" without warranty of any kind,
+#       either express or implied, including, but not limited to, the
+#       implied warranties of merchantability, fitness for a particular
+#       purpose, or non-infringement. This software could include
+#       technical inaccuracies or typographical errors. Changes are
+#       periodically made to the software; these changes will be
+#       incorporated in new editions of the software. DCLC may make
+#       improvements and/or changes in this software at any time
+#       without notice.
+#
+#     Limitation Of Liability 
+#
+#       In no event will DCLC be liable for direct, indirect, special,
+#       incidental, economic, cover, or consequential damages arising
+#       out of the use of or inability to use this software even if
+#       advised of the possibility of such damages. Some states do not
+#       allow the exclusion or limitation of implied warranties or
+#       limitation of liability for incidental or consequential
+#       damages, so the above limitation or exclusion may not apply to
+#       you.
+#  
+#
+# If you have questions regarding this software,
+# contact:
+#
+#   Jim Fulton, jim@digicool.com
+#
+#   (540) 371-6909
+#
+
 """\
 Pickling Algorithm
 ------------------
@@ -88,13 +141,13 @@ The interface is as follows:
 
 To pickle an object x onto a file f, open for writing:
 
-       p = pickle.Pickler(f)
-       p.dump(x)
+    p = pickle.Pickler(f)
+    p.dump(x)
 
 To unpickle an object x from a file f, open for reading:
 
-       u = pickle.Unpickler(f)
-       x = u.load()
+    u = pickle.Unpickler(f)
+    x = u.load()
 
 The Pickler class only calls the method f.write with a string argument
 (XXX possibly the interface should pass f.write instead of f).
@@ -128,463 +181,768 @@ the old value, not the modified one.  (XXX There are two problems here:
 I have no answers.  Garbage Collection may also become a problem here.)
 """
 
-__version__ = "1.6"                    # Code version
+__version__ = "1.7"                     # Code version
 
 from types import *
-import string
+from copy_reg import *
+import string, marshal
 
-format_version = "1.1"                 # File format version we write
-compatible_formats = ["1.0"]           # Old format versions we can read
+format_version = "1.2"                  # File format version we write
+compatible_formats = ["1.0", "1.1"]     # Old format versions we can read
 
-PicklingError = "pickle.PicklingError"
+mdumps = marshal.dumps
+mloads = marshal.loads
 
-AtomicTypes = [NoneType, IntType, FloatType, StringType]
-
-def safe(object):
-       t = type(object)
-       if t in AtomicTypes:
-               return 1
-       if t is TupleType:
-               for item in object:
-                       if not safe(item): return 0
-               return 1
-       return 0
-
-MARK = '('
-POP = '0'
-DUP = '2'
-STOP = '.'
-TUPLE = 't'
-LIST = 'l'
-DICT = 'd'
-INST = 'i'
-CLASS = 'c'
-GET = 'g'
-PUT = 'p'
-APPEND = 'a'
-SETITEM = 's'
-BUILD = 'b'
-NONE = 'N'
-INT = 'I'
-LONG = 'L'
-FLOAT = 'F'
-STRING = 'S'
-PERSID = 'P'
-AtomicKeys = [NONE, INT, LONG, FLOAT, STRING]
-AtomicMap = {
-       NoneType: NONE,
-       IntType: INT,
-       LongType: LONG,
-       FloatType: FLOAT,
-       StringType: STRING,
-}
+PicklingError = "pickle.PicklingError"
+UnpicklingError = "pickle.UnpicklingError"
+
+MARK            = '('
+STOP            = '.'
+POP             = '0'
+POP_MARK        = '1'
+DUP             = '2'
+FLOAT           = 'F'
+INT             = 'I'
+BININT          = 'J'
+BININT1         = 'K'
+LONG            = 'L'
+BININT2         = 'M'
+NONE            = 'N'
+PERSID          = 'P'
+BINPERSID       = 'Q'
+REDUCE          = 'R'
+STRING          = 'S'
+BINSTRING       = 'T'
+SHORT_BINSTRING = 'U'
+APPEND          = 'a'
+BUILD           = 'b'
+GLOBAL          = 'c'
+DICT            = 'd'
+EMPTY_DICT      = '}'
+APPENDS         = 'e'
+GET             = 'g'
+BINGET          = 'h'
+INST            = 'i'
+LONG_BINGET     = 'j'
+LIST            = 'l'
+EMPTY_LIST      = ']'
+OBJ             = 'o'
+PUT             = 'p'
+BINPUT          = 'q'
+LONG_BINPUT     = 'r'
+SETITEM         = 's'
+TUPLE           = 't'
+EMPTY_TUPLE     = ')'
+SETITEMS        = 'u'
 
 class Pickler:
 
-       def __init__(self, file):
-               self.write = file.write
-               self.memo = {}
-
-       def dump(self, object):
-               self.save(object)
-               self.write(STOP)
-
-       def save(self, object):
-               pid = self.persistent_id(object)
-               if pid:
-                       self.write(PERSID + str(pid) + '\n')
-                       return
-               d = id(object)
-               if self.memo.has_key(d):
-                       self.write(GET + `d` + '\n')
-                       return
-               t = type(object)
-               try:
-                       f = self.dispatch[t]
-               except KeyError:
-                       if hasattr(object, '__class__'):
-                               f = self.dispatch[InstanceType]
-                       else:
-                               raise PicklingError, \
-                               "can't pickle %s objects" % `t.__name__`
-               f(self, object)
-
-       def persistent_id(self, object):
-               return None
-
-       dispatch = {}
-
-       def save_none(self, object):
-               self.write(NONE)
-       dispatch[NoneType] = save_none
-
-       def save_int(self, object):
-               self.write(INT + `object` + '\n')
-       dispatch[IntType] = save_int
-
-       def save_long(self, object):
-               self.write(LONG + `object` + '\n')
-       dispatch[LongType] = save_long
-
-       def save_float(self, object):
-               self.write(FLOAT + `object` + '\n')
-       dispatch[FloatType] = save_float
-
-       def save_string(self, object):
-               d = id(object)
-               self.write(STRING + `object` + '\n')
-               self.write(PUT + `d` + '\n')
-               self.memo[d] = object
-       dispatch[StringType] = save_string
-
-       def save_tuple(self, object):
-               d = id(object)
-               write = self.write
-               save = self.save
-               has_key = self.memo.has_key
-               write(MARK)
-               n = len(object)
-               for k in range(n):
-                       save(object[k])
-                       if has_key(d):
-                               # Saving object[k] has saved us!
-                               while k >= 0:
-                                       write(POP)
-                                       k = k-1
-                               write(GET + `d` + '\n')
-                               break
-               else:
-                       write(TUPLE + PUT + `d` + '\n')
-                       self.memo[d] = object
-       dispatch[TupleType] = save_tuple
-
-       def save_list(self, object):
-               d = id(object)
-               write = self.write
-               save = self.save
-               write(MARK)
-               n = len(object)
-               for k in range(n):
-                       item = object[k]
-                       if not safe(item):
-                               break
-                       save(item)
-               else:
-                       k = n
-               write(LIST + PUT + `d` + '\n')
-               self.memo[d] = object
-               for k in range(k, n):
-                       item = object[k]
-                       save(item)
-                       write(APPEND)
-       dispatch[ListType] = save_list
-
-       def save_dict(self, object):
-               d = id(object)
-               write = self.write
-               save = self.save
-               write(MARK)
-               items = object.items()
-               n = len(items)
-               for k in range(n):
-                       key, value = items[k]
-                       if not safe(key) or not safe(value):
-                               break
-                       save(key)
-                       save(value)
-               else:
-                       k = n
-               self.write(DICT + PUT + `d` + '\n')
-               self.memo[d] = object
-               for k in range(k, n):
-                       key, value = items[k]
-                       save(key)
-                       save(value)
-                       write(SETITEM)
-       dispatch[DictionaryType] = save_dict
-
-       def save_inst(self, object):
-               d = id(object)
-               cls = object.__class__
-               write = self.write
-               save = self.save
-               module = whichmodule(cls)
-               name = cls.__name__
-               if hasattr(object, '__getinitargs__'):
-                       args = object.__getinitargs__()
-                       len(args) # XXX Assert it's a sequence
-               else:
-                       args = ()
-               write(MARK)
-               for arg in args:
-                       save(arg)
-               write(INST + module + '\n' + name + '\n' +
-                     PUT + `d` + '\n')
-               self.memo[d] = object
-               try:
-                       getstate = object.__getstate__
-               except AttributeError:
-                       stuff = object.__dict__
-               else:
-                       stuff = getstate()
-               save(stuff)
-               write(BUILD)
-       dispatch[InstanceType] = save_inst
-
-       def save_class(self, object):
-               d = id(object)
-               module = whichmodule(object)
-               name = object.__name__
-               self.write(CLASS + module + '\n' + name + '\n' + 
-                          PUT + `d` + '\n')
-       dispatch[ClassType] = save_class
+    def __init__(self, file, bin = 0):
+        self.write = file.write
+        self.memo = {}
+        self.bin = bin
+
+    def dump(self, object):
+        self.save(object)
+        self.write(STOP)
+
+    def dump_special(self, callable, args, state = None):
+       if (type(args) is not TupleType):
+            raise PicklingError, "Second argument to dump_special " \
+                                 "must be a tuple"
+
+        self.save_reduce(callable, args, state)
+        self.write(STOP)
+
+    def put(self, i):
+        if (self.bin):
+            s = mdumps(i)[1:]
+            if (i < 256):
+                return BINPUT + s[0]
+
+            return LONG_BINPUT + s
+
+        return PUT + `i` + '\n'
+
+    def get(self, i):
+        if (self.bin):
+            s = mdumps(i)[1:]
+
+            if (i < 256):
+                return BINGET + s[0]
+
+            return LONG_BINGET + s
+
+        return GET + `i` + '\n'
+        
+    def save(self, object, pers_save = 0):
+        memo = self.memo
+
+        if (not pers_save):
+           pid = self.persistent_id(object)
+           if (pid is not None):
+                self.save_pers(pid)
+                return
+
+        d = id(object)
+        t = type(object)
+
+       if ((t is TupleType) and (len(object) == 0)):
+           if (self.bin):
+                self.save_empty_tuple(object)
+            else:
+                self.save_tuple(object)
+            return
+
+        if memo.has_key(d):
+            self.write(self.get(memo[d][0]))
+            return
+
+        try:
+            f = self.dispatch[t]
+        except KeyError:
+            pid = self.inst_persistent_id(object)
+            if pid is not None:
+                self.save_pers(pid)
+                return
+
+            try:
+                reduce = dispatch_table[t]
+            except KeyError:
+                try:
+                    reduce = object.__reduce__
+                except AttributeError:
+                    raise PicklingError, \
+                        "can't pickle %s objects" % `t.__name__`
+                else:
+                    tup = reduce()
+            else:
+                tup = reduce(object)
+
+            if (type(tup) is not TupleType):
+                raise PicklingError, "Value returned by %s must be a " \
+                                     "tuple" % reduce
+
+            l = len(tup)
+   
+           if ((l != 2) and (l != 3)):
+                raise PicklingError, "tuple returned by %s must contain " \
+                                     "only two or three elements" % reduce
+
+            callable = tup[0]
+            arg_tup  = tup[1]
+          
+            if (l > 2):
+                state = tup[2]
+            else:
+                state = None
+
+            if (type(arg_tup) is not TupleType):
+                raise PicklingError, "Second element of tuple returned " \
+                                     "by %s must be a tuple" % reduce
+
+            self.save_reduce(callable, arg_tup, state) 
+            return
+
+        f(self, object)
+
+    def persistent_id(self, object):
+        return None
+
+    def inst_persistent_id(self, object):
+        return None
+
+    def save_pers(self, pid):
+        if (not self.bin):
+            self.write(PERSID + str(pid) + '\n')
+        else:
+            self.save(pid, 1)
+            self.write(BINPERSID)
+
+    def save_reduce(self, callable, arg_tup, state = None):
+        write = self.write
+        save = self.save
+
+        save(callable)
+        save(arg_tup)
+        write(REDUCE)
+        
+       if (state is not None):
+            save(state)
+            write(BUILD)
+
+    dispatch = {}
+
+    def save_none(self, object):
+        self.write(NONE)
+    dispatch[NoneType] = save_none
+
+    def save_int(self, object):
+        if (self.bin):
+            i = mdumps(object)[1:]
+            if (i[-2:] == '\000\000'):
+                if (i[-3] == '\000'):
+                    self.write(BININT1 + i[:-3])
+                    return
+
+                self.write(BININT2 + i[:-2])
+                return
+
+            self.write(BININT + i)
+        else:
+            self.write(INT + `object` + '\n')
+    dispatch[IntType] = save_int
+
+    def save_long(self, object):
+        self.write(LONG + `object` + '\n')
+    dispatch[LongType] = save_long
+
+    def save_float(self, object):
+        self.write(FLOAT + `object` + '\n')
+    dispatch[FloatType] = save_float
+
+    def save_string(self, object):
+        d = id(object)
+        memo = self.memo
+
+        if (self.bin):
+            l = len(object)
+            s = mdumps(l)[1:]
+            if (l < 256):
+                self.write(SHORT_BINSTRING + s[0] + object)
+            else:
+                self.write(BINSTRING + s + object)
+        else:
+            self.write(STRING + `object` + '\n')
+
+        memo_len = len(memo)
+        self.write(self.put(memo_len))
+        memo[d] = (memo_len, object)
+    dispatch[StringType] = save_string
+
+    def save_tuple(self, object):
+
+        write = self.write
+        save  = self.save
+        memo  = self.memo
+
+        d = id(object)
+
+        write(MARK)
+
+        for element in object:
+            save(element)
+
+        if (len(object) and memo.has_key(d)):
+           if (self.bin):
+                write(POP_MARK + self.get(memo[d][0]))
+                return
+           
+            write(POP * (len(object) + 1) + self.get(mem[d][0]))
+            return
+
+        memo_len = len(memo)
+        self.write(TUPLE + self.put(memo_len))
+        memo[d] = (memo_len, object)
+    dispatch[TupleType] = save_tuple
+
+    def save_empty_tuple(self, object):
+        self.write(EMPTY_TUPLE)
+
+    def save_list(self, object):
+        d = id(object)
+
+        write = self.write
+        save  = self.save
+        memo  = self.memo
+
+       if (self.bin):
+            write(EMPTY_LIST)
+        else:
+            write(MARK + LIST)
+
+        memo_len = len(memo)
+        write(self.put(memo_len))
+        memo[d] = (memo_len, object)
+
+        using_appends = (self.bin and (len(object) > 1))
+
+        if (using_appends):
+            write(MARK)
+
+        for element in object:
+            save(element)
+  
+            if (not using_appends):
+                write(APPEND)
+
+        if (using_appends):
+            write(APPENDS)
+    dispatch[ListType] = save_list
+
+    def save_dict(self, object):
+        d = id(object)
+
+        write = self.write
+        save  = self.save
+        memo  = self.memo
+
+       if (self.bin):
+            write(EMPTY_DICT)
+        else:
+            write(MARK + DICT)
+
+        memo_len = len(memo)
+        self.write(self.put(memo_len))
+        memo[d] = (memo_len, object)
+
+        using_setitems = (self.bin and (len(object) > 1))
+
+        if (using_setitems):
+            write(MARK)
+
+        items = object.items()
+        for key, value in items:
+            save(key)
+            save(value)
+
+            if (not using_setitems):
+                write(SETITEM)
+
+        if (using_setitems):
+            write(SETITEMS)
+
+    dispatch[DictionaryType] = save_dict
+
+    def save_inst(self, object):
+        d = id(object)
+        cls = object.__class__
+
+        memo  = self.memo
+        write = self.write
+        save  = self.save
+
+        if hasattr(object, '__getinitargs__'):
+            args = object.__getinitargs__()
+            len(args) # XXX Assert it's a sequence
+        else:
+            args = ()
+
+        write(MARK)
+
+        if (self.bin):
+            save(cls)
+
+        for arg in args:
+            save(arg)
+
+        memo_len = len(memo)
+        if (self.bin):
+            write(OBJ + self.put(memo_len))
+        else:
+            module = whichmodule(cls, cls.__name__)
+            name = cls.__name__
+            write(INST + module + '\n' + name + '\n' +
+                self.put(memo_len))
+
+        memo[d] = (memo_len, object)
+
+        try:
+            getstate = object.__getstate__
+        except AttributeError:
+            stuff = object.__dict__
+        else:
+            stuff = getstate()
+        save(stuff)
+        write(BUILD)
+    dispatch[InstanceType] = save_inst
+
+    def save_global(self, object, name = None):
+        write = self.write
+        memo = self.memo
+
+        if (name is None):
+            name = object.__name__
+
+        module = whichmodule(object, name)
+
+        memo_len = len(memo)
+        write(GLOBAL + module + '\n' + name + '\n' +
+            self.put(memo_len))
+        memo[id(object)] = (memo_len, object)
+    dispatch[ClassType] = save_global
+    dispatch[FunctionType] = save_global
+    dispatch[BuiltinFunctionType] = save_global
 
 
 classmap = {}
 
-def whichmodule(cls):
-       """Figure out the module in which a class occurs.
-
-       Search sys.modules for the module.
-       Cache in classmap.
-       Return a module name.
-       If the class cannot be found, return __main__.
-       """
-       if classmap.has_key(cls):
-               return classmap[cls]
-       import sys
-       clsname = cls.__name__
-       for name, module in sys.modules.items():
-               if name != '__main__' and \
-                  hasattr(module, clsname) and \
-                  getattr(module, clsname) is cls:
-                       break
-       else:
-               name = '__main__'
-       classmap[cls] = name
-       return name
+def whichmodule(cls, clsname):
+    """Figure out the module in which a class occurs.
 
+    Search sys.modules for the module.
+    Cache in classmap.
+    Return a module name.
+    If the class cannot be found, return __main__.
+    """
+    if classmap.has_key(cls):
+        return classmap[cls]
+    import sys
 
-class Unpickler:
+    for name, module in sys.modules.items():
+        if hasattr(module, clsname) and \
+            getattr(module, clsname) is cls:
+            break
+    else:
+        name = '__main__'
+    classmap[cls] = name
+    return name
 
-       def __init__(self, file):
-               self.readline = file.readline
-               self.read = file.read
-               self.memo = {}
-
-       def load(self):
-               self.mark = ['spam'] # Any new unique object
-               self.stack = []
-               self.append = self.stack.append
-               read = self.read
-               dispatch = self.dispatch
-               try:
-                       while 1:
-                               key = read(1)
-                               dispatch[key](self)
-               except STOP, value:
-                       return value
-
-       def marker(self):
-               stack = self.stack
-               mark = self.mark
-               k = len(stack)-1
-               while stack[k] is not mark: k = k-1
-               return k
-
-       dispatch = {}
-
-       def load_eof(self):
-               raise EOFError
-       dispatch[''] = load_eof
-
-       def load_persid(self):
-               pid = self.readline()[:-1]
-               self.append(self.persistent_load(pid))
-       dispatch[PERSID] = load_persid
-
-       def load_none(self):
-               self.append(None)
-       dispatch[NONE] = load_none
-
-       def load_int(self):
-               self.append(string.atoi(self.readline()[:-1], 0))
-       dispatch[INT] = load_int
-
-       def load_long(self):
-               self.append(string.atol(self.readline()[:-1], 0))
-       dispatch[LONG] = load_long
-
-       def load_float(self):
-               self.append(string.atof(self.readline()[:-1]))
-       dispatch[FLOAT] = load_float
-
-       def load_string(self):
-               self.append(eval(self.readline()[:-1],
-                                {'__builtins__': {}})) # Let's be careful
-       dispatch[STRING] = load_string
-
-       def load_tuple(self):
-               k = self.marker()
-               self.stack[k:] = [tuple(self.stack[k+1:])]
-       dispatch[TUPLE] = load_tuple
-
-       def load_list(self):
-               k = self.marker()
-               self.stack[k:] = [self.stack[k+1:]]
-       dispatch[LIST] = load_list
-
-       def load_dict(self):
-               k = self.marker()
-               d = {}
-               items = self.stack[k+1:]
-               for i in range(0, len(items), 2):
-                       key = items[i]
-                       value = items[i+1]
-                       d[key] = value
-               self.stack[k:] = [d]
-       dispatch[DICT] = load_dict
-
-       def load_inst(self):
-               k = self.marker()
-               args = tuple(self.stack[k+1:])
-               del self.stack[k:]
-               module = self.readline()[:-1]
-               name = self.readline()[:-1]
-               klass = self.find_class(module, name)
-               value = apply(klass, args)
-               self.append(value)
-       dispatch[INST] = load_inst
-
-       def load_class(self):
-               module = self.readline()[:-1]
-               name = self.readline()[:-1]
-               klass = self.find_class(module, name)
-               self.append(klass)
-               return klass
-       dispatch[CLASS] = load_class
-
-       def find_class(self, module, name):
-               try:
-                       klass = getattr(__import__(module), name)
-               except (ImportError, AttributeError):
-                       raise SystemError, \
-                             "Failed to import class %s from module %s" % \
-                             (name, module)
-               if type(klass) is BuiltinFunctionType:
-                       raise SystemError, \
-                        "Imported object %s from module %s is not a class" % \
-                        (name, module)
-               return klass
-
-       def load_pop(self):
-               del self.stack[-1]
-       dispatch[POP] = load_pop
-
-       def load_dup(self):
-               self.append(stack[-1])
-       dispatch[DUP] = load_dup
-
-       def load_get(self):
-               self.append(self.memo[self.readline()[:-1]])
-       dispatch[GET] = load_get
-
-       def load_put(self):
-               self.memo[self.readline()[:-1]] = self.stack[-1]
-       dispatch[PUT] = load_put
-
-       def load_append(self):
-               stack = self.stack
-               value = stack[-1]
-               del stack[-1]
-               list = stack[-1]
-               list.append(value)
-       dispatch[APPEND] = load_append
-
-       def load_setitem(self):
-               stack = self.stack
-               value = stack[-1]
-               key = stack[-2]
-               del stack[-2:]
-               dict = stack[-1]
-               dict[key] = value
-       dispatch[SETITEM] = load_setitem
-
-       def load_build(self):
-               stack = self.stack
-               value = stack[-1]
-               del stack[-1]
-               inst = stack[-1]
-               try:
-                       setstate = inst.__setstate__
-               except AttributeError:
-                       for key in value.keys():
-                               setattr(inst, key, value[key])
-               else:
-                       setstate(value)
-       dispatch[BUILD] = load_build
 
-       def load_mark(self):
-               self.append(self.mark)
-       dispatch[MARK] = load_mark
+class Unpickler:
 
-       def load_stop(self):
-               value = self.stack[-1]
-               del self.stack[-1]
-               raise STOP, value
-       dispatch[STOP] = load_stop
+    def __init__(self, file):
+        self.readline = file.readline
+        self.read = file.read
+        self.memo = {}
+
+    def load(self):
+        self.mark = ['spam'] # Any new unique object
+        self.stack = []
+        self.append = self.stack.append
+        read = self.read
+        dispatch = self.dispatch
+        try:
+            while 1:
+                key = read(1)
+                dispatch[key](self)
+        except STOP, value:
+            return value
+
+    def marker(self):
+        stack = self.stack
+        mark = self.mark
+        k = len(stack)-1
+        while stack[k] is not mark: k = k-1
+        return k
+
+    dispatch = {}
+
+    def load_eof(self):
+        raise EOFError
+    dispatch[''] = load_eof
+
+    def load_persid(self):
+        pid = self.readline()[:-1]
+        self.append(self.persistent_load(pid))
+    dispatch[PERSID] = load_persid
+
+    def load_binpersid(self):
+        stack = self.stack
+         
+        pid = stack[-1]
+        del stack[-1]
+
+        self.append(self.persistent_load(pid))
+    dispatch[BINPERSID] = load_binpersid
+
+    def load_none(self):
+        self.append(None)
+    dispatch[NONE] = load_none
+
+    def load_int(self):
+        self.append(string.atoi(self.readline()[:-1], 0))
+    dispatch[INT] = load_int
+
+    def load_binint(self):
+        self.append(mloads('i' + self.read(4)))
+    dispatch[BININT] = load_binint
+
+    def load_binint1(self):
+        self.append(mloads('i' + self.read(1) + '\000\000\000'))
+    dispatch[BININT1] = load_binint1
+
+    def load_binint2(self):
+        self.append(mloads('i' + self.read(2) + '\000\000'))
+    dispatch[BININT2] = load_binint2
+    def load_long(self):
+        self.append(string.atol(self.readline()[:-1], 0))
+    dispatch[LONG] = load_long
+
+    def load_float(self):
+        self.append(string.atof(self.readline()[:-1]))
+    dispatch[FLOAT] = load_float
+
+    def load_string(self):
+        self.append(eval(self.readline()[:-1],
+                         {'__builtins__': {}})) # Let's be careful
+    dispatch[STRING] = load_string
+
+    def load_binstring(self):
+        len = mloads('i' + self.read(4))
+        self.append(self.read(len))
+    dispatch[BINSTRING] = load_binstring
+
+    def load_short_binstring(self):
+        len = mloads('i' + self.read(1) + '\000\000\000')
+        self.append(self.read(len))
+    dispatch[SHORT_BINSTRING] = load_short_binstring
+
+    def load_tuple(self):
+        k = self.marker()
+        self.stack[k:] = [tuple(self.stack[k+1:])]
+    dispatch[TUPLE] = load_tuple
+
+    def load_empty_tuple(self):
+        self.stack.append(())
+    dispatch[EMPTY_TUPLE] = load_empty_tuple
+
+    def load_empty_list(self):
+        self.stack.append([])
+    dispatch[EMPTY_LIST] = load_empty_list
+
+    def load_empty_dictionary(self):
+        self.stack.append({})
+    dispatch[EMPTY_DICT] = load_empty_dictionary
+
+    def load_list(self):
+        k = self.marker()
+        self.stack[k:] = [self.stack[k+1:]]
+    dispatch[LIST] = load_list
+
+    def load_dict(self):
+        k = self.marker()
+        d = {}
+        items = self.stack[k+1:]
+        for i in range(0, len(items), 2):
+            key = items[i]
+            value = items[i+1]
+            d[key] = value
+        self.stack[k:] = [d]
+    dispatch[DICT] = load_dict
+
+    def load_inst(self):
+        k = self.marker()
+        args = tuple(self.stack[k+1:])
+        del self.stack[k:]
+        module = self.readline()[:-1]
+        name = self.readline()[:-1]
+        klass = self.find_class(module, name)
+       if (type(klass) is not ClassType):
+            raise SystemError, "Imported object %s from module %s is " \
+                               "not a class" % (name, module)
+
+        value = apply(klass, args)
+        self.append(value)
+    dispatch[INST] = load_inst
+
+    def load_obj(self):
+        stack = self.stack
+        k = self.marker()
+        klass = stack[k + 1]
+        del stack[k + 1]
+        args = tuple(stack[k + 1:]) 
+        del stack[k:]
+        value = apply(klass, args)
+        self.append(value)
+    dispatch[OBJ] = load_obj                
+
+    def load_global(self):
+        module = self.readline()[:-1]
+        name = self.readline()[:-1]
+        klass = self.find_class(module, name)
+        self.append(klass)
+    dispatch[GLOBAL] = load_global
+
+    def find_class(self, module, name):
+        env = {}
+
+        try:
+            exec 'from %s import %s' % (module, name) in env
+        except ImportError:
+            raise SystemError, \
+                  "Failed to import class %s from module %s" % \
+                  (name, module)
+        klass = env[name]
+        return klass
+
+    def load_reduce(self):
+        stack = self.stack
+
+        callable = stack[-2]
+        arg_tup  = stack[-1]
+       del stack[-2:]
+
+       if (type(callable) is not ClassType):
+           if (not safe_constructors.has_key(callable)):
+               try:
+                    safe = callable.__safe_for_unpickling__
+                except AttributeError:
+                    safe = None
+
+                if (not safe):
+                   raise UnpicklingError, "%s is not safe for " \
+                                          "unpickling" % callable
+
+        value = apply(callable, arg_tup)
+        self.append(value)
+    dispatch[REDUCE] = load_reduce
+
+    def load_pop(self):
+        del self.stack[-1]
+    dispatch[POP] = load_pop
+
+    def load_pop_mark(self):
+        k = self.marker()
+       del self.stack[k:]
+    dispatch[POP_MARK] = load_pop_mark
+
+    def load_dup(self):
+        self.append(stack[-1])
+    dispatch[DUP] = load_dup
+
+    def load_get(self):
+        self.append(self.memo[self.readline()[:-1]])
+    dispatch[GET] = load_get
+
+    def load_binget(self):
+        i = mloads('i' + self.read(1) + '\000\000\000')
+        self.append(self.memo[`i`])
+    dispatch[BINGET] = load_binget
+
+    def load_long_binget(self):
+        i = mloads('i' + self.read(4))
+        self.append(self.memo[`i`])
+    dispatch[LONG_BINGET] = load_long_binget
+
+    def load_put(self):
+        self.memo[self.readline()[:-1]] = self.stack[-1]
+    dispatch[PUT] = load_put
+
+    def load_binput(self):
+        i = mloads('i' + self.read(1) + '\000\000\000')
+        self.memo[`i`] = self.stack[-1]
+    dispatch[BINPUT] = load_binput
+
+    def load_long_binput(self):
+        i = mloads('i' + self.read(4))
+        self.memo[`i`] = self.stack[-1]
+    dispatch[LONG_BINPUT] = load_long_binput
+
+    def load_append(self):
+        stack = self.stack
+        value = stack[-1]
+        del stack[-1]
+        list = stack[-1]
+        list.append(value)
+    dispatch[APPEND] = load_append
+
+    def load_appends(self):
+        stack = self.stack
+        mark = self.marker()
+        list = stack[mark - 1]
+       for i in range(mark + 1, len(stack)):
+            list.append(stack[i])
+
+        del stack[mark:]
+    dispatch[APPENDS] = load_appends
+           
+    def load_setitem(self):
+        stack = self.stack
+        value = stack[-1]
+        key = stack[-2]
+        del stack[-2:]
+        dict = stack[-1]
+        dict[key] = value
+    dispatch[SETITEM] = load_setitem
+
+    def load_setitems(self):
+        stack = self.stack
+        mark = self.marker()
+        dict = stack[mark - 1]
+       for i in range(mark + 1, len(stack), 2):
+            dict[stack[i]] = stack[i + 1]
+
+        del stack[mark:]
+    dispatch[SETITEMS] = load_setitems
+
+    def load_build(self):
+        stack = self.stack
+        value = stack[-1]
+        del stack[-1]
+        inst = stack[-1]
+        try:
+            setstate = inst.__setstate__
+        except AttributeError:
+            for key in value.keys():
+                setattr(inst, key, value[key])
+        else:
+            setstate(value)
+    dispatch[BUILD] = load_build
+
+    def load_mark(self):
+        self.append(self.mark)
+    dispatch[MARK] = load_mark
+
+    def load_stop(self):
+        value = self.stack[-1]
+        del self.stack[-1]
+        raise STOP, value
+    dispatch[STOP] = load_stop
 
 
 # Shorthands
 
 from StringIO import StringIO
 
-def dump(object, file):
-       Pickler(file).dump(object)
+def dump(object, file, bin = 0):
+    Pickler(file, bin).dump(object)
 
-def dumps(object):
-       file = StringIO()
-       Pickler(file).dump(object)
-       return file.getvalue()
+def dumps(object, bin = 0):
+    file = StringIO()
+    Pickler(file, bin).dump(object)
+    return file.getvalue()
 
 def load(file):
-       return Unpickler(file).load()
+    return Unpickler(file).load()
 
 def loads(str):
-       file = StringIO(str)
-       return Unpickler(file).load()
+    file = StringIO(str)
+    return Unpickler(file).load()
 
 
 # The rest is used for testing only
 
 class C:
-       def __cmp__(self, other):
-               return cmp(self.__dict__, other.__dict__)
+    def __cmp__(self, other):
+        return cmp(self.__dict__, other.__dict__)
 
 def test():
-       fn = 'pickle_tmp'
-       c = C()
-       c.foo = 1
-       c.bar = 2L
-       x = [0, 1, 2, 3]
-       y = ('abc', 'abc', c, c)
-       x.append(y)
-       x.append(y)
-       x.append(5)
-       f = open(fn, 'w')
-       F = Pickler(f)
-       F.dump(x)
-       f.close()
-       f = open(fn, 'r')
-       U = Unpickler(f)
-       x2 = U.load()
-       print x
-       print x2
-       print x == x2
-       print map(id, x)
-       print map(id, x2)
-       print F.memo
-       print U.memo
+    fn = 'out'
+    c = C()
+    c.foo = 1
+    c.bar = 2
+    x = [0, 1, 2, 3]
+    y = ('abc', 'abc', c, c)
+    x.append(y)
+    x.append(y)
+    x.append(5)
+    f = open(fn, 'w')
+    F = Pickler(f)
+    F.dump(x)
+    f.close()
+    f = open(fn, 'r')
+    U = Unpickler(f)
+    x2 = U.load()
+    print x
+    print x2
+    print x == x2
+    print map(id, x)
+    print map(id, x2)
+    print F.memo
+    print U.memo
 
 if __name__ == '__main__':
-       test()
+    test()