Add support for saving maxlen of deque in Attributes

This commit is contained in:
Griatch 2023-03-06 20:12:49 +01:00
parent 82a71062f9
commit ccf173f2fa
2 changed files with 24 additions and 8 deletions

View file

@ -30,7 +30,6 @@ except ImportError:
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.utils.safestring import SafeString from django.utils.safestring import SafeString
from evennia.utils import logger from evennia.utils import logger
from evennia.utils.utils import is_iter, to_bytes, uses_database from evennia.utils.utils import is_iter, to_bytes, uses_database
@ -209,6 +208,8 @@ class _SaverMutable:
dat = _SaverDefaultDict(item.default_factory, _parent=parent) dat = _SaverDefaultDict(item.default_factory, _parent=parent)
dat._data.update((key, process_tree(val, dat)) for key, val in item.items()) dat._data.update((key, process_tree(val, dat)) for key, val in item.items())
return dat return dat
elif dtype == deque:
dat = _SaverDeque(_parent=parent, maxlen=item.maxlen)
elif dtype == set: elif dtype == set:
dat = _SaverSet(_parent=parent) dat = _SaverSet(_parent=parent)
dat._data.update(process_tree(val, dat) for val in item) dat._data.update(process_tree(val, dat) for val in item)
@ -431,9 +432,9 @@ class _SaverDeque(_SaverMutable):
A deque that can be saved and operated on. A deque that can be saved and operated on.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, maxlen=None, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._data = deque() self._data = deque((), maxlen=maxlen)
@_save @_save
def append(self, *args, **kwargs): def append(self, *args, **kwargs):
@ -513,6 +514,8 @@ def deserialize(obj):
return defaultdict( return defaultdict(
obj.default_factory, {_iter(key): _iter(val) for key, val in obj.items()} obj.default_factory, {_iter(key): _iter(val) for key, val in obj.items()}
) )
elif tname in ("_SaverDeque", deque):
return deque((_iter(val) for val in obj), maxlen=obj.maxlen)
elif tname in _DESERIALIZE_MAPPING: elif tname in _DESERIALIZE_MAPPING:
return _DESERIALIZE_MAPPING[tname](_iter(val) for val in obj) return _DESERIALIZE_MAPPING[tname](_iter(val) for val in obj)
elif is_iter(obj): elif is_iter(obj):
@ -680,6 +683,8 @@ def to_pickle(data):
item.default_factory, item.default_factory,
((process_item(key), process_item(val)) for key, val in item.items()), ((process_item(key), process_item(val)) for key, val in item.items()),
) )
elif dtype in (deque, _SaverDeque):
return deque((process_item(val) for val in item), maxlen=item.maxlen)
elif dtype in (set, _SaverSet): elif dtype in (set, _SaverSet):
return set(process_item(val) for val in item) return set(process_item(val) for val in item)
elif dtype in (OrderedDict, _SaverOrderedDict): elif dtype in (OrderedDict, _SaverOrderedDict):
@ -776,7 +781,7 @@ def from_pickle(data, db_obj=None):
elif dtype == OrderedDict: elif dtype == OrderedDict:
return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) return OrderedDict((process_item(key), process_item(val)) for key, val in item.items())
elif dtype == deque: elif dtype == deque:
return deque(process_item(val) for val in item) return deque((process_item(val) for val in item), maxlen=item.maxlen)
elif hasattr(item, "__iter__"): elif hasattr(item, "__iter__"):
try: try:
# we try to conserve the iterable class, if not convert to dict # we try to conserve the iterable class, if not convert to dict
@ -849,7 +854,7 @@ def from_pickle(data, db_obj=None):
) )
return dat return dat
elif dtype == deque: elif dtype == deque:
dat = _SaverDeque(_parent=parent) dat = _SaverDeque(_parent=parent, maxlen=item.maxlen)
dat._data.extend(process_item(val) for val in item) dat._data.extend(process_item(val) for val in item)
return dat return dat
elif hasattr(item, "__iter__"): elif hasattr(item, "__iter__"):
@ -920,7 +925,7 @@ def from_pickle(data, db_obj=None):
) )
return dat return dat
elif dtype == deque: elif dtype == deque:
dat = _SaverDeque(_db_obj=db_obj) dat = _SaverDeque(_db_obj=db_obj, maxlen=data.maxlen)
dat._data.extend(process_item(val) for val in data) dat._data.extend(process_item(val) for val in data)
return dat return dat
elif hasattr(data, "__iter__"): elif hasattr(data, "__iter__"):

View file

@ -5,10 +5,9 @@ Tests for dbserialize module
from collections import defaultdict, deque from collections import defaultdict, deque
from django.test import TestCase from django.test import TestCase
from parameterized import parameterized
from evennia.objects.objects import DefaultObject from evennia.objects.objects import DefaultObject
from evennia.utils import dbserialize from evennia.utils import dbserialize
from parameterized import parameterized
class TestDbSerialize(TestCase): class TestDbSerialize(TestCase):
@ -116,6 +115,18 @@ class TestDbSerialize(TestCase):
self.obj.db.test |= {"b": [5, 6]} self.obj.db.test |= {"b": [5, 6]}
self.assertEqual(self.obj.db.test, {"a": [1, 2, 3], "b": [5, 6]}) self.assertEqual(self.obj.db.test, {"a": [1, 2, 3], "b": [5, 6]})
def test_deque_with_maxlen(self):
_dd = deque((), maxlen=1)
_dd.append(1)
_dd.append(2)
self.assertEqual(list(_dd), [2])
dd = deque((), maxlen=1)
self.obj.db.test = dd
self.obj.db.test.append(1)
self.obj.db.test.append(2)
self.assertEqual(list(self.obj.db.test), [2])
class _InvalidContainer: class _InvalidContainer:
"""Container not saveable in Attribute (if obj is dbobj, it 'hides' it)""" """Container not saveable in Attribute (if obj is dbobj, it 'hides' it)"""