From 79bf61c9be9b6c468b8665b851afe4d95c069320 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Mon, 21 Nov 2022 01:56:37 +0300 Subject: [PATCH 01/14] gh-99631: Add custom unpickler and pickler support for the shelve module --- Lib/shelve.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/shelve.py b/Lib/shelve.py index e053c397345a07..78d74ae244afd0 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -82,7 +82,7 @@ class Shelf(collections.abc.MutableMapping): """ def __init__(self, dict, protocol=None, writeback=False, - keyencoding="utf-8"): + keyencoding="utf-8", pickler=Pickler, unpickler=Unpickler): self.dict = dict if protocol is None: protocol = DEFAULT_PROTOCOL @@ -90,6 +90,8 @@ def __init__(self, dict, protocol=None, writeback=False, self.writeback = writeback self.cache = {} self.keyencoding = keyencoding + self.pickler = pickler + self.unpickler = unpickler def __iter__(self): for k in self.dict.keys(): @@ -111,7 +113,7 @@ def __getitem__(self, key): value = self.cache[key] except KeyError: f = BytesIO(self.dict[key.encode(self.keyencoding)]) - value = Unpickler(f).load() + value = self.unpickler(f).load() if self.writeback: self.cache[key] = value return value @@ -120,7 +122,7 @@ def __setitem__(self, key, value): if self.writeback: self.cache[key] = value f = BytesIO() - p = Pickler(f, self._protocol) + p = self.pickler(f, self._protocol) p.dump(value) self.dict[key.encode(self.keyencoding)] = f.getvalue() @@ -172,6 +174,7 @@ def sync(self): self.dict.sync() + class BsdDbShelf(Shelf): """Shelf implementation using the "BSD" db interface. @@ -222,12 +225,12 @@ class DbfilenameShelf(Shelf): See the module's __doc__ string for an overview of the interface. """ - def __init__(self, filename, flag='c', protocol=None, writeback=False): + def __init__(self, filename, flag='c', protocol=None, writeback=False, pickler=Pickler, unpickler=Unpickler): import dbm - Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback) + Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, pickler=pickler, unpickler=unpickler) -def open(filename, flag='c', protocol=None, writeback=False): +def open(filename, flag='c', protocol=None, writeback=False, pickler=Pickler, unpickler=Unpickler): """Open a persistent dictionary for reading and writing. The filename parameter is the base filename for the underlying @@ -240,4 +243,4 @@ def open(filename, flag='c', protocol=None, writeback=False): See the module's __doc__ string for an overview of the interface. """ - return DbfilenameShelf(filename, flag, protocol, writeback) + return DbfilenameShelf(filename, flag, protocol, writeback, pickler, unpickler) From ef7ba367259e5f06fbfa4d2d6dab58043f6cac7c Mon Sep 17 00:00:00 2001 From: furkanonder Date: Sun, 4 Dec 2022 00:03:17 +0300 Subject: [PATCH 02/14] add custom loads & dumps test --- Lib/test/test_shelve.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 08c6562f2a273e..c7e53e85122af1 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -3,6 +3,7 @@ import shelve import pickle import os +from io import BytesIO from test.support import os_helper from collections.abc import MutableMapping @@ -165,6 +166,22 @@ def test_default_protocol(self): with shelve.Shelf({}) as s: self.assertEqual(s._protocol, pickle.DEFAULT_PROTOCOL) + def test_custom_loads_and_dumps(self): + def custom_dumps(obj, protocol=None): + return bytes(f"{type(obj)}", 'utf-8') + + def custom_loads(data): + value = BytesIO(data).read() + return value.decode("utf-8") + + os.mkdir(self.dirname) + self.addCleanup(os_helper.rmtree, self.dirname) + + with shelve.open(self.fn, custom_dumps=custom_dumps, custom_loads=custom_loads) as s: + num = 1 + s['number'] = num + self.assertEqual(s['number'], f"{type(num)}") + class TestShelveBase: type2test = shelve.Shelf From cfba257cabf69322c468ee8d3715ec511fef58de Mon Sep 17 00:00:00 2001 From: furkanonder Date: Sun, 4 Dec 2022 00:04:23 +0300 Subject: [PATCH 03/14] use custom loads & dumps instead of custom pickler & unpickler --- Lib/shelve.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/Lib/shelve.py b/Lib/shelve.py index 78d74ae244afd0..8f440f93333734 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -56,7 +56,7 @@ the persistent dictionary on disk, if feasible). """ -from pickle import DEFAULT_PROTOCOL, Pickler, Unpickler +from pickle import DEFAULT_PROTOCOL, Unpickler, dumps, loads from io import BytesIO import collections.abc @@ -82,7 +82,7 @@ class Shelf(collections.abc.MutableMapping): """ def __init__(self, dict, protocol=None, writeback=False, - keyencoding="utf-8", pickler=Pickler, unpickler=Unpickler): + keyencoding="utf-8", custom_dumps=dumps, custom_loads=loads): self.dict = dict if protocol is None: protocol = DEFAULT_PROTOCOL @@ -90,8 +90,8 @@ def __init__(self, dict, protocol=None, writeback=False, self.writeback = writeback self.cache = {} self.keyencoding = keyencoding - self.pickler = pickler - self.unpickler = unpickler + self.custom_dumps = custom_dumps + self.custom_loads = custom_loads def __iter__(self): for k in self.dict.keys(): @@ -112,8 +112,8 @@ def __getitem__(self, key): try: value = self.cache[key] except KeyError: - f = BytesIO(self.dict[key.encode(self.keyencoding)]) - value = self.unpickler(f).load() + f = self.dict[key.encode(self.keyencoding)] + value = self.custom_loads(f) if self.writeback: self.cache[key] = value return value @@ -121,10 +121,7 @@ def __getitem__(self, key): def __setitem__(self, key, value): if self.writeback: self.cache[key] = value - f = BytesIO() - p = self.pickler(f, self._protocol) - p.dump(value) - self.dict[key.encode(self.keyencoding)] = f.getvalue() + self.dict[key.encode(self.keyencoding)] = self.custom_dumps(value, self._protocol) def __delitem__(self, key): del self.dict[key.encode(self.keyencoding)] @@ -225,12 +222,12 @@ class DbfilenameShelf(Shelf): See the module's __doc__ string for an overview of the interface. """ - def __init__(self, filename, flag='c', protocol=None, writeback=False, pickler=Pickler, unpickler=Unpickler): + def __init__(self, filename, flag='c', protocol=None, writeback=False, custom_dumps=dumps, custom_loads=loads): import dbm - Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, pickler=pickler, unpickler=unpickler) + Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, custom_dumps=custom_dumps, custom_loads=custom_loads) -def open(filename, flag='c', protocol=None, writeback=False, pickler=Pickler, unpickler=Unpickler): +def open(filename, flag='c', protocol=None, writeback=False, custom_dumps=dumps, custom_loads=loads): """Open a persistent dictionary for reading and writing. The filename parameter is the base filename for the underlying @@ -243,4 +240,4 @@ def open(filename, flag='c', protocol=None, writeback=False, pickler=Pickler, un See the module's __doc__ string for an overview of the interface. """ - return DbfilenameShelf(filename, flag, protocol, writeback, pickler, unpickler) + return DbfilenameShelf(filename, flag, protocol, writeback, custom_dumps, custom_loads) From 24ebcdf218846cf901815554be8d1643fa6cf70c Mon Sep 17 00:00:00 2001 From: furkanonder Date: Sun, 4 Dec 2022 01:04:20 +0300 Subject: [PATCH 04/14] update custom loads & dumps test --- Lib/test/test_shelve.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index c7e53e85122af1..03bcccf95d11c1 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -4,6 +4,7 @@ import pickle import os from io import BytesIO +from pydoc import locate from test.support import os_helper from collections.abc import MutableMapping @@ -168,11 +169,11 @@ def test_default_protocol(self): def test_custom_loads_and_dumps(self): def custom_dumps(obj, protocol=None): - return bytes(f"{type(obj)}", 'utf-8') + return bytes(f"{type(obj).__name__}", 'utf-8') def custom_loads(data): value = BytesIO(data).read() - return value.decode("utf-8") + return locate(value.decode("utf-8")) os.mkdir(self.dirname) self.addCleanup(os_helper.rmtree, self.dirname) @@ -180,7 +181,7 @@ def custom_loads(data): with shelve.open(self.fn, custom_dumps=custom_dumps, custom_loads=custom_loads) as s: num = 1 s['number'] = num - self.assertEqual(s['number'], f"{type(num)}") + self.assertEqual(s['number'], type(num)) class TestShelveBase: From 4c80767e231db10877b3ae9acef4e8d47aff6626 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Sun, 4 Dec 2022 01:15:02 +0300 Subject: [PATCH 05/14] Update document for custom_loads and custom_dumps --- Doc/library/shelve.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index a50fc6f0bf77b2..5cf35f5eed4743 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -17,7 +17,7 @@ This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings. -.. function:: open(filename, flag='c', protocol=None, writeback=False) +.. function:: open(filename, flag='c', protocol=None, writeback=False, custom_dumps=dumps, custom_loads=loads) Open a persistent dictionary. The filename specified is the base filename for the underlying database. As a side-effect, an extension may be added to the @@ -41,6 +41,14 @@ lots of shared sub-objects. The keys are ordinary strings. determine which accessed entries are mutable, nor which ones were actually mutated). + By default, :mod:`shelve` uses :func:`pickle.dumps` and :func:`pickle.loads` + for pickling and unpickling. However *custom_loads* can be the function + that takes the :term:`bytes-like object` and returns the object. *custom_dumps* + can be the function that takes the object and returns :class:`bytes`. For example, + :keyword:`lambda`, which the :mod:`pickle` does not support, can be used in + :mod:`shelve` using the custom loads and custom dumps functions, which do support + the :keyword:`lambda`. + .. versionchanged:: 3.10 :data:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle protocol. @@ -48,6 +56,9 @@ lots of shared sub-objects. The keys are ordinary strings. .. versionchanged:: 3.11 Accepts :term:`path-like object` for filename. + .. versionchanged:: 3.12 + Accepts *custom_dumps* and *custom_loads*. + .. note:: Do not rely on the shelf being closed automatically; always call From 64ea4742829922460e77e1a2b8560851f062639e Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 5 Dec 2022 19:21:26 +0000 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst diff --git a/Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst b/Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst new file mode 100644 index 00000000000000..afab82b6448fa0 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst @@ -0,0 +1 @@ +Shelve module accepts custom_dumps and custom_loads functions. From 7dfc0c7e0e66a675b2d6a2704b5c7be2fcbd6fb7 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Wed, 7 Dec 2022 23:02:48 +0300 Subject: [PATCH 07/14] use serializer & deserializer instead of custom_dumps & custom_loads --- Doc/library/shelve.rst | 10 +++++----- Lib/shelve.py | 23 ++++++++++++++--------- Lib/test/test_shelve.py | 8 ++++---- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index 5cf35f5eed4743..388c2fee466c99 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -17,7 +17,7 @@ This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings. -.. function:: open(filename, flag='c', protocol=None, writeback=False, custom_dumps=dumps, custom_loads=loads) +.. function:: open(filename, flag='c', protocol=None, writeback=False, serializer=None, deserializer=None) Open a persistent dictionary. The filename specified is the base filename for the underlying database. As a side-effect, an extension may be added to the @@ -42,11 +42,11 @@ lots of shared sub-objects. The keys are ordinary strings. mutated). By default, :mod:`shelve` uses :func:`pickle.dumps` and :func:`pickle.loads` - for pickling and unpickling. However *custom_loads* can be the function - that takes the :term:`bytes-like object` and returns the object. *custom_dumps* + for serializing and deserializing. However *serializer* can be the function + that takes the :term:`bytes-like object` and returns the object. *deserializer* can be the function that takes the object and returns :class:`bytes`. For example, :keyword:`lambda`, which the :mod:`pickle` does not support, can be used in - :mod:`shelve` using the custom loads and custom dumps functions, which do support + :mod:`shelve` using the serializer and deserializer functions, which do support the :keyword:`lambda`. .. versionchanged:: 3.10 @@ -57,7 +57,7 @@ lots of shared sub-objects. The keys are ordinary strings. Accepts :term:`path-like object` for filename. .. versionchanged:: 3.12 - Accepts *custom_dumps* and *custom_loads*. + Accepts *serializer* and *deserializer*. .. note:: diff --git a/Lib/shelve.py b/Lib/shelve.py index 8f440f93333734..c02bbfddbb644b 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -82,7 +82,7 @@ class Shelf(collections.abc.MutableMapping): """ def __init__(self, dict, protocol=None, writeback=False, - keyencoding="utf-8", custom_dumps=dumps, custom_loads=loads): + keyencoding="utf-8", *, serializer=None, deserializer=None): self.dict = dict if protocol is None: protocol = DEFAULT_PROTOCOL @@ -90,8 +90,13 @@ def __init__(self, dict, protocol=None, writeback=False, self.writeback = writeback self.cache = {} self.keyencoding = keyencoding - self.custom_dumps = custom_dumps - self.custom_loads = custom_loads + + if serializer is None and deserializer is None: + self.serializer = dumps + self.deserializer = loads + else: + self.serializer = serializer + self.deserializer = deserializer def __iter__(self): for k in self.dict.keys(): @@ -113,7 +118,7 @@ def __getitem__(self, key): value = self.cache[key] except KeyError: f = self.dict[key.encode(self.keyencoding)] - value = self.custom_loads(f) + value = self.deserializer(f) if self.writeback: self.cache[key] = value return value @@ -121,7 +126,7 @@ def __getitem__(self, key): def __setitem__(self, key, value): if self.writeback: self.cache[key] = value - self.dict[key.encode(self.keyencoding)] = self.custom_dumps(value, self._protocol) + self.dict[key.encode(self.keyencoding)] = self.serializer(value, self._protocol) def __delitem__(self, key): del self.dict[key.encode(self.keyencoding)] @@ -222,12 +227,12 @@ class DbfilenameShelf(Shelf): See the module's __doc__ string for an overview of the interface. """ - def __init__(self, filename, flag='c', protocol=None, writeback=False, custom_dumps=dumps, custom_loads=loads): + def __init__(self, filename, flag='c', protocol=None, writeback=False, serializer=None, deserializer=None): import dbm - Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, custom_dumps=custom_dumps, custom_loads=custom_loads) + Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, serializer=serializer, deserializer=deserializer) -def open(filename, flag='c', protocol=None, writeback=False, custom_dumps=dumps, custom_loads=loads): +def open(filename, flag='c', protocol=None, writeback=False, *, serializer=None, deserializer=None): """Open a persistent dictionary for reading and writing. The filename parameter is the base filename for the underlying @@ -240,4 +245,4 @@ def open(filename, flag='c', protocol=None, writeback=False, custom_dumps=dumps, See the module's __doc__ string for an overview of the interface. """ - return DbfilenameShelf(filename, flag, protocol, writeback, custom_dumps, custom_loads) + return DbfilenameShelf(filename, flag, protocol, writeback, serializer, deserializer) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 03bcccf95d11c1..9f6db9f771e449 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -167,18 +167,18 @@ def test_default_protocol(self): with shelve.Shelf({}) as s: self.assertEqual(s._protocol, pickle.DEFAULT_PROTOCOL) - def test_custom_loads_and_dumps(self): - def custom_dumps(obj, protocol=None): + def test_custom_serializer_and_deserializer(self): + def serializer(obj, protocol=None): return bytes(f"{type(obj).__name__}", 'utf-8') - def custom_loads(data): + def deserializer(data): value = BytesIO(data).read() return locate(value.decode("utf-8")) os.mkdir(self.dirname) self.addCleanup(os_helper.rmtree, self.dirname) - with shelve.open(self.fn, custom_dumps=custom_dumps, custom_loads=custom_loads) as s: + with shelve.open(self.fn, serializer=serializer, deserializer=deserializer) as s: num = 1 s['number'] = num self.assertEqual(s['number'], type(num)) From bb9ffd85101607286d172c978086f536ff24a7aa Mon Sep 17 00:00:00 2001 From: furkanonder Date: Fri, 9 Dec 2022 13:12:58 +0300 Subject: [PATCH 08/14] Add custom error for missing serializer & deserializer --- Lib/shelve.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/shelve.py b/Lib/shelve.py index c02bbfddbb644b..83f9e08f452883 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -63,6 +63,11 @@ __all__ = ["Shelf", "BsdDbShelf", "DbfilenameShelf", "open"] + +class ShelveError(Exception): + pass + + class _ClosedDict(collections.abc.MutableMapping): 'Marker for a closed dict. Access attempts raise a ValueError.' @@ -94,6 +99,8 @@ def __init__(self, dict, protocol=None, writeback=False, if serializer is None and deserializer is None: self.serializer = dumps self.deserializer = loads + elif (serializer is None and deserializer is not None) or (deserializer is None and serializer is not None): + raise ShelveError("Serializer and deserializer must be defined together.") else: self.serializer = serializer self.deserializer = deserializer From 534f4759f99a4df2152266c748526c25ad32cded Mon Sep 17 00:00:00 2001 From: furkanonder Date: Fri, 9 Dec 2022 13:17:23 +0300 Subject: [PATCH 09/14] add test cases for missing serializer & deserializer --- Lib/test/test_shelve.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 9f6db9f771e449..64b3769f1f2ea8 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -10,6 +10,9 @@ from collections.abc import MutableMapping from test.test_dbm import dbm_iterator +from Lib.shelve import ShelveError + + def L1(s): return s.decode("latin-1") @@ -183,6 +186,20 @@ def deserializer(data): s['number'] = num self.assertEqual(s['number'], type(num)) + def test_missing_custom_deserializer(self): + def serializer(obj, protocol=None): + pass + + with self.assertRaises(shelve.ShelveError): + shelve.Shelf({}, protocol=2, writeback=False, serializer=serializer) + + def test_missing_custom_serializer(self): + def deserializer(data): + pass + + with self.assertRaises(shelve.ShelveError): + shelve.Shelf({}, protocol=2, writeback=False, deserializer=deserializer) + class TestShelveBase: type2test = shelve.Shelf From c9132f3e412302e0b1fad1e9285f2927329f5dee Mon Sep 17 00:00:00 2001 From: Furkan Onder Date: Fri, 9 Dec 2022 17:30:44 +0300 Subject: [PATCH 10/14] Update 2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst --- .../Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst b/Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst index afab82b6448fa0..3a14448a98b84c 100644 --- a/Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst +++ b/Misc/NEWS.d/next/Documentation/2022-12-05-19-21-22.gh-issue-99631.WVkNJl.rst @@ -1 +1 @@ -Shelve module accepts custom_dumps and custom_loads functions. +Shelve module accepts serializer and deserializer functions. From 4d45669971d0103db0b4d38ebb84318daa776dc5 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Fri, 9 Dec 2022 17:41:43 +0300 Subject: [PATCH 11/14] add new testcases for shelve --- Lib/test/test_shelve.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 64b3769f1f2ea8..2302d25f742687 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -186,6 +186,28 @@ def deserializer(data): s['number'] = num self.assertEqual(s['number'], type(num)) + with self.assertRaises(AssertionError): + def serializer(obj, protocol=None): + return bytes(f"{type(obj).__name__}", 'utf-8') + + def deserializer(data): + pass + + with shelve.open(self.fn, serializer=serializer, deserializer=deserializer) as s: + s['number'] = 100 + self.assertEqual(s['number'], 100) + + with self.assertRaises(TypeError): + def serializer(obj, protocol=None): + pass + + def deserializer(data): + return BytesIO(data).read().decode("utf-8") + + with shelve.open(self.fn, serializer=serializer, deserializer=deserializer) as s: + s['number'] = 100 + self.assertEqual(s['number'], 100) + def test_missing_custom_deserializer(self): def serializer(obj, protocol=None): pass From 11cbfbf1c9587245aaafc296a606f7f55cf983e5 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Fri, 9 Dec 2022 17:51:10 +0300 Subject: [PATCH 12/14] remove unnecessary imports & white spaces --- Lib/shelve.py | 1 - Lib/test/test_shelve.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/Lib/shelve.py b/Lib/shelve.py index 83f9e08f452883..6476e461e0eb30 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -183,7 +183,6 @@ def sync(self): self.dict.sync() - class BsdDbShelf(Shelf): """Shelf implementation using the "BSD" db interface. diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 2302d25f742687..87477d830d377e 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -10,9 +10,6 @@ from collections.abc import MutableMapping from test.test_dbm import dbm_iterator -from Lib.shelve import ShelveError - - def L1(s): return s.decode("latin-1") From 9ced2cd24d4d8eb0576597913bb717135efe9637 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Tue, 20 Dec 2022 00:51:40 +0300 Subject: [PATCH 13/14] use xor in the simply serializer & deserializer check --- Lib/shelve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/shelve.py b/Lib/shelve.py index 6476e461e0eb30..9963e49d6227b7 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -99,7 +99,7 @@ def __init__(self, dict, protocol=None, writeback=False, if serializer is None and deserializer is None: self.serializer = dumps self.deserializer = loads - elif (serializer is None and deserializer is not None) or (deserializer is None and serializer is not None): + elif (serializer is None) ^ (deserializer is None): raise ShelveError("Serializer and deserializer must be defined together.") else: self.serializer = serializer From e9ae1be68ccc931cf8300e195d15c89cf88ff2a1 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Tue, 20 Dec 2022 00:52:36 +0300 Subject: [PATCH 14/14] update DbfilenameShelf __init__ function as keyword-argument only --- Lib/shelve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/shelve.py b/Lib/shelve.py index 9963e49d6227b7..f4bac3d962201c 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -233,7 +233,7 @@ class DbfilenameShelf(Shelf): See the module's __doc__ string for an overview of the interface. """ - def __init__(self, filename, flag='c', protocol=None, writeback=False, serializer=None, deserializer=None): + def __init__(self, filename, flag='c', protocol=None, writeback=False, *, serializer=None, deserializer=None): import dbm Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, serializer=serializer, deserializer=deserializer)