From fcbc2fbb7bf828cbe7b077619abd9a6375a0f5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com> Date: Fri, 27 Dec 2024 14:17:03 +0100 Subject: [PATCH] XMLExportImport.OrderedPickle: prevent TypeError on dicts with non orderable keys --- .../test.erp5.testXMLPickle.py | 24 ++++++++++++++++++- product/ERP5Type/XMLExportImport/__init__.py | 7 +++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/bt5/erp5_core_test/TestTemplateItem/portal_components/test.erp5.testXMLPickle.py b/bt5/erp5_core_test/TestTemplateItem/portal_components/test.erp5.testXMLPickle.py index cebc840af3..6a38e7e68f 100644 --- a/bt5/erp5_core_test/TestTemplateItem/portal_components/test.erp5.testXMLPickle.py +++ b/bt5/erp5_core_test/TestTemplateItem/portal_components/test.erp5.testXMLPickle.py @@ -33,7 +33,7 @@ import zodbpickle.fastpickle as pickle import re from io import BytesIO from six import StringIO -from Products.ERP5Type.XMLExportImport import importXML, ppml +from Products.ERP5Type.XMLExportImport import importXML, OrderedPickler, ppml import six import lxml.etree @@ -194,6 +194,7 @@ class TestXMLPickle(XMLPickleTestCase): self.check_and_load({'a': 1, 'b': 2}) self.check_and_load({'hé': 'ho'}) self.check_and_load(dict.fromkeys(range(3000))) + self.check_and_load({1: 'one', 'two': 2}) def test_tuple(self): self.check_and_load((1, )) @@ -346,3 +347,24 @@ class TestXMLPickleStringHeuristics(XMLPickleTestCase): self.assertEqual( persistent_ids, [b'\x00\x00\x00\x00\x00\x00\x00\x01']) + + +class TestOrderedPickler(unittest.TestCase): + def test_ordered_pickler(self): + def check(obj, check_items_order=True): + f = BytesIO() + pickler = OrderedPickler(f) + pickler.dump(obj) + f.seek(0) + reconstructed = pickle.load(f) + self.assertEqual(reconstructed, obj) + self.assertIs(type(reconstructed), type(obj)) + if check_items_order: + self.assertEqual(list(reconstructed.items()), list(obj.items())) + + check({"one": 1, "two": 2}) + check({1: "one", "two": 2}) + check({b"one": 1, b"two": 2}) + check({}) + check(1, check_items_order=False) + check("one", check_items_order=False) diff --git a/product/ERP5Type/XMLExportImport/__init__.py b/product/ERP5Type/XMLExportImport/__init__.py index e64e8ec1e2..2fb2a58f81 100644 --- a/product/ERP5Type/XMLExportImport/__init__.py +++ b/product/ERP5Type/XMLExportImport/__init__.py @@ -74,9 +74,10 @@ class OrderedPickler(Pickler): dispatch = Pickler.dispatch.copy() def save_dict(self, obj): - return Pickler.save_dict( - self, - OrderedDict(sorted(obj.items()))) + items = sorted( + obj.items(), + key=lambda item:str(item[0])) + return Pickler.save_dict(self, OrderedDict(items)) dispatch[dict] = save_dict -- 2.30.9