diff --git a/evennia/typeclasses/tests.py b/evennia/typeclasses/tests.py index d97e7c3b5e..d4761638f9 100644 --- a/evennia/typeclasses/tests.py +++ b/evennia/typeclasses/tests.py @@ -3,8 +3,8 @@ Unit tests for typeclass base system """ from django.test import override_settings -from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTestCase from evennia.typeclasses import attributes +from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTestCase from mock import patch from parameterized import parameterized @@ -13,6 +13,10 @@ from parameterized import parameterized # ------------------------------------------------------------ +class DictSubclass(dict): + pass + + class TestAttributes(BaseEvenniaTest): def test_attrhandler(self): key = "testattr" @@ -22,6 +26,14 @@ class TestAttributes(BaseEvenniaTest): self.obj1.db.testattr = value self.assertEqual(self.obj1.db.testattr, value) + value = DictSubclass({"fo": "foo", "bar": "bar"}) + self.obj1.db.testattr = value + self.assertEqual(self.obj1.db.testattr, value) + + value = DictSubclass({"fo": "foo", "bar": "bar", "obj": self.obj2}) + self.obj1.db.testattr = value + self.assertEqual(self.obj1.db.testattr, value) + @override_settings(TYPECLASS_AGGRESSIVE_CACHE=False) @patch("evennia.typeclasses.attributes._TYPECLASS_AGGRESSIVE_CACHE", False) def test_attrhandler_nocache(self): @@ -35,6 +47,16 @@ class TestAttributes(BaseEvenniaTest): self.assertEqual(self.obj1.db.testattr, value) self.assertFalse(self.obj1.attributes.backend._cache) + value = DictSubclass({"fo": "foo", "bar": "bar"}) + self.obj1.db.dict_subclass = value + self.assertEqual(self.obj1.db.dict_subclass, value) + self.assertFalse(self.obj1.attributes.backend._cache) + + value = DictSubclass({"fo": "foo", "bar": "bar", "obj": self.obj2}) + self.obj1.db.dict_subclass = value + self.assertEqual(self.obj1.db.dict_subclass, value) + self.assertFalse(self.obj1.attributes.backend._cache) + def test_weird_text_save(self): "test 'weird' text type (different in py2 vs py3)" from django.utils.safestring import SafeText diff --git a/evennia/utils/dbserialize.py b/evennia/utils/dbserialize.py index 11321d8dfd..dba21c63a2 100644 --- a/evennia/utils/dbserialize.py +++ b/evennia/utils/dbserialize.py @@ -644,7 +644,15 @@ def to_pickle(data): # classmethods) and instances pass - if hasattr(item, "__iter__"): + if hasattr(item, "items"): + # we try to conserve the iterable class, if not convert to dict + try: + return item.__class__( + (process_item(key), process_item(val)) for key, val in item.items() + ) + except (AttributeError, TypeError): + return {process_item(key): process_item(val) for key, val in item.items()} + elif hasattr(item, "__iter__"): # we try to conserve the iterable class, if not convert to list try: return item.__class__([process_item(val) for val in item]) @@ -712,6 +720,14 @@ def from_pickle(data, db_obj=None): return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) elif dtype == deque: return deque(process_item(val) for val in item) + elif hasattr(item, "items"): + # we try to conserve the iterable class, if not convert to dict + try: + return item.__class__( + (process_item(key), process_item(val)) for key, val in item.items() + ) + except (AttributeError, TypeError): + return {process_item(key): process_item(val) for key, val in item.items()} elif hasattr(item, "__iter__"): try: # we try to conserve the iterable class if @@ -778,6 +794,18 @@ def from_pickle(data, db_obj=None): dat = _SaverDeque(_parent=parent) dat._data.extend(process_item(val) for val in item) return dat + elif hasattr(item, "items"): + # we try to conserve the iterable class, if not convert to dict + try: + return item.__class__( + (process_item(key), process_tree(val, parent)) for key, val in item.items() + ) + except (AttributeError, TypeError): + dat = _SaverDict(_parent=parent) + dat._data.update( + (process_item(key), process_tree(val, dat)) for key, val in item.items() + ) + return dat elif hasattr(item, "__iter__"): try: # we try to conserve the iterable class if it diff --git a/evennia/utils/tests/test_gametime.py b/evennia/utils/tests/test_gametime.py index 9060546cbf..c9d7801ea8 100644 --- a/evennia/utils/tests/test_gametime.py +++ b/evennia/utils/tests/test_gametime.py @@ -86,6 +86,7 @@ class TestGametime(TestCase): def test_schedule(self): callback = Mock() + del callback.items script = gametime.schedule(callback, day=19) self.timescripts.append(script) self.assertIsInstance(script, gametime.TimeScript) @@ -94,6 +95,7 @@ class TestGametime(TestCase): def test_repeat_schedule(self): callback = Mock() + del callback.items script = gametime.schedule(callback, repeat=True, min=32) self.timescripts.append(script) self.assertIsInstance(script, gametime.TimeScript)