diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py index fe5d9b27d..68d751b9f 100644 --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -646,8 +646,6 @@ class TestBasic(unittest.TestCase): self.assertEqual(id(e[-1]), id(e)) self.assertEqual(e.maxlen, d.maxlen) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_iterator_pickle(self): orig = deque(range(200)) data = [i*1.01 for i in orig] @@ -729,8 +727,6 @@ class TestBasic(unittest.TestCase): for s in ('abcd', range(2000)): self.assertEqual(list(reversed(deque(s))), list(reversed(s))) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_reversed_new(self): klass = type(reversed(deque())) for s in ('abcd', range(2000)): diff --git a/extra_tests/snippets/deque.py b/extra_tests/snippets/deque.py new file mode 100644 index 000000000..3fd8de9cf --- /dev/null +++ b/extra_tests/snippets/deque.py @@ -0,0 +1,85 @@ +from collections import deque + + +def test_deque_iterator__new__(): + klass = type(iter(deque())) + s = 'abcd' + d = klass(deque(s)) + assert (list(d) == list(s)) + + +test_deque_iterator__new__() + + +def test_deque_iterator__new__positional_index(): + klass = type(iter(deque())) + + # index between 0 and len + for s in ('abcd', range(2000)): + for i in range(len(s)): + d = klass(deque(s), i) + assert (list(d) == list(s)[i:]) + + # negative index + for s in ('abcd', range(2000)): + for i in range(-1000, 0): + d = klass(deque(s), i) + assert (list(d) == list(s)) + + # index ge len + for s in ('abcd', range(2000)): + for i in range(len(s), 4000): + d = klass(deque(s), i) + assert (list(d) == list()) + + +test_deque_iterator__new__positional_index() + + +def test_deque_iterator__new__not_using_keyword_index(): + klass = type(iter(deque())) + + for s in ('abcd', range(2000)): + for i in range(-1000, 4000): + d = klass(deque(s), index=i) + assert (list(d) == list(s)) + + +test_deque_iterator__new__not_using_keyword_index() + + +def test_deque_reverse_iterator__new__positional_index(): + klass = type(reversed(deque())) + + # index between 0 and len + for s in ('abcd', range(2000)): + for i in range(len(s)): + d = klass(deque(s), i) + assert (list(d) == list(reversed(s))[i:]) + + # negative index + for s in ('abcd', range(2000)): + for i in range(-1000, 0): + d = klass(deque(s), i) + assert (list(d) == list(reversed(s))) + + # index ge len + for s in ('abcd', range(2000)): + for i in range(len(s), 4000): + d = klass(deque(s), i) + assert (list(d) == list()) + + +test_deque_reverse_iterator__new__positional_index() + + +def test_deque_reverse_iterator__new__not_using_keyword_index(): + klass = type(reversed(deque())) + + for s in ('abcd', range(2000)): + for i in range(-1000, 4000): + d = klass(deque(s), index=i) + assert (list(d) == list(reversed(s))) + + +test_deque_reverse_iterator__new__not_using_keyword_index() diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index f42e64d8f..801b34d71 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -3,7 +3,7 @@ pub(crate) use _collections::make_module; #[pymodule] mod _collections { use crate::common::lock::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; - use crate::function::{FuncArgs, OptionalArg}; + use crate::function::{FuncArgs, KwArgs, OptionalArg}; use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable}; use crate::vm::ReprGuard; use crate::VirtualMachine; @@ -361,15 +361,14 @@ mod _collections { } #[pymethod(magic)] - fn reversed(zelf: PyRef, vm: &VirtualMachine) -> PyResult { + fn reversed(zelf: PyRef) -> PyResult { let length = zelf.len(); Ok(PyReverseDequeIterator { position: AtomicCell::new(length), status: AtomicCell::new(if length > 0 { Active } else { Exhausted }), length, deque: zelf, - } - .into_object(vm)) + }) } #[pymethod] @@ -581,6 +580,15 @@ mod _collections { } } + #[derive(FromArgs)] + struct DequeIterArgs { + #[pyarg(positional)] + deque: PyDequeRef, + + #[pyarg(positional, optional)] + index: OptionalArg, + } + #[pyimpl(with(PyIter))] impl PyDequeIterator { pub(crate) fn new(deque: PyDequeRef) -> Self { @@ -592,6 +600,26 @@ mod _collections { } } + #[pyslot] + fn tp_new( + cls: PyTypeRef, + DequeIterArgs { deque, index }: DequeIterArgs, + _kwargs: KwArgs, + vm: &VirtualMachine, + ) -> PyResult> { + let len = deque.len(); + let iter = PyDequeIterator::new(deque); + if let OptionalArg::Present(index) = index { + let index = max(index, 0) as usize; + iter.position.store(min(index, len)); + + if len.le(&index) { + iter.status.store(Exhausted); + } + } + iter.into_ref_with_type(vm, cls) + } + #[pymethod(magic)] fn length_hint(&self) -> usize { match self.status.load() { @@ -663,6 +691,25 @@ mod _collections { } } + #[pyslot] + fn tp_new( + cls: PyTypeRef, + DequeIterArgs { deque, index }: DequeIterArgs, + _kwargs: KwArgs, + vm: &VirtualMachine, + ) -> PyResult> { + let len = deque.len(); + let iter = PyDeque::reversed(deque)?; + if let OptionalArg::Present(index) = index { + let index = max(index, 0) as usize; + if len.le(&index) { + iter.status.store(Exhausted); + } + iter.position.store(len.saturating_sub(index)); + } + iter.into_ref_with_type(vm, cls) + } + #[pymethod(magic)] fn reduce( zelf: PyRef,