1cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum"""Manage shelves of pickled objects.
2cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
3cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van RossumA "shelf" is a persistent, dictionary-like object.  The difference
4cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossumwith dbm databases is that the values (not the keys!) in a shelf can
5cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossumbe essentially arbitrary Python objects -- anything that the "pickle"
6cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossummodule can handle.  This includes most class instances, recursive data
7cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossumtypes, and objects containing lots of shared sub-objects.  The keys
8cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossumare ordinary strings.
9cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
10cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van RossumTo summarize the interface (key is a string, data is an arbitrary
11cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossumobject):
12cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
1313a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake        import shelve
1413a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake        d = shelve.open(filename) # open, with (g)dbm filename -- no suffix
15cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
1613a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake        d[key] = data   # store data at key (overwrites old data if
1713a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake                        # using an existing key)
180eadaac7dc3ae49974c105ff9e8c1e98a04d7d5aTim Peters        data = d[key]   # retrieve a COPY of the data at key (raise
19153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis                        # KeyError if no such key) -- NOTE that this
20153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis                        # access returns a *copy* of the entry!
2113a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake        del d[key]      # delete data stored at key (raises KeyError
2213a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake                        # if no such key)
23e2b70bcf7401477936fba99a8bf4a1f759ecc8a3Guido van Rossum        flag = key in d # true if the key exists
2413a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake        list = d.keys() # a list of all existing keys (slow!)
25cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
2613a2c279c504ae58c20baba5f0b3d1d6c0a85ed3Fred Drake        d.close()       # close it
27cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
28cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van RossumDependent on the implementation, closing a persistent dictionary may
29cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossumor may not be necessary to flush changes to disk.
30153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis
31153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. LöwisNormally, d[key] returns a COPY of the entry.  This needs care when
32153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwismutable entries are mutated: for example, if d[key] is a list,
33153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        d[key].append(anitem)
34153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisdoes NOT modify the entry d[key] itself, as stored in the persistent
35153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwismapping -- it only modifies the copy, which is then immediately
36153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisdiscarded, so that the append has NO effect whatsoever.  To append an
37153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisitem to d[key] in a way that will affect the persistent mapping, use:
38153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        data = d[key]
39153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        data.append(anitem)
40153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        d[key] = data
41153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis
42153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. LöwisTo avoid the problem with mutable entries, you may pass the keyword
43153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisargument writeback=True in the call to shelve.open.  When you use:
44153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        d = shelve.open(filename, writeback=True)
45153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisthen d keeps a cache of all entries you access, and writes them all back
46153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisto the persistent mapping when you call d.close().  This ensures that
47153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwissuch usage as d[key].append(anitem) works as intended.
48153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis
49153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. LöwisHowever, using keyword argument writeback=True may consume vast amount
50153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisof memory for the cache, and it may make d.close() very slow, if you
51153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisaccess many of d's entries after opening it in this way: d has no way to
52153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwischeck which of the entries you access are mutable and/or which ones you
53153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisactually mutate, so it must cache, and write back at close, all of the
54153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisentries that you access.  You can call d.sync() to write back all the
55153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisentries in the cache, and empty the cache (d.sync() also synchronizes
56153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwisthe persistent dictionary on disk, if feasible).
57cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum"""
58a48061a5804418a63aac24bfce444fd555e3ffe7Guido van Rossum
5968937b4cbcc3e88d4207e6391a311f9b7d067b71Guido van Rossumfrom pickle import Pickler, Unpickler
60d24fffe7c67c2097aa33e04498dc6b3ae0cc17abBrett Cannonfrom io import BytesIO
61a48061a5804418a63aac24bfce444fd555e3ffe7Guido van Rossum
62b9da9bc0a04b718e8395e2e88c3053ab944579b7Raymond Hettingerimport collections
637994716b6bcaeca64f47b7b3ed4e411bb6afc415Raymond Hettinger
64ac0f965fd0d33da64f42d1a7ece1a66c80c3ff52Andrew Svetlov__all__ = ["Shelf", "BsdDbShelf", "DbfilenameShelf", "open"]
65cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
66d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Petersonclass _ClosedDict(collections.MutableMapping):
67d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson    'Marker for a closed dict.  Access attempts raise a ValueError.'
68d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson
69d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson    def closed(self, *args):
70d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson        raise ValueError('invalid operation on closed shelf')
71d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson    __iter__ = __len__ = __getitem__ = __setitem__ = __delitem__ = keys = closed
72d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson
73d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson    def __repr__(self):
74d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson        return '<Closed Dictionary>'
75d63137159b0e0cdbaec5d4cb98b3de5940173ee3Benjamin Peterson
76732324a3f86a352217b01ae2438b6db7691ae0b1Georg Brandl
77b9da9bc0a04b718e8395e2e88c3053ab944579b7Raymond Hettingerclass Shelf(collections.MutableMapping):
78495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    """Base class for shelf implementations.
79495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
80495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    This is initialized with a dictionary-like object.
81495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    See the module's __doc__ string for an overview of the interface.
82495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    """
83495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
8479c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis    def __init__(self, dict, protocol=None, writeback=False,
8579c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis                 keyencoding="utf-8"):
86495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        self.dict = dict
87153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        if protocol is None:
8885602268dc9d57b8965b619dd313868ebe4b9b8fRaymond Hettinger            protocol = 3
89153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        self._protocol = protocol
90153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        self.writeback = writeback
91153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        self.cache = {}
92732324a3f86a352217b01ae2438b6db7691ae0b1Georg Brandl        self.keyencoding = keyencoding
93495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
94b9da9bc0a04b718e8395e2e88c3053ab944579b7Raymond Hettinger    def __iter__(self):
9579c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        for k in self.dict.keys():
9679c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis            yield k.decode(self.keyencoding)
97495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
98495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def __len__(self):
99495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        return len(self.dict)
100495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
101e4913c9987d88f5a1bd52753afe8eb6bee32f6e9Martin v. Löwis    def __contains__(self, key):
10279c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        return key.encode(self.keyencoding) in self.dict
103e4913c9987d88f5a1bd52753afe8eb6bee32f6e9Martin v. Löwis
104495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def get(self, key, default=None):
10579c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        if key.encode(self.keyencoding) in self.dict:
106495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters            return self[key]
107495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        return default
108495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
109495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def __getitem__(self, key):
110153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        try:
111153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            value = self.cache[key]
112153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        except KeyError:
11379c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis            f = BytesIO(self.dict[key.encode(self.keyencoding)])
114153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            value = Unpickler(f).load()
115153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            if self.writeback:
116153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis                self.cache[key] = value
117153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        return value
118495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
119495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def __setitem__(self, key, value):
120153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        if self.writeback:
121153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            self.cache[key] = value
122d24fffe7c67c2097aa33e04498dc6b3ae0cc17abBrett Cannon        f = BytesIO()
123153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        p = Pickler(f, self._protocol)
124495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        p.dump(value)
12579c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        self.dict[key.encode(self.keyencoding)] = f.getvalue()
126495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
127495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def __delitem__(self, key):
12879c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        del self.dict[key.encode(self.keyencoding)]
129153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        try:
130153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            del self.cache[key]
131153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        except KeyError:
132153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            pass
133495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
134ef08fb1f040cb51e752c6b1322008714262fbf3eAndrew Svetlov    def __enter__(self):
135ef08fb1f040cb51e752c6b1322008714262fbf3eAndrew Svetlov        return self
136ef08fb1f040cb51e752c6b1322008714262fbf3eAndrew Svetlov
137ef08fb1f040cb51e752c6b1322008714262fbf3eAndrew Svetlov    def __exit__(self, type, value, traceback):
138ef08fb1f040cb51e752c6b1322008714262fbf3eAndrew Svetlov        self.close()
139ef08fb1f040cb51e752c6b1322008714262fbf3eAndrew Svetlov
140495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def close(self):
1417e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka        if self.dict is None:
1427e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            return
143495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        try:
1447e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            self.sync()
1457e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            try:
1467e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka                self.dict.close()
1477e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            except AttributeError:
1487e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka                pass
1497e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka        finally:
1507e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            # Catch errors that may happen when close is called from __del__
1517e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            # because CPython is in interpreter shutdown.
1527e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            try:
1537e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka                self.dict = _ClosedDict()
1547e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka            except:
1557e7a3dba5fd4262269f713dfe21ba7e4746fc2ddSerhiy Storchaka                self.dict = None
156495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
157495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def __del__(self):
1580e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters        if not hasattr(self, 'writeback'):
1590e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters            # __init__ didn't succeed, so don't bother closing
160ef08fb1f040cb51e752c6b1322008714262fbf3eAndrew Svetlov            # see http://bugs.python.org/issue1339007 for details
1610e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters            return
162495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        self.close()
163495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
164495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def sync(self):
165153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis        if self.writeback and self.cache:
166153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            self.writeback = False
167cc2b0161257495f859200bce0aea3ed7e646feb3Guido van Rossum            for key, entry in self.cache.items():
168153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis                self[key] = entry
169153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            self.writeback = True
170153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis            self.cache = {}
171495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        if hasattr(self.dict, 'sync'):
172495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters            self.dict.sync()
173495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
174cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
175abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossumclass BsdDbShelf(Shelf):
176495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    """Shelf implementation using the "BSD" db interface.
177abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
178495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    This adds methods first(), next(), previous(), last() and
179495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    set_location() that have no counterpart in [g]dbm databases.
180abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
181495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    The actual database must be opened using one of the "bsddb"
182495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    modules "open" routines (i.e. bsddb.hashopen, bsddb.btopen or
183495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    bsddb.rnopen) and passed to the constructor.
184abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
185495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    See the module's __doc__ string for an overview of the interface.
186495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    """
187abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
18879c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis    def __init__(self, dict, protocol=None, writeback=False,
18979c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis                 keyencoding="utf-8"):
19079c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        Shelf.__init__(self, dict, protocol, writeback, keyencoding)
191abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
192495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def set_location(self, key):
193495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        (key, value) = self.dict.set_location(key)
194d24fffe7c67c2097aa33e04498dc6b3ae0cc17abBrett Cannon        f = BytesIO(value)
19579c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        return (key.decode(self.keyencoding), Unpickler(f).load())
196abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
197495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def next(self):
198a18af4e7a2091d11478754eb66ae387a85535763Georg Brandl        (key, value) = next(self.dict)
199d24fffe7c67c2097aa33e04498dc6b3ae0cc17abBrett Cannon        f = BytesIO(value)
20079c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        return (key.decode(self.keyencoding), Unpickler(f).load())
201abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
202495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def previous(self):
203495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        (key, value) = self.dict.previous()
204d24fffe7c67c2097aa33e04498dc6b3ae0cc17abBrett Cannon        f = BytesIO(value)
20579c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        return (key.decode(self.keyencoding), Unpickler(f).load())
206abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
207495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def first(self):
208495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        (key, value) = self.dict.first()
209d24fffe7c67c2097aa33e04498dc6b3ae0cc17abBrett Cannon        f = BytesIO(value)
21079c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        return (key.decode(self.keyencoding), Unpickler(f).load())
211abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
212495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    def last(self):
213495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters        (key, value) = self.dict.last()
214d24fffe7c67c2097aa33e04498dc6b3ae0cc17abBrett Cannon        f = BytesIO(value)
21579c320898d43eaafa28c1c67a105a17cb9b233bfMartin v. Löwis        return (key.decode(self.keyencoding), Unpickler(f).load())
216abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
217abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossum
218abad1cc647a9c8e892829f8066dc85ad3b7c9632Guido van Rossumclass DbfilenameShelf(Shelf):
2190a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5Georg Brandl    """Shelf implementation using the "dbm" generic dbm interface.
220495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
221495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    This is initialized with the filename for the dbm database.
222495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    See the module's __doc__ string for an overview of the interface.
223495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    """
224cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
2251bc82f891c2ed0c4b062158d2c8339fb90406395Raymond Hettinger    def __init__(self, filename, flag='c', protocol=None, writeback=False):
2260a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5Georg Brandl        import dbm
2270a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5Georg Brandl        Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback)
228a48061a5804418a63aac24bfce444fd555e3ffe7Guido van Rossum
229cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
2301bc82f891c2ed0c4b062158d2c8339fb90406395Raymond Hettingerdef open(filename, flag='c', protocol=None, writeback=False):
231495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    """Open a persistent dictionary for reading and writing.
232495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters
233153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis    The filename parameter is the base filename for the underlying
234153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis    database.  As a side-effect, an extension may be added to the
235153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis    filename and more than one file may be created.  The optional flag
236153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis    parameter has the same interpretation as the flag parameter of
2370a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5Georg Brandl    dbm.open(). The optional protocol parameter specifies the
238153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis    version of the pickle protocol (0, 1, or 2).
239153c9e493e9850340fd686ab7a6e5c176953abd7Martin v. Löwis
240495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    See the module's __doc__ string for an overview of the interface.
241495ad3c8ccb9ed3554177a3e8687676c78e667deTim Peters    """
242cc6764c1ba92e947638d1c0c8fe8d312a0e3e6d4Guido van Rossum
2431bc82f891c2ed0c4b062158d2c8339fb90406395Raymond Hettinger    return DbfilenameShelf(filename, flag, protocol, writeback)
244