From 306e43dc49aadf0151428a13c2efcd97a9a024da Mon Sep 17 00:00:00 2001 From: furkanonder Date: Sun, 17 Aug 2025 17:48:55 +0300 Subject: [PATCH 1/3] Fix shelve tests for backend compatibility --- Lib/test/test_shelve.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 64609ab9dd9a62..35544a98795241 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -173,6 +173,8 @@ def test_custom_serializer_and_deserializer(self): def serializer(obj, protocol): if isinstance(obj, (bytes, bytearray, str)): if protocol == 5: + if isinstance(obj, bytearray): + return bytes(obj) return obj return type(obj).__name__ elif isinstance(obj, array.array): @@ -223,11 +225,10 @@ def deserializer(data): ) def test_custom_incomplete_serializer_and_deserializer(self): - dbm_sqlite3 = import_helper.import_module("dbm.sqlite3") os.mkdir(self.dirname) self.addCleanup(os_helper.rmtree, self.dirname) - with self.assertRaises(dbm_sqlite3.error): + with self.assertRaises((TypeError, dbm.error)): def serializer(obj, protocol=None): pass From 79e335ebe7ccd5dec0c1d0076d06e6f1d36ad973 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Mon, 18 Aug 2025 23:10:47 +0300 Subject: [PATCH 2/3] split incomplete serializer/deserializer in test_shelve --- Lib/test/test_shelve.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 35544a98795241..bb589e544c269d 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -224,21 +224,25 @@ def deserializer(data): s["array_data"], array_data.tobytes().decode() ) - def test_custom_incomplete_serializer_and_deserializer(self): + def test_custom_incomplete_serializer(self): os.mkdir(self.dirname) self.addCleanup(os_helper.rmtree, self.dirname) - with self.assertRaises((TypeError, dbm.error)): - def serializer(obj, protocol=None): - pass + def serializer(obj, protocol=None): + pass - def deserializer(data): - return data.decode("utf-8") + def deserializer(data): + return data.decode("utf-8") + with self.assertRaises((TypeError, dbm.error)): with shelve.open(self.fn, serializer=serializer, deserializer=deserializer) as s: s["foo"] = "bar" + def test_custom_incomplete_deserializer(self): + os.mkdir(self.dirname) + self.addCleanup(os_helper.rmtree, self.dirname) + def serializer(obj, protocol=None): return type(obj).__name__.encode("utf-8") @@ -353,7 +357,7 @@ def type_name_len(obj): self.assertEqual(s["bytearray_data"], "bytearray") self.assertEqual(s["array_data"], "array") - def test_custom_incomplete_serializer_and_deserializer_bsd_db_shelf(self): + def test_custom_incomplete_deserializer_bsd_db_shelf(self): berkeleydb = import_helper.import_module("berkeleydb") os.mkdir(self.dirname) self.addCleanup(os_helper.rmtree, self.dirname) @@ -371,6 +375,11 @@ def deserializer(data): self.assertIsNone(s["foo"]) self.assertNotEqual(s["foo"], "bar") + def test_custom_incomplete_serializer_bsd_db_shelf(self): + berkeleydb = import_helper.import_module("berkeleydb") + os.mkdir(self.dirname) + self.addCleanup(os_helper.rmtree, self.dirname) + def serializer(obj, protocol=None): pass From 5b9f61b4ff3547e7c56b92233954de39ea76f4aa Mon Sep 17 00:00:00 2001 From: furkanonder Date: Tue, 19 Aug 2025 02:03:17 +0300 Subject: [PATCH 3/3] add a test case for custom serializer that returning wrong type --- 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 bb589e544c269d..760bb5096bef2d 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -409,6 +409,28 @@ def deserializer(data): self.assertRaises(shelve.ShelveError, shelve.Shelf, {}, **kwargs) self.assertRaises(shelve.ShelveError, shelve.BsdDbShelf, {}, **kwargs) + def test_custom_serializer_returns_wrong_type_for_key(self): + os.mkdir(self.dirname) + self.addCleanup(os_helper.rmtree, self.dirname) + + def serializer(obj, protocol): + # Return None instead of bytes, which is wrong for dbm keys + return None + + def deserializer(data): + return data.decode("utf-8") if data else "" + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto), shelve.open( + self.fn, + protocol=proto, + serializer=serializer, + deserializer=deserializer + ) as s: + # Serializer returns None for the value, but dbm expects bytes + with self.assertRaises((TypeError, dbm.error)): + s["foo"] = "bar" + class TestShelveBase: type2test = shelve.Shelf