# persister: safe class persistance wrapper # Copyright 2003, 2004 Adam Sampson # # persister is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of the # License, or (at your option) any later version. # # persister 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with persister; see the file COPYING.LGPL. If not, # write to the Free Software Foundation, Inc., 59 Temple Place, Suite # 330, Boston, MA 02111-1307 USA, or see http://www.gnu.org/. import pickle, fcntl class Persistable: """Something which can be persisted. When a subclass of this wants to indicate that it has been modified, it should call self.modified().""" def __init__(self): self._modified = 0 def modified(self, state = 1): self._modified = state def is_modified(self): return self._modified class Persister: """Persist another class to a file, safely. The class being persisted must derive from Persistable (although this isn't enforced).""" def __init__(self, filename, klass): self.filename = filename self.klass = klass self.file = None self.object = None def load(self): """Load the persisted object from the file, or create a new one if this isn't possible. Returns the loaded object.""" try: self.file = open(self.filename, "r+") fcntl.lockf(self.file.fileno(), fcntl.LOCK_EX) self.object = pickle.load(self.file) self.object.modified(0) except IOError: self.file = open(self.filename, "w+") fcntl.lockf(self.file.fileno(), fcntl.LOCK_EX) self.object = self.klass() self.object.modified() return self.object def save(self): """Save the persisted object back to the file if necessary.""" if self.object.is_modified(): self.file.seek(0) self.file.truncate(0) pickle.dump(self.object, self.file) self.file.close()