5656the persistent dictionary on disk, if feasible).
5757"""
5858
59- from pickle import DEFAULT_PROTOCOL , Pickler , Unpickler
59+ from pickle import DEFAULT_PROTOCOL , dumps , loads
6060from io import BytesIO
6161
6262import collections .abc
6363
64- __all__ = ["Shelf" , "BsdDbShelf" , "DbfilenameShelf" , "open" ]
64+ __all__ = ["ShelveError" , "Shelf" , "BsdDbShelf" , "DbfilenameShelf" , "open" ]
65+
66+
67+ class ShelveError (Exception ):
68+ pass
69+
6570
6671class _ClosedDict (collections .abc .MutableMapping ):
6772 'Marker for a closed dict. Access attempts raise a ValueError.'
@@ -82,7 +87,7 @@ class Shelf(collections.abc.MutableMapping):
8287 """
8388
8489 def __init__ (self , dict , protocol = None , writeback = False ,
85- keyencoding = "utf-8" ):
90+ keyencoding = "utf-8" , * , serializer = None , deserializer = None ):
8691 self .dict = dict
8792 if protocol is None :
8893 protocol = DEFAULT_PROTOCOL
@@ -91,6 +96,16 @@ def __init__(self, dict, protocol=None, writeback=False,
9196 self .cache = {}
9297 self .keyencoding = keyencoding
9398
99+ if serializer is None and deserializer is None :
100+ self .serializer = dumps
101+ self .deserializer = loads
102+ elif (serializer is None ) ^ (deserializer is None ):
103+ raise ShelveError ("serializer and deserializer must be "
104+ "defined together" )
105+ else :
106+ self .serializer = serializer
107+ self .deserializer = deserializer
108+
94109 def __iter__ (self ):
95110 for k in self .dict .keys ():
96111 yield k .decode (self .keyencoding )
@@ -110,19 +125,17 @@ def __getitem__(self, key):
110125 try :
111126 value = self .cache [key ]
112127 except KeyError :
113- f = BytesIO ( self .dict [key .encode (self .keyencoding )])
114- value = Unpickler ( f ). load ( )
128+ f = self .dict [key .encode (self .keyencoding )]
129+ value = self . deserializer ( f )
115130 if self .writeback :
116131 self .cache [key ] = value
117132 return value
118133
119134 def __setitem__ (self , key , value ):
120135 if self .writeback :
121136 self .cache [key ] = value
122- f = BytesIO ()
123- p = Pickler (f , self ._protocol )
124- p .dump (value )
125- self .dict [key .encode (self .keyencoding )] = f .getvalue ()
137+ serialized_value = self .serializer (value , self ._protocol )
138+ self .dict [key .encode (self .keyencoding )] = serialized_value
126139
127140 def __delitem__ (self , key ):
128141 del self .dict [key .encode (self .keyencoding )]
@@ -191,33 +204,29 @@ class BsdDbShelf(Shelf):
191204 """
192205
193206 def __init__ (self , dict , protocol = None , writeback = False ,
194- keyencoding = "utf-8" ):
195- Shelf .__init__ (self , dict , protocol , writeback , keyencoding )
207+ keyencoding = "utf-8" , * , serializer = None , deserializer = None ):
208+ Shelf .__init__ (self , dict , protocol , writeback , keyencoding ,
209+ serializer = serializer , deserializer = deserializer )
196210
197211 def set_location (self , key ):
198212 (key , value ) = self .dict .set_location (key )
199- f = BytesIO (value )
200- return (key .decode (self .keyencoding ), Unpickler (f ).load ())
213+ return (key .decode (self .keyencoding ), self .deserializer (value ))
201214
202215 def next (self ):
203216 (key , value ) = next (self .dict )
204- f = BytesIO (value )
205- return (key .decode (self .keyencoding ), Unpickler (f ).load ())
217+ return (key .decode (self .keyencoding ), self .deserializer (value ))
206218
207219 def previous (self ):
208220 (key , value ) = self .dict .previous ()
209- f = BytesIO (value )
210- return (key .decode (self .keyencoding ), Unpickler (f ).load ())
221+ return (key .decode (self .keyencoding ), self .deserializer (value ))
211222
212223 def first (self ):
213224 (key , value ) = self .dict .first ()
214- f = BytesIO (value )
215- return (key .decode (self .keyencoding ), Unpickler (f ).load ())
225+ return (key .decode (self .keyencoding ), self .deserializer (value ))
216226
217227 def last (self ):
218228 (key , value ) = self .dict .last ()
219- f = BytesIO (value )
220- return (key .decode (self .keyencoding ), Unpickler (f ).load ())
229+ return (key .decode (self .keyencoding ), self .deserializer (value ))
221230
222231
223232class DbfilenameShelf (Shelf ):
@@ -227,9 +236,11 @@ class DbfilenameShelf(Shelf):
227236 See the module's __doc__ string for an overview of the interface.
228237 """
229238
230- def __init__ (self , filename , flag = 'c' , protocol = None , writeback = False ):
239+ def __init__ (self , filename , flag = 'c' , protocol = None , writeback = False , * ,
240+ serializer = None , deserializer = None ):
231241 import dbm
232- Shelf .__init__ (self , dbm .open (filename , flag ), protocol , writeback )
242+ Shelf .__init__ (self , dbm .open (filename , flag ), protocol , writeback ,
243+ serializer = serializer , deserializer = deserializer )
233244
234245 def clear (self ):
235246 """Remove all items from the shelf."""
@@ -238,8 +249,8 @@ def clear(self):
238249 self .cache .clear ()
239250 self .dict .clear ()
240251
241-
242- def open ( filename , flag = 'c' , protocol = None , writeback = False ):
252+ def open ( filename , flag = 'c' , protocol = None , writeback = False , * ,
253+ serializer = None , deserializer = None ):
243254 """Open a persistent dictionary for reading and writing.
244255
245256 The filename parameter is the base filename for the underlying
@@ -252,4 +263,5 @@ def open(filename, flag='c', protocol=None, writeback=False):
252263 See the module's __doc__ string for an overview of the interface.
253264 """
254265
255- return DbfilenameShelf (filename , flag , protocol , writeback )
266+ return DbfilenameShelf (filename , flag , protocol , writeback ,
267+ serializer = serializer , deserializer = deserializer )
0 commit comments