blob: 5759d4ec63ce15246467fb0e19f48c7610862011 [file] [log] [blame]
Guido van Rossumcc6764c1995-02-09 17:18:10 +00001"""Manage shelves of pickled objects.
2
3A "shelf" is a persistent, dictionary-like object. The difference
4with dbm databases is that the values (not the keys!) in a shelf can
5be essentially arbitrary Python objects -- anything that the "pickle"
6module can handle. This includes most class instances, recursive data
7types, and objects containing lots of shared sub-objects. The keys
8are ordinary strings.
9
10To summarize the interface (key is a string, data is an arbitrary
11object):
12
Fred Drake13a2c272000-02-10 17:17:14 +000013 import shelve
14 d = shelve.open(filename) # open, with (g)dbm filename -- no suffix
Guido van Rossumcc6764c1995-02-09 17:18:10 +000015
Fred Drake13a2c272000-02-10 17:17:14 +000016 d[key] = data # store data at key (overwrites old data if
17 # using an existing key)
Tim Peters0eadaac2003-04-24 16:02:54 +000018 data = d[key] # retrieve a COPY of the data at key (raise
Martin v. Löwis153c9e42003-04-19 20:59:03 +000019 # KeyError if no such key) -- NOTE that this
20 # access returns a *copy* of the entry!
Fred Drake13a2c272000-02-10 17:17:14 +000021 del d[key] # delete data stored at key (raises KeyError
22 # if no such key)
Guido van Rossume2b70bc2006-08-18 22:13:04 +000023 flag = key in d # true if the key exists
Fred Drake13a2c272000-02-10 17:17:14 +000024 list = d.keys() # a list of all existing keys (slow!)
Guido van Rossumcc6764c1995-02-09 17:18:10 +000025
Fred Drake13a2c272000-02-10 17:17:14 +000026 d.close() # close it
Guido van Rossumcc6764c1995-02-09 17:18:10 +000027
28Dependent on the implementation, closing a persistent dictionary may
29or may not be necessary to flush changes to disk.
Martin v. Löwis153c9e42003-04-19 20:59:03 +000030
31Normally, d[key] returns a COPY of the entry. This needs care when
32mutable entries are mutated: for example, if d[key] is a list,
33 d[key].append(anitem)
34does NOT modify the entry d[key] itself, as stored in the persistent
35mapping -- it only modifies the copy, which is then immediately
36discarded, so that the append has NO effect whatsoever. To append an
37item to d[key] in a way that will affect the persistent mapping, use:
38 data = d[key]
39 data.append(anitem)
40 d[key] = data
41
42To avoid the problem with mutable entries, you may pass the keyword
43argument writeback=True in the call to shelve.open. When you use:
44 d = shelve.open(filename, writeback=True)
45then d keeps a cache of all entries you access, and writes them all back
46to the persistent mapping when you call d.close(). This ensures that
47such usage as d[key].append(anitem) works as intended.
48
49However, using keyword argument writeback=True may consume vast amount
50of memory for the cache, and it may make d.close() very slow, if you
51access many of d's entries after opening it in this way: d has no way to
52check which of the entries you access are mutable and/or which ones you
53actually mutate, so it must cache, and write back at close, all of the
54entries that you access. You can call d.sync() to write back all the
55entries in the cache, and empty the cache (d.sync() also synchronizes
56the persistent dictionary on disk, if feasible).
Guido van Rossumcc6764c1995-02-09 17:18:10 +000057"""
Guido van Rossuma48061a1995-01-10 00:31:14 +000058
Guido van Rossum68937b42007-05-18 00:51:22 +000059from pickle import Pickler, Unpickler
Brett Cannond24fffe2007-07-26 03:07:02 +000060from io import BytesIO
Guido van Rossuma48061a1995-01-10 00:31:14 +000061
Raymond Hettinger79947162002-11-15 06:46:14 +000062import UserDict
Martin v. Löwis153c9e42003-04-19 20:59:03 +000063import warnings
Raymond Hettinger79947162002-11-15 06:46:14 +000064
Skip Montanaro0de65802001-02-15 22:15:14 +000065__all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]
Guido van Rossumcc6764c1995-02-09 17:18:10 +000066
Raymond Hettinger79947162002-11-15 06:46:14 +000067class Shelf(UserDict.DictMixin):
Tim Peters495ad3c2001-01-15 01:36:40 +000068 """Base class for shelf implementations.
Guido van Rossumcc6764c1995-02-09 17:18:10 +000069
Tim Peters495ad3c2001-01-15 01:36:40 +000070 This is initialized with a dictionary-like object.
71 See the module's __doc__ string for an overview of the interface.
72 """
Guido van Rossuma48061a1995-01-10 00:31:14 +000073
Raymond Hettinger1bc82f82004-12-05 03:58:17 +000074 def __init__(self, dict, protocol=None, writeback=False):
Tim Peters495ad3c2001-01-15 01:36:40 +000075 self.dict = dict
Martin v. Löwis153c9e42003-04-19 20:59:03 +000076 if protocol is None:
77 protocol = 0
78 self._protocol = protocol
79 self.writeback = writeback
80 self.cache = {}
Guido van Rossum2f7df121999-08-11 01:54:05 +000081
Tim Peters495ad3c2001-01-15 01:36:40 +000082 def keys(self):
83 return self.dict.keys()
Guido van Rossuma48061a1995-01-10 00:31:14 +000084
Tim Peters495ad3c2001-01-15 01:36:40 +000085 def __len__(self):
86 return len(self.dict)
Guido van Rossuma48061a1995-01-10 00:31:14 +000087
Martin v. Löwise4913c92002-10-18 08:58:14 +000088 def __contains__(self, key):
Guido van Rossume2b70bc2006-08-18 22:13:04 +000089 return key in self.dict
Martin v. Löwise4913c92002-10-18 08:58:14 +000090
Tim Peters495ad3c2001-01-15 01:36:40 +000091 def get(self, key, default=None):
Guido van Rossume2b70bc2006-08-18 22:13:04 +000092 if key in self.dict:
Tim Peters495ad3c2001-01-15 01:36:40 +000093 return self[key]
94 return default
95
96 def __getitem__(self, key):
Martin v. Löwis153c9e42003-04-19 20:59:03 +000097 try:
98 value = self.cache[key]
99 except KeyError:
Brett Cannond24fffe2007-07-26 03:07:02 +0000100 f = BytesIO(self.dict[key])
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000101 value = Unpickler(f).load()
102 if self.writeback:
103 self.cache[key] = value
104 return value
Tim Peters495ad3c2001-01-15 01:36:40 +0000105
106 def __setitem__(self, key, value):
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000107 if self.writeback:
108 self.cache[key] = value
Brett Cannond24fffe2007-07-26 03:07:02 +0000109 f = BytesIO()
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000110 p = Pickler(f, self._protocol)
Tim Peters495ad3c2001-01-15 01:36:40 +0000111 p.dump(value)
112 self.dict[key] = f.getvalue()
113
114 def __delitem__(self, key):
115 del self.dict[key]
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000116 try:
117 del self.cache[key]
118 except KeyError:
119 pass
Tim Peters495ad3c2001-01-15 01:36:40 +0000120
121 def close(self):
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000122 self.sync()
Tim Peters495ad3c2001-01-15 01:36:40 +0000123 try:
124 self.dict.close()
Raymond Hettinger68dcd342003-05-27 06:30:52 +0000125 except AttributeError:
Tim Peters495ad3c2001-01-15 01:36:40 +0000126 pass
127 self.dict = 0
128
129 def __del__(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000130 if not hasattr(self, 'writeback'):
131 # __init__ didn't succeed, so don't bother closing
132 return
Tim Peters495ad3c2001-01-15 01:36:40 +0000133 self.close()
134
135 def sync(self):
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000136 if self.writeback and self.cache:
137 self.writeback = False
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000138 for key, entry in self.cache.items():
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000139 self[key] = entry
140 self.writeback = True
141 self.cache = {}
Tim Peters495ad3c2001-01-15 01:36:40 +0000142 if hasattr(self.dict, 'sync'):
143 self.dict.sync()
144
Guido van Rossumcc6764c1995-02-09 17:18:10 +0000145
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000146class BsdDbShelf(Shelf):
Tim Peters495ad3c2001-01-15 01:36:40 +0000147 """Shelf implementation using the "BSD" db interface.
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000148
Tim Peters495ad3c2001-01-15 01:36:40 +0000149 This adds methods first(), next(), previous(), last() and
150 set_location() that have no counterpart in [g]dbm databases.
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000151
Tim Peters495ad3c2001-01-15 01:36:40 +0000152 The actual database must be opened using one of the "bsddb"
153 modules "open" routines (i.e. bsddb.hashopen, bsddb.btopen or
154 bsddb.rnopen) and passed to the constructor.
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000155
Tim Peters495ad3c2001-01-15 01:36:40 +0000156 See the module's __doc__ string for an overview of the interface.
157 """
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000158
Raymond Hettinger1bc82f82004-12-05 03:58:17 +0000159 def __init__(self, dict, protocol=None, writeback=False):
160 Shelf.__init__(self, dict, protocol, writeback)
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000161
Tim Peters495ad3c2001-01-15 01:36:40 +0000162 def set_location(self, key):
163 (key, value) = self.dict.set_location(key)
Brett Cannond24fffe2007-07-26 03:07:02 +0000164 f = BytesIO(value)
Tim Peters495ad3c2001-01-15 01:36:40 +0000165 return (key, Unpickler(f).load())
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000166
Tim Peters495ad3c2001-01-15 01:36:40 +0000167 def next(self):
Georg Brandla18af4e2007-04-21 15:47:16 +0000168 (key, value) = next(self.dict)
Brett Cannond24fffe2007-07-26 03:07:02 +0000169 f = BytesIO(value)
Tim Peters495ad3c2001-01-15 01:36:40 +0000170 return (key, Unpickler(f).load())
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000171
Tim Peters495ad3c2001-01-15 01:36:40 +0000172 def previous(self):
173 (key, value) = self.dict.previous()
Brett Cannond24fffe2007-07-26 03:07:02 +0000174 f = BytesIO(value)
Tim Peters495ad3c2001-01-15 01:36:40 +0000175 return (key, Unpickler(f).load())
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000176
Tim Peters495ad3c2001-01-15 01:36:40 +0000177 def first(self):
178 (key, value) = self.dict.first()
Brett Cannond24fffe2007-07-26 03:07:02 +0000179 f = BytesIO(value)
Tim Peters495ad3c2001-01-15 01:36:40 +0000180 return (key, Unpickler(f).load())
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000181
Tim Peters495ad3c2001-01-15 01:36:40 +0000182 def last(self):
183 (key, value) = self.dict.last()
Brett Cannond24fffe2007-07-26 03:07:02 +0000184 f = BytesIO(value)
Tim Peters495ad3c2001-01-15 01:36:40 +0000185 return (key, Unpickler(f).load())
Guido van Rossumabad1cc1995-08-11 14:19:16 +0000186
187
188class DbfilenameShelf(Shelf):
Tim Peters495ad3c2001-01-15 01:36:40 +0000189 """Shelf implementation using the "anydbm" generic dbm interface.
Guido van Rossumcc6764c1995-02-09 17:18:10 +0000190
Tim Peters495ad3c2001-01-15 01:36:40 +0000191 This is initialized with the filename for the dbm database.
192 See the module's __doc__ string for an overview of the interface.
193 """
194
Raymond Hettinger1bc82f82004-12-05 03:58:17 +0000195 def __init__(self, filename, flag='c', protocol=None, writeback=False):
Tim Peters495ad3c2001-01-15 01:36:40 +0000196 import anydbm
Raymond Hettinger1bc82f82004-12-05 03:58:17 +0000197 Shelf.__init__(self, anydbm.open(filename, flag), protocol, writeback)
Guido van Rossumcc6764c1995-02-09 17:18:10 +0000198
199
Raymond Hettinger1bc82f82004-12-05 03:58:17 +0000200def open(filename, flag='c', protocol=None, writeback=False):
Tim Peters495ad3c2001-01-15 01:36:40 +0000201 """Open a persistent dictionary for reading and writing.
Guido van Rossumcc6764c1995-02-09 17:18:10 +0000202
Martin v. Löwis153c9e42003-04-19 20:59:03 +0000203 The filename parameter is the base filename for the underlying
204 database. As a side-effect, an extension may be added to the
205 filename and more than one file may be created. The optional flag
206 parameter has the same interpretation as the flag parameter of
207 anydbm.open(). The optional protocol parameter specifies the
208 version of the pickle protocol (0, 1, or 2).
209
Tim Peters495ad3c2001-01-15 01:36:40 +0000210 See the module's __doc__ string for an overview of the interface.
211 """
212
Raymond Hettinger1bc82f82004-12-05 03:58:17 +0000213 return DbfilenameShelf(filename, flag, protocol, writeback)