From fe10f4559b97164a6e5649af13f5dbd3a77ba99d Mon Sep 17 00:00:00 2001 From: James Page Date: Mon, 22 Jan 2024 17:08:52 +0000 Subject: [PATCH] fixture: Drop use of OrderedDict for Python compat Python >= 3.12 changes the string representation of an OrderedDict which changes the md5 digest of an object; this causes a regression on the test_get_hashes unit test on newer Pythons. Subclass OrderedDict to revert the change in __repr__ in order provide a represenation which is consistent across all supported Python versions. Closes-Bug: #2046220 Change-Id: I9b0d9e7b501f3de425bc2c342f25b8ea2248da20 --- oslo_versionedobjects/fixture.py | 19 ++++++++++++++++++- oslo_versionedobjects/tests/test_fixture.py | 6 +++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/oslo_versionedobjects/fixture.py b/oslo_versionedobjects/fixture.py index 9661c70e..eccacd98 100644 --- a/oslo_versionedobjects/fixture.py +++ b/oslo_versionedobjects/fixture.py @@ -26,6 +26,7 @@ import copy import datetime import inspect import logging +from reprlib import recursive_repr from unittest import mock import fixtures @@ -101,6 +102,22 @@ def compare_obj(test, obj, db_obj, subs=None, allow_missing=None, test.assertEqual(db_val, obj_val) +class OsloOrderedDict(OrderedDict): + """Oslo version of OrderedDict for Python consistency.""" + + @recursive_repr() + def __repr__(self): + if not self: + return '%s()' % self.__class__.__bases__[0].__name__ + # NOTE(jamespage): + # Python >= 3.12 uses a dict instead of a list which changes the + # repr of the versioned object and its associated hash value + # Switch back to using list an use super class name. + return '%s(%r)' % ( + self.__class__.__bases__[0].__name__, list(self.items()) + ) + + class FakeIndirectionAPI(base.VersionedObjectIndirectionAPI): def __init__(self, serializer=None): super(FakeIndirectionAPI, self).__init__() @@ -263,7 +280,7 @@ class ObjectVersionChecker(object): # and return value changes, for example). if hasattr(obj_class, 'child_versions'): relevant_data = (obj_fields, methods, - OrderedDict( + OsloOrderedDict( sorted(obj_class.child_versions.items()))) else: relevant_data = (obj_fields, methods) diff --git a/oslo_versionedobjects/tests/test_fixture.py b/oslo_versionedobjects/tests/test_fixture.py index f991f745..e6a84a55 100644 --- a/oslo_versionedobjects/tests/test_fixture.py +++ b/oslo_versionedobjects/tests/test_fixture.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -import collections import copy import datetime import hashlib @@ -565,8 +564,9 @@ class TestObjectVersionChecker(test.TestCase): exp_fields = sorted(list(MyObject.fields.items())) exp_methods = sorted([('remotable_method', argspec), ('remotable_classmethod', argspec)]) - exp_child_versions = collections.OrderedDict(sorted( - child_versions.items())) + exp_child_versions = fixture.OsloOrderedDict( + sorted(child_versions.items()) + ) exp_relevant_data = (exp_fields, exp_methods, exp_child_versions) # NOTE(hberaud) the following hashlib usage will emit a bandit