From aa580231e151550ce252ec4dcfdd6a5cba83bdc4 Mon Sep 17 00:00:00 2001 From: Muneeb Sheikh Date: Sun, 11 Oct 2026 13:11:50 -0400 Subject: [PATCH] Reject negative deque limits before changing persisted data --- diskcache/persistent.py | 9 +++++++++ tests/test_deque.py | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/diskcache/persistent.py b/diskcache/persistent.py index 522bb74..a51df9d 100644 --- a/diskcache/persistent.py +++ b/diskcache/persistent.py @@ -83,8 +83,11 @@ def __init__(self, iterable=(), directory=None, maxlen=None): :param iterable: iterable of items to append to deque :param directory: deque directory (default None) + :raises ValueError: if maxlen is negative """ + if maxlen is not None and maxlen < 0: + raise ValueError('maxlen must be non-negative') self._cache = Cache(directory, eviction_policy='none') self._maxlen = float('inf') if maxlen is None else maxlen self._extend(iterable) @@ -107,8 +110,11 @@ def fromcache(cls, cache, iterable=(), maxlen=None): :param Cache cache: cache to use :param iterable: iterable of items :return: initialized Deque + :raises ValueError: if maxlen is negative """ + if maxlen is not None and maxlen < 0: + raise ValueError('maxlen must be non-negative') # pylint: disable=no-member,protected-access self = cls.__new__(cls) self._cache = cache @@ -144,8 +150,11 @@ def maxlen(self, value): ['c', 'd', 'e'] :param value: max length + :raises ValueError: if value is negative """ + if value is not None and value < 0: + raise ValueError('maxlen must be non-negative') self._maxlen = value with self._cache.transact(retry=True): while len(self._cache) > self._maxlen: diff --git a/tests/test_deque.py b/tests/test_deque.py index f997a86..e49c506 100644 --- a/tests/test_deque.py +++ b/tests/test_deque.py @@ -50,6 +50,32 @@ def test_init(): rmdir(directory) +@pytest.mark.parametrize('factory', ['constructor', 'fromcache']) +def test_negative_maxlen_does_not_change_existing_data(tmp_path, factory): + deque = dc.Deque([1, 2, 3], directory=str(tmp_path / 'deque')) + try: + with pytest.raises(ValueError, match='maxlen'): + if factory == 'constructor': + dc.Deque([4], directory=deque.directory, maxlen=-1) + else: + dc.Deque.fromcache(deque.cache, [4], maxlen=-1) + + assert list(deque) == [1, 2, 3] + finally: + deque.cache.close() + + +def test_negative_maxlen_assignment_keeps_limit_and_data(deque): + deque.maxlen = 3 + deque.extend([1, 2, 3]) + + with pytest.raises(ValueError, match='maxlen'): + deque.maxlen = -1 + + assert deque.maxlen == 3 + assert list(deque) == [1, 2, 3] + + def test_getsetdel(deque): sequence = list('abcde') assert len(deque) == 0