#MUDPyE - (M)ulti-(U)ser (D)imension (Py)thon (E)ngine #Copyright (C) 2005 Corey Staten #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #Send feedback/questions to MUDPyE@gmail.com import cPickle import marshal import types #This is a simple module that wraps around cPickle. #It replaces things that can not be unpickled properly with "None". #Pickling is done recursively, so no "bad" objects can possibly get through(IE, it's uncrashable theoretically). easyTypes = [types.LongType, types.IntType, types.FloatType, types.StringType, types.BooleanType, types.NoneType] class Save_MudObjectRef(object): def __init__(self, objID): self.objID = objID def __getstate__(self): return self.objID def __setstate__(self, objID): self.objID = objID class Save_Tuple(object): def __init__(self, elementList): self.elementList = elementList def __getstate__(self): return self.elementList def __setstate__(self, elementList): self.elementList = elementList def SimplifyTupleElement(element): elementType = type(element) if elementType in easyTypes: return element elif elementType is types.TupleType: return RecursiveSimplifyTuple(element) else: return None def RecursiveSimplifyTuple(curTuple): newList = map(SimplifyTupleElement, curTuple) return tuple(newList) def RecursiveNullifyBadValues(convertObject, seenObjs): """Returns a version of an object that is safe to pickle. Doesn't change the object itself.""" if seenObjs.has_key(id(convertObject)): return seenObjs[id(convertObject)] returnVal = None objectType = type(convertObject) if objectType in easyTypes: returnVal = convertObject elif objectType is types.ListType: returnVal = [] seenObjs[id(convertObject)] = returnVal returnVal.extend(map(RecursiveNullifyBadValues, convertObject, [seenObjs]*len(convertObject))) elif objectType is types.DictType: returnVal = {} seenObjs[id(convertObject)] = returnVal for key,val in convertObject.items(): returnVal[key] = RecursiveNullifyBadValues(val, seenObjs) elif objectType is types.TupleType: newList = [] returnVal = Save_Tuple(newList) seenObjs[id(convertObject)] = returnVal newList.extend(map(RecursiveNullifyBadValues, convertObject, [seenObjs]*len(convertObject))) #Tuples need to be of simple types only. Non-constant tuples don't work, because to make them #work we would need to be able to create the copied tuple BEFORE recursing over its elements. #Since we can't modify tuples this way, we're forced to restrict them to simple types. #returnVal = RecursiveSimplifyTuple(convertObject) elif objectType.__name__ == "MudObjectRef": returnVal = Save_MudObjectRef(object.__getattribute__(convertObject, "objID")) elif objectType.__name__ == "CallableNone": returnVal = None else: try: returnVal = RecursiveNullifyBadValues(convertObject._Sys_Serialize(), seenObjs) except: pass return returnVal def dumps(convertObject, proto=0): return cPickle.dumps(RecursiveNullifyBadValues(convertObject, {}), proto) def RecursiveLoadReferences(loadObj, seenObjs, getRefFunc): if seenObjs.has_key(id(loadObj)): return seenObjs[id(loadObj)] returnVal = loadObj objectType = type(loadObj) if objectType is types.ListType: returnVal = [] seenObjs[id(loadObj)] = returnVal returnVal.extend(map(RecursiveLoadReferences, loadObj, [seenObjs]*len(loadObj), [getRefFunc]*len(loadObj))) elif objectType is types.DictType: returnVal = {} seenObjs[id(loadObj)] = returnVal for key,val in loadObj.items(): returnVal[key] = RecursiveLoadReferences(val, seenObjs, getRefFunc) elif objectType is Save_Tuple: returnVal = tuple(loadObj.elementList) elif objectType is Save_MudObjectRef: returnVal = getRefFunc(loadObj.objID) return returnVal def loads(pickledString, getRefFunc): return RecursiveLoadReferences(cPickle.loads(pickledString), {}, getRefFunc)