From 9a96e0726d08f5df324ec5a303ec7d577ed13ab0 Mon Sep 17 00:00:00 2001 From: Gonghan-Princess <268298391+Gonghan-Princess@users.noreply.github.com> Date: Fri, 11 Sep 2026 13:34:41 +0800 Subject: [PATCH] Fix Deque self-extension preserving original values --- diskcache/persistent.py | 4 ++++ tests/test_deque.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/diskcache/persistent.py b/diskcache/persistent.py index 522bb74..fa78a6e 100644 --- a/diskcache/persistent.py +++ b/diskcache/persistent.py @@ -409,6 +409,8 @@ def extend(self, iterable): :param iterable: iterable of values """ + if iterable is self: + iterable = tuple(iterable) for value in iterable: self._append(value) @@ -425,6 +427,8 @@ def extendleft(self, iterable): :param iterable: iterable of values """ + if iterable is self: + iterable = tuple(iterable) for value in iterable: self._appendleft(value) diff --git a/tests/test_deque.py b/tests/test_deque.py index f997a86..5a2a666 100644 --- a/tests/test_deque.py +++ b/tests/test_deque.py @@ -3,6 +3,7 @@ import pickle import shutil import tempfile +from collections import deque as memory_deque from unittest import mock import pytest @@ -205,6 +206,36 @@ def test_extendleft(deque): assert deque == list(reversed(sequence)) +@pytest.mark.parametrize('method', ['extend', 'extendleft', '__iadd__']) +@pytest.mark.parametrize('size', [0, 1, 3, 101]) +@pytest.mark.parametrize('maxlen', [None, 0, 1, 3, 101]) +def test_extend_self(deque, method, size, maxlen): + if maxlen is not None: + deque.maxlen = maxlen + deque.extend(range(size)) + expected = memory_deque(range(size), maxlen=maxlen) + original_size = len(expected) + getattr(expected, method)(expected) + + append_name = '_appendleft' if method == 'extendleft' else '_append' + append = getattr(deque, append_name) + calls = 0 + + def bounded_append(value): + nonlocal calls + calls += 1 + # Stop a regression before self-extension can grow without bound. + assert calls <= original_size + append(value) + + with mock.patch.object(deque, append_name, bounded_append): + result = getattr(deque, method)(deque) + + assert list(deque) == list(expected) + if method == '__iadd__': + assert result is deque + + def test_pop(deque): sequence = list('abcde') deque.extend(sequence)