| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 1 | """Manage shelves of pickled objects. | 
 | 2 |  | 
 | 3 | A "shelf" is a persistent, dictionary-like object.  The difference | 
 | 4 | with dbm databases is that the values (not the keys!) in a shelf can | 
 | 5 | be essentially arbitrary Python objects -- anything that the "pickle" | 
 | 6 | module can handle.  This includes most class instances, recursive data | 
 | 7 | types, and objects containing lots of shared sub-objects.  The keys | 
 | 8 | are ordinary strings. | 
 | 9 |  | 
 | 10 | To summarize the interface (key is a string, data is an arbitrary | 
 | 11 | object): | 
 | 12 |  | 
| Fred Drake | 13a2c27 | 2000-02-10 17:17:14 +0000 | [diff] [blame] | 13 |         import shelve | 
 | 14 |         d = shelve.open(filename) # open, with (g)dbm filename -- no suffix | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 15 |  | 
| Fred Drake | 13a2c27 | 2000-02-10 17:17:14 +0000 | [diff] [blame] | 16 |         d[key] = data   # store data at key (overwrites old data if | 
 | 17 |                         # using an existing key) | 
 | 18 |         data = d[key]   # retrieve data at key (raise KeyError if no | 
 | 19 |                         # such key) | 
 | 20 |         del d[key]      # delete data stored at key (raises KeyError | 
 | 21 |                         # if no such key) | 
 | 22 |         flag = d.has_key(key)   # true if the key exists | 
 | 23 |         list = d.keys() # a list of all existing keys (slow!) | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 24 |  | 
| Fred Drake | 13a2c27 | 2000-02-10 17:17:14 +0000 | [diff] [blame] | 25 |         d.close()       # close it | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 26 |  | 
 | 27 | Dependent on the implementation, closing a persistent dictionary may | 
 | 28 | or may not be necessary to flush changes to disk. | 
 | 29 | """ | 
| Guido van Rossum | a48061a | 1995-01-10 00:31:14 +0000 | [diff] [blame] | 30 |  | 
| Guido van Rossum | 914c938 | 1997-06-06 21:12:45 +0000 | [diff] [blame] | 31 | # Try using cPickle and cStringIO if available. | 
 | 32 |  | 
 | 33 | try: | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 34 |     from cPickle import Pickler, Unpickler | 
| Guido van Rossum | 914c938 | 1997-06-06 21:12:45 +0000 | [diff] [blame] | 35 | except ImportError: | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 36 |     from pickle import Pickler, Unpickler | 
| Guido van Rossum | 914c938 | 1997-06-06 21:12:45 +0000 | [diff] [blame] | 37 |  | 
 | 38 | try: | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 39 |     from cStringIO import StringIO | 
| Guido van Rossum | 914c938 | 1997-06-06 21:12:45 +0000 | [diff] [blame] | 40 | except ImportError: | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 41 |     from StringIO import StringIO | 
| Guido van Rossum | a48061a | 1995-01-10 00:31:14 +0000 | [diff] [blame] | 42 |  | 
| Skip Montanaro | 0de6580 | 2001-02-15 22:15:14 +0000 | [diff] [blame] | 43 | __all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"] | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 44 |  | 
| Guido van Rossum | a48061a | 1995-01-10 00:31:14 +0000 | [diff] [blame] | 45 | class Shelf: | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 46 |     """Base class for shelf implementations. | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 47 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 48 |     This is initialized with a dictionary-like object. | 
 | 49 |     See the module's __doc__ string for an overview of the interface. | 
 | 50 |     """ | 
| Guido van Rossum | a48061a | 1995-01-10 00:31:14 +0000 | [diff] [blame] | 51 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 52 |     def __init__(self, dict): | 
 | 53 |         self.dict = dict | 
| Guido van Rossum | 2f7df12 | 1999-08-11 01:54:05 +0000 | [diff] [blame] | 54 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 55 |     def keys(self): | 
 | 56 |         return self.dict.keys() | 
| Guido van Rossum | a48061a | 1995-01-10 00:31:14 +0000 | [diff] [blame] | 57 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 58 |     def __len__(self): | 
 | 59 |         return len(self.dict) | 
| Guido van Rossum | a48061a | 1995-01-10 00:31:14 +0000 | [diff] [blame] | 60 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 61 |     def has_key(self, key): | 
 | 62 |         return self.dict.has_key(key) | 
 | 63 |  | 
 | 64 |     def get(self, key, default=None): | 
 | 65 |         if self.dict.has_key(key): | 
 | 66 |             return self[key] | 
 | 67 |         return default | 
 | 68 |  | 
 | 69 |     def __getitem__(self, key): | 
 | 70 |         f = StringIO(self.dict[key]) | 
 | 71 |         return Unpickler(f).load() | 
 | 72 |  | 
 | 73 |     def __setitem__(self, key, value): | 
 | 74 |         f = StringIO() | 
 | 75 |         p = Pickler(f) | 
 | 76 |         p.dump(value) | 
 | 77 |         self.dict[key] = f.getvalue() | 
 | 78 |  | 
 | 79 |     def __delitem__(self, key): | 
 | 80 |         del self.dict[key] | 
 | 81 |  | 
 | 82 |     def close(self): | 
 | 83 |         try: | 
 | 84 |             self.dict.close() | 
 | 85 |         except: | 
 | 86 |             pass | 
 | 87 |         self.dict = 0 | 
 | 88 |  | 
 | 89 |     def __del__(self): | 
 | 90 |         self.close() | 
 | 91 |  | 
 | 92 |     def sync(self): | 
 | 93 |         if hasattr(self.dict, 'sync'): | 
 | 94 |             self.dict.sync() | 
 | 95 |  | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 96 |  | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 97 | class BsdDbShelf(Shelf): | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 98 |     """Shelf implementation using the "BSD" db interface. | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 99 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 100 |     This adds methods first(), next(), previous(), last() and | 
 | 101 |     set_location() that have no counterpart in [g]dbm databases. | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 102 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 103 |     The actual database must be opened using one of the "bsddb" | 
 | 104 |     modules "open" routines (i.e. bsddb.hashopen, bsddb.btopen or | 
 | 105 |     bsddb.rnopen) and passed to the constructor. | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 106 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 107 |     See the module's __doc__ string for an overview of the interface. | 
 | 108 |     """ | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 109 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 110 |     def __init__(self, dict): | 
 | 111 |         Shelf.__init__(self, dict) | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 112 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 113 |     def set_location(self, key): | 
 | 114 |         (key, value) = self.dict.set_location(key) | 
 | 115 |         f = StringIO(value) | 
 | 116 |         return (key, Unpickler(f).load()) | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 117 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 118 |     def next(self): | 
 | 119 |         (key, value) = self.dict.next() | 
 | 120 |         f = StringIO(value) | 
 | 121 |         return (key, Unpickler(f).load()) | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 122 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 123 |     def previous(self): | 
 | 124 |         (key, value) = self.dict.previous() | 
 | 125 |         f = StringIO(value) | 
 | 126 |         return (key, Unpickler(f).load()) | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 127 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 128 |     def first(self): | 
 | 129 |         (key, value) = self.dict.first() | 
 | 130 |         f = StringIO(value) | 
 | 131 |         return (key, Unpickler(f).load()) | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 132 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 133 |     def last(self): | 
 | 134 |         (key, value) = self.dict.last() | 
 | 135 |         f = StringIO(value) | 
 | 136 |         return (key, Unpickler(f).load()) | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 137 |  | 
 | 138 |  | 
 | 139 | class DbfilenameShelf(Shelf): | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 140 |     """Shelf implementation using the "anydbm" generic dbm interface. | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 141 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 142 |     This is initialized with the filename for the dbm database. | 
 | 143 |     See the module's __doc__ string for an overview of the interface. | 
 | 144 |     """ | 
 | 145 |  | 
 | 146 |     def __init__(self, filename, flag='c'): | 
 | 147 |         import anydbm | 
 | 148 |         Shelf.__init__(self, anydbm.open(filename, flag)) | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 149 |  | 
 | 150 |  | 
| Guido van Rossum | abad1cc | 1995-08-11 14:19:16 +0000 | [diff] [blame] | 151 | def open(filename, flag='c'): | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 152 |     """Open a persistent dictionary for reading and writing. | 
| Guido van Rossum | cc6764c | 1995-02-09 17:18:10 +0000 | [diff] [blame] | 153 |  | 
| Tim Peters | 495ad3c | 2001-01-15 01:36:40 +0000 | [diff] [blame] | 154 |     Argument is the filename for the dbm database. | 
 | 155 |     See the module's __doc__ string for an overview of the interface. | 
 | 156 |     """ | 
 | 157 |  | 
 | 158 |     return DbfilenameShelf(filename, flag) |