summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/pickle.py1212
1 files changed, 785 insertions, 427 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py
index bfe49f9..2a4357d 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -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()