Skip to content

Commit 9a96e07

Browse files
Fix Deque self-extension preserving original values
1 parent ebfa37c commit 9a96e07

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

‎diskcache/persistent.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ def extend(self, iterable):
409409
:param iterable: iterable of values
410410
411411
"""
412+
if iterable is self:
413+
iterable = tuple(iterable)
412414
for value in iterable:
413415
self._append(value)
414416

@@ -425,6 +427,8 @@ def extendleft(self, iterable):
425427
:param iterable: iterable of values
426428
427429
"""
430+
if iterable is self:
431+
iterable = tuple(iterable)
428432
for value in iterable:
429433
self._appendleft(value)
430434

‎tests/test_deque.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pickle
44
import shutil
55
import tempfile
6+
from collections import deque as memory_deque
67
from unittest import mock
78

89
import pytest
@@ -205,6 +206,36 @@ def test_extendleft(deque):
205206
assert deque == list(reversed(sequence))
206207

207208

209+
@pytest.mark.parametrize('method', ['extend', 'extendleft', '__iadd__'])
210+
@pytest.mark.parametrize('size', [0, 1, 3, 101])
211+
@pytest.mark.parametrize('maxlen', [None, 0, 1, 3, 101])
212+
def test_extend_self(deque, method, size, maxlen):
213+
if maxlen is not None:
214+
deque.maxlen = maxlen
215+
deque.extend(range(size))
216+
expected = memory_deque(range(size), maxlen=maxlen)
217+
original_size = len(expected)
218+
getattr(expected, method)(expected)
219+
220+
append_name = '_appendleft' if method == 'extendleft' else '_append'
221+
append = getattr(deque, append_name)
222+
calls = 0
223+
224+
def bounded_append(value):
225+
nonlocal calls
226+
calls += 1
227+
# Stop a regression before self-extension can grow without bound.
228+
assert calls <= original_size
229+
append(value)
230+
231+
with mock.patch.object(deque, append_name, bounded_append):
232+
result = getattr(deque, method)(deque)
233+
234+
assert list(deque) == list(expected)
235+
if method == '__iadd__':
236+
assert result is deque
237+
238+
208239
def test_pop(deque):
209240
sequence = list('abcde')
210241
deque.extend(sequence)

0 commit comments

Comments
 (0)