| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c564847 commit dda70fa
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,7 +17,8 @@ This includes most class instances, recursive data types, and objects containing | |||
| 17 | 17 | lots of shared sub-objects. The keys are ordinary strings. | |
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | - .. function:: open(filename, flag='c', protocol=None, writeback=False) | ||
| 20 | + .. function:: open(filename, flag='c', protocol=None, writeback=False, *, \ | ||
| 21 | + serializer=None, deserializer=None) | ||
| 21 | 22 | ||
| 22 | 23 | Open a persistent dictionary. The filename specified is the base filename for | |
| 23 | 24 | the underlying database. As a side-effect, an extension may be added to the | |
@@ -41,13 +42,32 @@ lots of shared sub-objects. The keys are ordinary strings. | |||
| 41 | 42 | determine which accessed entries are mutable, nor which ones were actually | |
| 42 | 43 | mutated). | |
| 43 | 44 | ||
| 45 | + By default, :mod:`shelve` uses :func:`pickle.dumps` and :func:`pickle.loads` | ||
| 46 | + for serializing and deserializing. This can be changed by supplying | ||
| 47 | + *serializer* and *deserializer*, respectively. | ||
| 48 | + | ||
| 49 | + The *serializer* argument must be a callable which takes an object ``obj`` | ||
| 50 | + and the *protocol* as inputs and returns the representation ``obj`` as a | ||
| 51 | + :term:`bytes-like object`; the *protocol* value may be ignored by the | ||
| 52 | + serializer. | ||
| 53 | + | ||
| 54 | + The *deserializer* argument must be callable which takes a serialized object | ||
| 55 | + given as a :class:`bytes` object and returns the corresponding object. | ||
| 56 | + | ||
| 57 | + A :exc:`ShelveError` is raised if *serializer* is given but *deserializer* | ||
| 58 | + is not, or vice-versa. | ||
| 59 | + | ||
| 44 | 60 | .. versionchanged:: 3.10 | |
| 45 | 61 | :const:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle | |
| 46 | 62 | protocol. | |
| 47 | 63 | ||
| 48 | 64 | .. versionchanged:: 3.11 | |
| 49 | 65 | Accepts :term:`path-like object` for filename. | |
| 50 | 66 | ||
| 67 | + .. versionchanged:: next | ||
| 68 | + Accepts custom *serializer* and *deserializer* functions in place of | ||
| 69 | + :func:`pickle.dumps` and :func:`pickle.loads`. | ||
| 70 | + | ||
| 51 | 71 | .. note:: | |
| 52 | 72 | ||
| 53 | 73 | Do not rely on the shelf being closed automatically; always call | |
@@ -129,7 +149,8 @@ Restrictions | |||
| 129 | 149 | explicitly. | |
| 130 | 150 | ||
| 131 | 151 | ||
| 132 | - .. class:: Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8') | ||
| 152 | + .. class:: Shelf(dict, protocol=None, writeback=False, \ | ||
| 153 | + keyencoding='utf-8', *, serializer=None, deserializer=None) | ||
| 133 | 154 | ||
| 134 | 155 | A subclass of :class:`collections.abc.MutableMapping` which stores pickled | |
| 135 | 156 | values in the *dict* object. | |
@@ -147,6 +168,9 @@ Restrictions | |||
| 147 | 168 | The *keyencoding* parameter is the encoding used to encode keys before they | |
| 148 | 169 | are used with the underlying dict. | |
| 149 | 170 | ||
| 171 | + The *serializer* and *deserializer* parameters have the same interpretation | ||
| 172 | + as in :func:`~shelve.open`. | ||
| 173 | + | ||
| 150 | 174 | A :class:`Shelf` object can also be used as a context manager, in which | |
| 151 | 175 | case it will be automatically closed when the :keyword:`with` block ends. | |
| 152 | 176 | ||
@@ -161,8 +185,13 @@ Restrictions | |||
| 161 | 185 | :const:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle | |
| 162 | 186 | protocol. | |
| 163 | 187 | ||
| 188 | + .. versionchanged:: next | ||
| 189 | + Added the *serializer* and *deserializer* parameters. | ||
| 164 | 190 | ||
| 165 | - .. class:: BsdDbShelf(dict, protocol=None, writeback=False, keyencoding='utf-8') | ||
| 191 | + | ||
| 192 | + .. class:: BsdDbShelf(dict, protocol=None, writeback=False, \ | ||
| 193 | + keyencoding='utf-8', *, \ | ||
| 194 | + serializer=None, deserializer=None) | ||
| 166 | 195 | ||
| 167 | 196 | A subclass of :class:`Shelf` which exposes :meth:`!first`, :meth:`!next`, | |
| 168 | 197 | :meth:`!previous`, :meth:`!last` and :meth:`!set_location` methods. | |
@@ -172,18 +201,27 @@ Restrictions | |||
| 172 | 201 | modules. The *dict* object passed to the constructor must support those | |
| 173 | 202 | methods. This is generally accomplished by calling one of | |
| 174 | 203 | :func:`!bsddb.hashopen`, :func:`!bsddb.btopen` or :func:`!bsddb.rnopen`. The | |
| 175 | - optional *protocol*, *writeback*, and *keyencoding* parameters have the same | ||
| 176 | - interpretation as for the :class:`Shelf` class. | ||
| 204 | + optional *protocol*, *writeback*, *keyencoding*, *serializer* and *deserializer* | ||
| 205 | + parameters have the same interpretation as in :func:`~shelve.open`. | ||
| 206 | + | ||
| 207 | + .. versionchanged:: next | ||
| 208 | + Added the *serializer* and *deserializer* parameters. | ||
| 177 | 209 | ||
| 178 | 210 | ||
| 179 | - .. class:: DbfilenameShelf(filename, flag='c', protocol=None, writeback=False) | ||
| 211 | + .. class:: DbfilenameShelf(filename, flag='c', protocol=None, \ | ||
| 212 | + writeback=False, *, serializer=None, \ | ||
| 213 | + deserializer=None) | ||
| 180 | 214 | ||
| 181 | 215 | A subclass of :class:`Shelf` which accepts a *filename* instead of a dict-like | |
| 182 | 216 | object. The underlying file will be opened using :func:`dbm.open`. By | |
| 183 | 217 | default, the file will be created and opened for both read and write. The | |
| 184 | - optional *flag* parameter has the same interpretation as for the :func:`.open` | ||
| 185 | - function. The optional *protocol* and *writeback* parameters have the same | ||
| 186 | - interpretation as for the :class:`Shelf` class. | ||
| 218 | + optional *flag* parameter has the same interpretation as for the | ||
| 219 | + :func:`.open` function. The optional *protocol*, *writeback*, *serializer* | ||
| 220 | + and *deserializer* parameters have the same interpretation as in | ||
| 221 | + :func:`~shelve.open`. | ||
| 222 | + | ||
| 223 | + .. versionchanged:: next | ||
| 224 | + Added the *serializer* and *deserializer* parameters. | ||
| 187 | 225 | ||
| 188 | 226 | ||
| 189 | 227 | .. _shelve-example: | |
@@ -225,6 +263,20 @@ object):: | |||
| 225 | 263 | d.close() # close it | |
| 226 | 264 | ||
| 227 | 265 | ||
| 266 | + Exceptions | ||
| 267 | + ---------- | ||
| 268 | + | ||
| 269 | + .. exception:: ShelveError | ||
| 270 | + | ||
| 271 | + Exception raised when one of the arguments *deserializer* and *serializer* | ||
| 272 | + is missing in the :func:`~shelve.open`, :class:`Shelf`, :class:`BsdDbShelf` | ||
| 273 | + and :class:`DbfilenameShelf`. | ||
| 274 | + | ||
| 275 | + The *deserializer* and *serializer* arguments must be given together. | ||
| 276 | + | ||
| 277 | + .. versionadded:: next | ||
| 278 | + | ||
| 279 | + | ||
| 228 | 280 | .. seealso:: | |
| 229 | 281 | ||
| 230 | 282 | Module :mod:`dbm` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -56,12 +56,17 @@ | |||
| 56 | 56 | the persistent dictionary on disk, if feasible). | |
| 57 | 57 | """ | |
| 58 | 58 | ||
| 59 | - from pickle import DEFAULT_PROTOCOL, Pickler, Unpickler | ||
| 59 | + from pickle import DEFAULT_PROTOCOL, dumps, loads | ||
| 60 | 60 | from io import BytesIO | |
| 61 | 61 | ||
| 62 | 62 | import collections.abc | |
| 63 | 63 | ||
| 64 | - __all__ = ["Shelf", "BsdDbShelf", "DbfilenameShelf", "open"] | ||
| 64 | + __all__ = ["ShelveError", "Shelf", "BsdDbShelf", "DbfilenameShelf", "open"] | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + class ShelveError(Exception): | ||
| 68 | + pass | ||
| 69 | + | ||
| 65 | 70 | ||
| 66 | 71 | class _ClosedDict(collections.abc.MutableMapping): | |
| 67 | 72 | 'Marker for a closed dict. Access attempts raise a ValueError.' | |
@@ -82,7 +87,7 @@ class Shelf(collections.abc.MutableMapping): | |||
| 82 | 87 | """ | |
| 83 | 88 | ||
| 84 | 89 | def __init__(self, dict, protocol=None, writeback=False, | |
| 85 | - keyencoding="utf-8"): | ||
| 90 | + keyencoding="utf-8", *, serializer=None, deserializer=None): | ||
| 86 | 91 | self.dict = dict | |
| 87 | 92 | if protocol is None: | |
| 88 | 93 | protocol = DEFAULT_PROTOCOL | |
@@ -91,6 +96,16 @@ def __init__(self, dict, protocol=None, writeback=False, | |||
| 91 | 96 | self.cache = {} | |
| 92 | 97 | self.keyencoding = keyencoding | |
| 93 | 98 | ||
| 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 | + | ||
| 94 | 109 | def __iter__(self): | |
| 95 | 110 | for k in self.dict.keys(): | |
| 96 | 111 | yield k.decode(self.keyencoding) | |
@@ -110,19 +125,17 @@ def __getitem__(self, key): | |||
| 110 | 125 | try: | |
| 111 | 126 | value = self.cache[key] | |
| 112 | 127 | 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) | ||
| 115 | 130 | if self.writeback: | |
| 116 | 131 | self.cache[key] = value | |
| 117 | 132 | return value | |
| 118 | 133 | ||
| 119 | 134 | def __setitem__(self, key, value): | |
| 120 | 135 | if self.writeback: | |
| 121 | 136 | 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 | ||
| 126 | 139 | ||
| 127 | 140 | def __delitem__(self, key): | |
| 128 | 141 | del self.dict[key.encode(self.keyencoding)] | |
@@ -191,33 +204,29 @@ class BsdDbShelf(Shelf): | |||
| 191 | 204 | """ | |
| 192 | 205 | ||
| 193 | 206 | 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) | ||
| 196 | 210 | ||
| 197 | 211 | def set_location(self, key): | |
| 198 | 212 | (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)) | ||
| 201 | 214 | ||
| 202 | 215 | def next(self): | |
| 203 | 216 | (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)) | ||
| 206 | 218 | ||
| 207 | 219 | def previous(self): | |
| 208 | 220 | (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)) | ||
| 211 | 222 | ||
| 212 | 223 | def first(self): | |
| 213 | 224 | (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)) | ||
| 216 | 226 | ||
| 217 | 227 | def last(self): | |
| 218 | 228 | (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)) | ||
| 221 | 230 | ||
| 222 | 231 | ||
| 223 | 232 | class DbfilenameShelf(Shelf): | |
@@ -227,9 +236,11 @@ class DbfilenameShelf(Shelf): | |||
| 227 | 236 | See the module's __doc__ string for an overview of the interface. | |
| 228 | 237 | """ | |
| 229 | 238 | ||
| 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): | ||
| 231 | 241 | 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) | ||
| 233 | 244 | ||
| 234 | 245 | def clear(self): | |
| 235 | 246 | """Remove all items from the shelf.""" | |
@@ -238,8 +249,8 @@ def clear(self): | |||
| 238 | 249 | self.cache.clear() | |
| 239 | 250 | self.dict.clear() | |
| 240 | 251 | ||
| 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): | ||
| 243 | 254 | """Open a persistent dictionary for reading and writing. | |
| 244 | 255 | ||
| 245 | 256 | The filename parameter is the base filename for the underlying | |
@@ -252,4 +263,5 @@ def open(filename, flag='c', protocol=None, writeback=False): | |||
| 252 | 263 | See the module's __doc__ string for an overview of the interface. | |
| 253 | 264 | """ | |
| 254 | 265 | ||
| 255 | - return DbfilenameShelf(filename, flag, protocol, writeback) | ||
| 266 | + return DbfilenameShelf(filename, flag, protocol, writeback, | ||
| 267 | + serializer=serializer, deserializer=deserializer) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments