diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 8962b02730..ef0c25fe52 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -71,6 +71,8 @@ class AbstractMemoryTests: m = None self.assertEqual(sys.getrefcount(b), oldrefcount) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_setitem_writable(self): if not self.rw_type: self.skipTest("no writable type to test") @@ -112,13 +114,11 @@ class AbstractMemoryTests: self.assertRaises(TypeError, setitem, "a", b"a") # Not implemented: multidimensional slices slices = (slice(0,1,1), slice(0,1,2)) - # TODO: RUSTPYTHON - # self.assertRaises(NotImplementedError, setitem, slices, b"a") + self.assertRaises(NotImplementedError, setitem, slices, b"a") # Trying to resize the memory object exc = ValueError if m.format == 'c' else TypeError - # TODO: RUSTPYTHON - # self.assertRaises(exc, setitem, 0, b"") - # self.assertRaises(exc, setitem, 0, b"ab") + self.assertRaises(exc, setitem, 0, b"") + self.assertRaises(exc, setitem, 0, b"ab") self.assertRaises(ValueError, setitem, slice(1,1), b"a") self.assertRaises(ValueError, setitem, slice(0,2), b"a") @@ -150,6 +150,8 @@ class AbstractMemoryTests: l = m.tolist() self.assertEqual(l, list(b"abcdef")) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_compare(self): # memoryviews can compare for equality with other objects # having the buffer interface. @@ -174,12 +176,11 @@ class AbstractMemoryTests: self.assertTrue("abcdef" != m) # Unordered comparisons - # TODO: RUSTPYTHON - # for c in (m, b"abcdef"): - # self.assertRaises(TypeError, lambda: m < c) - # self.assertRaises(TypeError, lambda: c <= m) - # self.assertRaises(TypeError, lambda: m >= c) - # self.assertRaises(TypeError, lambda: c > m) + for c in (m, b"abcdef"): + self.assertRaises(TypeError, lambda: m < c) + self.assertRaises(TypeError, lambda: c <= m) + self.assertRaises(TypeError, lambda: m >= c) + self.assertRaises(TypeError, lambda: c > m) def check_attributes_with_type(self, tp): m = self._view(tp(self._source)) @@ -272,12 +273,11 @@ class AbstractMemoryTests: with check: m.itemsize with check: m.ndim with check: m.readonly - # TODO: RUSTPYTHON - # with check: m.shape - # with check: m.strides - # with check: - # with m: - # pass + with check: m.shape + with check: m.strides + with check: + with m: + pass # str() and repr() still function self.assertIn("released memory", str(m)) self.assertIn("released memory", repr(m)) diff --git a/extra_tests/snippets/memoryview.py b/extra_tests/snippets/memoryview.py index a2f7f8b17d..121028d418 100644 --- a/extra_tests/snippets/memoryview.py +++ b/extra_tests/snippets/memoryview.py @@ -6,7 +6,7 @@ obj = b"abcde" a = memoryview(obj) assert a.obj == obj -# assert a[2:3] == b"c" +assert a[2:3] == b"c" assert hash(obj) == hash(a) diff --git a/vm/src/bytesinner.rs b/vm/src/bytesinner.rs index 7c92dad6be..1f1a068bfc 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -3,7 +3,6 @@ use itertools::Itertools; use num_bigint::BigInt; use num_traits::ToPrimitive; -use crate::anystr::{self, AnyStr, AnyStrContainer, AnyStrWrapper}; use crate::byteslike::try_bytes_like; use crate::function::{OptionalArg, OptionalOption}; use crate::obj::objbytearray::PyByteArray; @@ -21,6 +20,10 @@ use crate::pyobject::{ use crate::sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}; use crate::slots::PyComparisonOp; use crate::vm::VirtualMachine; +use crate::{ + anystr::{self, AnyStr, AnyStrContainer, AnyStrWrapper}, + obj::objtuple::PyTuple, +}; use rustpython_common::hash; #[derive(Debug, Default, Clone)] @@ -41,8 +44,9 @@ impl TryFromObject for PyBytesInner { } match_class!(match obj { + // TODO: generic way from &[PyObjectRef] l @ PyList => l.to_byte_inner(vm), - // TODO: PyTyple + t @ PyTuple => t.to_bytes_inner(vm), obj => { let iter = vm.get_method_or_type_error(obj.clone(), "__iter__", || { format!( diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index bce11b4079..aeeca65279 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -72,6 +72,7 @@ impl PyList { self.elements.write() } + // TODO: more generic way to do so pub(crate) fn to_byte_inner(&self, vm: &VirtualMachine) -> PyResult { let mut elements = Vec::::with_capacity(self.borrow_value().len()); for elem in self.borrow_value().iter() { diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index 1e7252c08a..57d16592fb 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -8,8 +8,8 @@ use crate::obj::objslice::PySliceRef; use crate::obj::objstr::PyStr; use crate::obj::objtype::PyTypeRef; use crate::pyobject::{ - IdProtocol, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, - PyThreadingConstraint, PyValue, TypeProtocol, + IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, + PyResult, PyThreadingConstraint, PyValue, TypeProtocol, }; use crate::sliceable::{convert_slice, saturate_range, wrap_index, SequenceIndex}; use crate::slots::{BufferProtocol, Comparable, Hashable, PyComparisonOp}; @@ -85,9 +85,11 @@ pub struct BufferOptions { pub len: usize, pub itemsize: usize, pub contiguous: bool, + pub format: String, // TODO: support multiple dimension array pub ndim: usize, - pub format: String, + pub shape: Vec, + pub strides: Vec, } impl Default for BufferOptions { @@ -97,8 +99,10 @@ impl Default for BufferOptions { len: 0, itemsize: 1, contiguous: true, - ndim: 1, format: "B".to_owned(), + ndim: 1, + shape: Vec::new(), + strides: Vec::new(), } } } @@ -209,12 +213,35 @@ impl PyMemoryView { self.try_not_released(vm).map(|_| self.options.ndim) } + // TODO + #[pyproperty] + fn shape(&self, vm: &VirtualMachine) -> PyResult { + self.try_not_released(vm) + .map(|_| (self.options.len,).into_pyobject(vm)) + } + + // TODO + #[pyproperty] + fn strides(&self, vm: &VirtualMachine) -> PyResult { + self.try_not_released(vm).map(|_| (0,).into_pyobject(vm)) + } + #[pyproperty] fn format(&self, vm: &VirtualMachine) -> PyResult { self.try_not_released(vm) .map(|_| PyStr::from(&self.options.format)) } + #[pymethod(magic)] + fn enter(zelf: PyRef, vm: &VirtualMachine) -> PyResult> { + zelf.try_not_released(vm).map(|_| zelf) + } + + #[pymethod(magic)] + fn exit(&self) { + self.release(); + } + // translate the slice index to memory index fn get_pos(&self, i: isize) -> Option { let len = self.options.len; diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 67e4d21494..18374b7a8b 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -1,18 +1,21 @@ use crossbeam_utils::atomic::AtomicCell; +use num_traits::ToPrimitive; use std::fmt; +use super::objint::PyIntRef; use super::objiter; use super::objtype::PyTypeRef; -use crate::function::OptionalArg; +use crate::common::hash::PyHash; use crate::pyobject::{ self, BorrowValue, Either, IdProtocol, IntoPyObject, PyArithmaticValue, PyClassImpl, - PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, + PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, + TypeProtocol, }; use crate::sequence::{self, SimpleSeq}; use crate::sliceable::PySliceableSequence; use crate::slots::{Comparable, Hashable, PyComparisonOp}; use crate::vm::{ReprGuard, VirtualMachine}; -use rustpython_common::hash::PyHash; +use crate::{bytesinner::PyBytesInner, function::OptionalArg}; /// tuple() -> empty tuple /// tuple(iterable) -> tuple initialized from iterable's items @@ -66,6 +69,25 @@ impl PyTuple { pub(crate) fn fast_getitem(&self, idx: usize) -> PyObjectRef { self.elements[idx].clone() } + + // TODO: more generic way to do so + pub(crate) fn to_bytes_inner(&self, vm: &VirtualMachine) -> PyResult { + let mut elements = Vec::::with_capacity(self.borrow_value().len()); + for elem in self.borrow_value().iter() { + let py_int = PyIntRef::try_from_object(vm, elem.clone()).map_err(|_| { + vm.new_type_error(format!( + "'{}' object cannot be interpreted as an integer", + elem.class().name + )) + })?; + let result = py_int + .borrow_value() + .to_u8() + .ok_or_else(|| vm.new_value_error("bytes must be in range (0, 256)".to_owned()))?; + elements.push(result); + } + Ok(elements.into()) + } } pub type PyTupleRef = PyRef;