diff options
Diffstat (limited to 'Lib/pickle.py')
-rw-r--r-- | Lib/pickle.py | 1212 |
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() |