|
Programmer's Notebook |
All computer source code presented on this page, unless it includes attribution to another author, is provided by Ed Halley under the Artistic License. Use such code freely and without any expectation of support. I would like to know if you make anything cool with the code, or need questions answered.
python/ bindings.py boards.py buzz.py cache.py cards.py constraints.py csql.py english.py getopts.py gizmos.py goals.py improv.py interpolations.py namespaces.py nihongo.py nodes.py octalplus.py patterns.py persist.py physics.py pids.py pieces.py quizzes.py recipes.py relays.py romaji.py ropen.py sheets.py strokes.py subscriptions.py svgbuild.py testing.py things.py timing.py ucsv.py useful.py uuid.py vectors.py weighted.py java/ CSVReader.java CSVWriter.java GlobFilenameFilter.java RegexFilenameFilter.java StringBufferOutputStream.java ThreadSet.java Throttle.java TracingThread.java Utf8ConsoleTest.java droid/ ArrangeViewsTouchListener.java DownloadFileTask.java perl/ CVQM.pm Kana.pm Typo.pm cxx/ CCache.h equalish.cpp |
Download persist.py
|
# persist - general storage-depot persistence helpers ''' Some general storage-depot persistence helper classes. ABSTRACT Builds on pickle, creating a depot or repository of uniquely identified persistent objects. Each object has its own permanent unchanging identity with id(), and that identity is used in the filesystem or database as a key to retrieve it later. AUTHOR Ed Halley (ed@halley.cc) 12 December 2006 ''' #---------------------------------------------------------------------------- class Identified: """A mix-in class for anything you need to have a stable unique identity. class MyClass (MyBaseClass, Identified): pass myobj = MyClass() print myobj.id() To give your MyClass instances a globally unique identity, add this class to your bases. The instance will gain a method .id() to retrieve the unique identifier for the instance. The identifier value itself resides in a private attribute ._id for serialization, which should not be modified by any application code. """ def allocid(self): import uuid return uuid.uuid1() def id(self): if not hasattr(self, '_id'): self._id = self.allocid() return self._id #---------------------------------------------------------------------------- class Persistent: """A mix-in class for anything you need to persist in a data store. class MyClass (MyBaseClass, Persistent): pass s = Store() myobj = MyClass() myobj.commit(s) # attaches to store myobj.commit() To manage your MyClass instances in a persistent store, add this class to your bases. The instance will gain one method, .commit(), to attach the instance to the store and also flush any uncommitted modifications. As a whole, your MyClass definition must be able to be serialized with the pickle module. """ def commit(self, store=None): store = getattr(self, '_store', store) if store: self._store = store store = Store.find(store) store.commit(self) #---------------------------------------------------------------------------- import cPickle as pickle import os class Store: """A system to manage any number of persistent, identified objects. The stored objects must include the Identified and Persistent bases. """ _stores = { } # name : store @classmethod def find(cls, name): if not name in Store._stores: return Store(name) return Store._stores[name] def __init__(self, name=None): self._saved = set([]) self._awake = { } if not name: name = 'Store' + str(len(Store._stores)) self.name = name Store._stores[name] = self self.startup() def startup(self): # override for external storage self._storage = { } self._saved = set(self._storage.keys()) def load(self, id): # override for external storage blob = self._storage[id] return blob def save(self, id, blob): # override for external storage self._storage[id] = blob return id def kill(self, id): # override for external storage self._storage.pop(id) def add(self, item): if not isinstance(item, Identified): raise TypeError, 'Stored objects must include Identified base type.' if not isinstance(item, Persistent): raise TypeError, 'Stored objects must include Persistent base type.' if getattr(item, '_store', None): raise KeyError, 'Object already kept in a Store.' id = item.id() self._saved.add(id) self._awake[id] = item item._store = self.name self.commit(id) return id def destroy(self, id): if not id in self._saved: raise KeyError, 'Id not known in store ' + self.name self.kill(id) self._saved.remove(id) if id in self._awake: self._awake.pop(id) def fetch(self, id): if isinstance(id, Identified): id = id.id() if not id in self._saved: raise KeyError, 'Id not known in store ' + self.name if not id in self._awake: blob = self.load(id) item = self.deserialize(blob) self._awake[id] = item return self._awake[id] def __getitem__(self, id): "As a convenience, referring to mystore[id] calls mystore.fetch(id)." return self.fetch(id) def __setitem__(self, id, item): raise TypeError, 'Add new items to the Store with add(item).' def serialize(self, id): item = self.fetch(id) blob = pickle.dumps(item) # See exception notes below. return blob def deserialize(self, blob): item = pickle.loads(blob) return item def commit(self, id=None): if id is None: for id in self._awake: self.commit(id) return if isinstance(id, Identified): id = id.id() if not id in self._saved: raise KeyError, 'Id not known in store ' + self.name if not id in self._awake: return blob = self.serialize(id) self.save(id, blob) return id def clone(self, id): if isinstance(id, Identified): id = id.id() if not id in self._saved: raise ValueError, 'id not known in store ' + self.name if id in self._awake: self.commit(id) blob = self.load(id) other = self.deserialize(blob) other._id = other.allocid() self._saved.add(other._id) self._awake[other._id] = other other.commit() return other # # Possible errors or exceptions raised: # # PicklingError: Can't pickle <class 'X'>: attribute lookup X failed # The above message may indicate X is not at top level of a module. # (Can't embed a persistent class in a def or a class, for example.) # #---------------------------------------------------------------------------- def fetch(id): "A global routine attempts to fetch one or more objects from all stores." if isinstance(id, list) or isinstance(id, tuple) or isinstance(id, set): return [ fetch(x) for x in id ] for store in Store._stores.values(): if id in store._saved: return store.fetch(id) return None |
|
Contact Ed Halley by email at
ed@halley.cc. Text, code, layout and artwork are Copyright © 1996-2013 Ed Halley. Copying in whole or in part, with author attribution, is expressly allowed. Any references to trademarks are illustrative and are controlled by their respective owners. |
|