diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 09b44c9ca..b5a2a89d8 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -897,7 +897,6 @@ class MmapTests(unittest.TestCase): match = closed_mmap_repr_pat.match(repr(mm)) self.assertIsNotNone(match) - @unittest.expectedFailure # TODO: RUSTPYTHON @unittest.skipUnless(hasattr(mmap.mmap, 'madvise'), 'needs madvise') def test_madvise(self): size = 2 * PAGESIZE @@ -1039,7 +1038,6 @@ class MmapTests(unittest.TestCase): self.assertEqual(m1[:data_length], data) self.assertEqual(m2[:data_length], data) - @unittest.expectedFailure # TODO: RUSTPYTHON def test_mmap_closed_by_int_scenarios(self): """ gh-103987: Test that mmap objects raise ValueError diff --git a/crates/stdlib/src/fcntl.rs b/crates/stdlib/src/fcntl.rs index a6dfdeb63..f04304de0 100644 --- a/crates/stdlib/src/fcntl.rs +++ b/crates/stdlib/src/fcntl.rs @@ -8,9 +8,8 @@ mod fcntl { use crate::vm::{ PyResult, VirtualMachine, - builtins::PyIntRef, convert::ToPyException, - function::{ArgMemoryBuffer, ArgStrOrBytesLike, Either, OptionalArg}, + function::{ArgIndex, ArgMemoryBuffer, ArgStrOrBytesLike, Either, OptionalArg}, stdlib::_io, }; use rustpython_host_env::io::is_interrupted_error; @@ -86,7 +85,7 @@ mod fcntl { #[derive(FromArgs)] struct FcntlArg { #[pyarg(positional, default = 0)] - arg: Either, + arg: Either, } #[pyfunction] @@ -114,7 +113,7 @@ mod fcntl { )?; return Ok(vm.ctx.new_bytes(buf[..arg_len].to_vec()).into()); } - Either::B(i) => i.as_u32_mask(), + Either::B(i) => i.as_ref().as_u32_mask(), }; let ret = retry_on_eintr( vm, @@ -213,9 +212,9 @@ mod fcntl { #[derive(FromArgs)] struct LockfArgs { #[pyarg(positional, default = 0)] - len: PyIntRef, + len: ArgIndex, #[pyarg(positional, default = 0)] - start: PyIntRef, + start: ArgIndex, #[pyarg(positional, default)] whence: i32, } @@ -229,8 +228,8 @@ mod fcntl { LockfArgs { len, start, whence }: LockfArgs, vm: &VirtualMachine, ) -> PyResult { - let start = start.try_to_primitive(vm)?; - let len = len.try_to_primitive(vm)?; + let start = start.as_ref().try_to_primitive(vm)?; + let len = len.as_ref().try_to_primitive(vm)?; // F_LOCK and F_TLOCK differ in exactly this: the first one waits. let ret = retry_on_eintr( vm, diff --git a/crates/stdlib/src/grp.rs b/crates/stdlib/src/grp.rs index 5e73f5648..39e5285f6 100644 --- a/crates/stdlib/src/grp.rs +++ b/crates/stdlib/src/grp.rs @@ -5,9 +5,10 @@ pub(crate) use grp::module_def; mod grp { use crate::vm::{ PyObjectRef, PyResult, VirtualMachine, - builtins::{PyIntRef, PyListRef, PyUtf8StrRef}, + builtins::{PyListRef, PyUtf8StrRef}, convert::{IntoPyException, ToPyObject}, exceptions, + function::ArgIndex, types::PyStructSequence, }; use core::hint::cold_path; @@ -44,12 +45,12 @@ mod grp { #[derive(FromArgs)] struct GetGrGidArgs { #[pyarg(any)] - id: PyIntRef, + id: ArgIndex, } #[pyfunction] fn getgrgid(id: GetGrGidArgs, vm: &VirtualMachine) -> PyResult { - let gid = id.id; + let gid = id.id.into_int_ref(); let gr_gid = gid.as_bigint(); let gid = host_grp::gid_t::try_from(gr_gid).ok(); let group = gid diff --git a/crates/stdlib/src/mmap.rs b/crates/stdlib/src/mmap.rs index 317176c45..c33c21fcd 100644 --- a/crates/stdlib/src/mmap.rs +++ b/crates/stdlib/src/mmap.rs @@ -14,7 +14,7 @@ mod mmap { builtins::{PyBytes, PyBytesRef, PyInt, PyIntRef, PyType, PyTypeRef}, byte::{bytes_from_object, value_from_object}, convert::ToPyException, - function::ArgBytesLike, + function::{ArgBytesLike, ArgIndex}, protocol::{ BufferDescriptor, BufferMethods, PyBuffer, PyMappingMethods, PySequenceMethods, }, @@ -330,9 +330,9 @@ mod mmap { option: core::ffi::c_int, // None means 0. #[pyarg(positional, default, py_default = "0")] - start: Option, + start: Option, #[pyarg(positional, optional)] - length: Option, + length: Option, } #[cfg(all(unix, not(target_os = "redox")))] @@ -345,7 +345,8 @@ mod mmap { let start = self .start .map(|s| { - s.try_to_primitive::(vm) + s.as_ref() + .try_to_primitive::(vm) .ok() .filter(|s| *s < len) .ok_or_else(|| vm.new_value_error("madvise start out of bounds")) @@ -355,7 +356,8 @@ mod mmap { let length = self .length .map(|s| { - s.try_to_primitive::(vm) + s.as_ref() + .try_to_primitive::(vm) .map_err(|_| vm.new_value_error("madvise length invalid")) }) .transpose()? @@ -920,9 +922,9 @@ mod mmap { #[pymethod(name = "move")] fn move_( zelf: &Py, - dest: PyIntRef, - src: PyIntRef, - count: PyIntRef, + dest: ArgIndex, + src: ArgIndex, + count: ArgIndex, vm: &VirtualMachine, ) -> PyResult<()> { fn args( @@ -948,7 +950,7 @@ mod mmap { } let size = zelf.__len__(); - let (dest, src, cnt) = args(&dest, &src, &count, size, vm) + let (dest, src, cnt) = args(dest.as_ref(), src.as_ref(), count.as_ref(), size, vm) .ok_or_else(|| vm.new_value_error("source, destination, or count out of range"))?; let dest_end = dest + cnt; diff --git a/crates/stdlib/src/resource.rs b/crates/stdlib/src/resource.rs index 0e2a777e6..0750a3bf1 100644 --- a/crates/stdlib/src/resource.rs +++ b/crates/stdlib/src/resource.rs @@ -6,8 +6,9 @@ pub(crate) use resource::module_def; mod resource { use crate::vm::{ Py, PyObject, PyObjectRef, PyResult, TryFromBorrowedObject, VirtualMachine, - builtins::{PyInt, PyIntRef}, + builtins::PyInt, convert::{ToPyException, ToPyObject}, + function::ArgIndex, types::PyStructSequence, }; use num_traits::Signed; @@ -185,8 +186,8 @@ mod resource { } #[pyfunction] - fn getrlimit(resource: PyIntRef, vm: &VirtualMachine) -> PyResult { - let resource = py2rlim(&resource, vm)?; + fn getrlimit(resource: ArgIndex, vm: &VirtualMachine) -> PyResult { + let resource = py2rlim(resource.as_ref(), vm)?; if resource >= RLIM_NLIMITS as host_resource::rlim_t { return Err(vm.new_value_error("invalid resource specified")); @@ -197,8 +198,8 @@ mod resource { } #[pyfunction] - fn setrlimit(resource: PyIntRef, limits: Limits, vm: &VirtualMachine) -> PyResult<()> { - let resource = py2rlim(&resource, vm)?; + fn setrlimit(resource: ArgIndex, limits: Limits, vm: &VirtualMachine) -> PyResult<()> { + let resource = py2rlim(resource.as_ref(), vm)?; if resource >= RLIM_NLIMITS as host_resource::rlim_t { return Err(vm.new_value_error("invalid resource specified")); diff --git a/crates/vm/src/anystr.rs b/crates/vm/src/anystr.rs index f1ea7d735..b9ce61250 100644 --- a/crates/vm/src/anystr.rs +++ b/crates/vm/src/anystr.rs @@ -5,9 +5,9 @@ use rustpython_unicode::case; use crate::{ AsObject, Py, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, - builtins::{PyInt, PyIntRef, PyTuple}, + builtins::{PyInt, PyTuple}, convert::TryFromBorrowedObject, - function::PySsize, + function::{ArgIndex, PySsize}, }; #[derive(FromArgs)] @@ -41,17 +41,17 @@ pub(crate) struct StartsEndsWithArgs { #[pyarg(positional)] affix: PyObjectRef, #[pyarg(positional, default)] - start: Option, + start: Option, #[pyarg(positional, default)] - end: Option, + end: Option, } impl StartsEndsWithArgs { pub(crate) fn get_value(self, len: usize) -> (PyObjectRef, Option>) { let range = if self.start.is_some() || self.end.is_some() { Some(adjust_indices( - self.start.as_deref(), - self.end.as_deref(), + self.start.as_ref().map(AsRef::as_ref), + self.end.as_ref().map(AsRef::as_ref), len, )) } else { diff --git a/crates/vm/src/builtins/enumerate.rs b/crates/vm/src/builtins/enumerate.rs index 76ee3cca2..f7a3b8d25 100644 --- a/crates/vm/src/builtins/enumerate.rs +++ b/crates/vm/src/builtins/enumerate.rs @@ -1,11 +1,12 @@ use super::{ - IterStatus, PositionIterInternal, PyGenericAlias, PyIntRef, PyTupleRef, PyType, PyTypeRef, + IterStatus, PositionIterInternal, PyGenericAlias, PyTupleRef, PyType, PyTypeRef, iter::builtins_reversed, locked_rev_next, }; use crate::common::lock::{PyMutex, PyRwLock}; use crate::{ AsObject, Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, class::PyClassImpl, + function::ArgIndex, protocol::{PyIter, PyIterReturn}, raise_if_stop, types::{Constructor, IterNext, Iterable, SelfIter}, @@ -56,7 +57,7 @@ pub struct EnumerateArgs { #[pyarg(any)] iterable: PyIter, #[pyarg(any, default = 0)] - start: PyIntRef, + start: ArgIndex, } impl Constructor for PyEnumerate { @@ -67,6 +68,7 @@ impl Constructor for PyEnumerate { Self::Args { iterable, start }: Self::Args, _vm: &VirtualMachine, ) -> PyResult { + let start = start.into_int_ref(); let counter = match start.as_bigint().to_usize() { Some(n) => Counter::Small(n), None => Counter::Big(start.as_bigint().clone()), diff --git a/crates/vm/src/builtins/str.rs b/crates/vm/src/builtins/str.rs index fa4e905cd..91f99b22c 100644 --- a/crates/vm/src/builtins/str.rs +++ b/crates/vm/src/builtins/str.rs @@ -1,6 +1,6 @@ use super::{ PositionIterInternal, PyBytesRef, PyDict, PyList, PyTuple, PyTupleRef, PyType, PyTypeRef, - int::{PyInt, PyIntRef}, + int::PyInt, iter::{IterStatus, builtins_iter}, }; use crate::{ @@ -17,7 +17,7 @@ use crate::{ }, convert::{ToPyException, ToPyObject, ToPyResult}, format::{format, format_map}, - function::{ArgIterable, FuncArgs, OptionalArg, PyComparisonValue, PySsize}, + function::{ArgIndex, ArgIterable, FuncArgs, OptionalArg, PyComparisonValue, PySsize}, intern::PyInterned, object::{MaybeTraverse, Traverse, TraverseFn}, protocol::{ @@ -1871,14 +1871,18 @@ pub(crate) struct FindArgs { #[pyarg(positional)] sub: PyStrRef, #[pyarg(positional, default)] - start: Option, + start: Option, #[pyarg(positional, default)] - end: Option, + end: Option, } impl FindArgs { fn get_value(self, len: usize) -> (PyStrRef, core::ops::Range) { - let range = adjust_indices(self.start.as_deref(), self.end.as_deref(), len); + let range = adjust_indices( + self.start.as_ref().map(AsRef::as_ref), + self.end.as_ref().map(AsRef::as_ref), + len, + ); (self.sub, range) } } diff --git a/crates/vm/src/bytes_inner.rs b/crates/vm/src/bytes_inner.rs index f38b4dbd4..ecda0a42c 100644 --- a/crates/vm/src/bytes_inner.rs +++ b/crates/vm/src/bytes_inner.rs @@ -10,7 +10,7 @@ use crate::{ cformat::cformat_bytes, common::wtf8::is_py_ascii_whitespace, common::{borrow::BorrowedValue, hash}, - function::{ArgIterable, Either, OptionalArg, PyComparisonValue}, + function::{ArgIndex, ArgIterable, Either, OptionalArg, PyComparisonValue}, literal::escape::Escape, protocol::{BufferFlags, PyBuffer}, sequence::{SequenceExt, SequenceMutExt}, @@ -315,9 +315,9 @@ pub struct ByteInnerFindOptions { #[pyarg(positional)] sub: ByteInnerSub, #[pyarg(positional, default)] - start: Option, + start: Option, #[pyarg(positional, default)] - end: Option, + end: Option, } impl ByteInnerFindOptions { @@ -327,7 +327,11 @@ impl ByteInnerFindOptions { vm: &VirtualMachine, ) -> PyResult<(Vec, core::ops::Range)> { let sub = self.sub.into_vec(vm)?; - let range = anystr::adjust_indices(self.start.as_deref(), self.end.as_deref(), len); + let range = anystr::adjust_indices( + self.start.as_ref().map(AsRef::as_ref), + self.end.as_ref().map(AsRef::as_ref), + len, + ); Ok((sub, range)) } } diff --git a/crates/vm/src/stdlib/_thread.rs b/crates/vm/src/stdlib/_thread.rs index 984a08655..7ac20af92 100644 --- a/crates/vm/src/stdlib/_thread.rs +++ b/crates/vm/src/stdlib/_thread.rs @@ -27,8 +27,8 @@ pub(crate) mod _thread { convert::ToPyException, frame::FrameObjectRef, function::{ - ArgCallable, ArgumentError, DefaultRepr, FromArgs, FuncArgs, KwArgs, NameExcInfo, - OptionalArg, Param, ParamKind, PosArgs, PySetterValue, TimeoutSeconds, + ArgCallable, ArgIndex, ArgumentError, DefaultRepr, FromArgs, FuncArgs, KwArgs, + NameExcInfo, OptionalArg, Param, ParamKind, PosArgs, PySetterValue, TimeoutSeconds, }, object::{Traverse, TraverseFn}, types::{Constructor, GetAttr, PyStructSequence, Representable, SetAttr}, @@ -847,7 +847,7 @@ pub(crate) mod _thread { #[derive(FromArgs)] struct StackSizeArgs { #[pyarg(positional, default = 0)] - size: PyIntRef, + size: ArgIndex, } #[pyfunction] @@ -855,7 +855,7 @@ pub(crate) mod _thread { const MIN_SIZE: usize = PY_OS_MIN_STACK_SIZE + SYSTEM_PAGE_SIZE; let StackSizeArgs { size } = args; - let Ok(size) = size.try_to_primitive(vm) else { + let Ok(size) = size.as_ref().try_to_primitive(vm) else { return Err(vm.new_value_error(format!("size must be at least {MIN_SIZE} bytes"))); }; diff --git a/crates/vm/src/stdlib/itertools.rs b/crates/vm/src/stdlib/itertools.rs index 371e3ee68..f016f486c 100644 --- a/crates/vm/src/stdlib/itertools.rs +++ b/crates/vm/src/stdlib/itertools.rs @@ -5,13 +5,11 @@ mod decl { use crate::{ AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, PyWeakRef, TryFromObject, VirtualMachine, - builtins::{ - PyGenericAlias, PyInt, PyIntRef, PyList, PyTuple, PyTupleRef, PyType, PyTypeRef, int, - }, + builtins::{PyGenericAlias, PyInt, PyList, PyTuple, PyTupleRef, PyType, PyTypeRef, int}, class::PyClassDef, common::lock::{PyMutex, PyRwLock, PyRwLockWriteGuard}, convert::ToPyObject, - function::{FuncArgs, NameIterables, PosArgs}, + function::{ArgIndex, FuncArgs, NameIterables, PosArgs}, protocol::{PyIter, PyIterReturn, PyNumber}, raise_if_stop, stdlib::sys, @@ -1329,7 +1327,7 @@ mod decl { #[pyarg(any)] iterable: PyObjectRef, #[pyarg(any)] - r: PyIntRef, + r: ArgIndex, } impl Constructor for PyItertoolsCombinations { @@ -1342,6 +1340,7 @@ mod decl { ) -> PyResult { let pool: Vec<_> = iterable.try_to_value(vm)?; + let r = r.into_int_ref(); let r = r.as_bigint(); if r.is_negative() { return Err(vm.new_value_error("r must be non-negative")); @@ -1454,6 +1453,7 @@ mod decl { vm: &VirtualMachine, ) -> PyResult { let pool: Vec<_> = iterable.try_to_value(vm)?; + let r = r.into_int_ref(); let r = r.as_bigint(); if r.is_negative() { return Err(vm.new_value_error("r must be non-negative")); @@ -1800,7 +1800,7 @@ mod decl { #[pyarg(any)] iterable: PyObjectRef, #[pyarg(any)] - n: PyIntRef, + n: ArgIndex, #[pyarg(named, default)] strict: bool, } @@ -1817,6 +1817,7 @@ mod decl { }: Self::Args, vm: &VirtualMachine, ) -> PyResult { + let n = n.into_int_ref(); let n = n.as_bigint(); if n.lt(&BigInt::one()) { return Err(vm.new_value_error("n must be at least one")); diff --git a/crates/vm/src/stdlib/pwd.rs b/crates/vm/src/stdlib/pwd.rs index bfa7eb034..90a37d6d3 100644 --- a/crates/vm/src/stdlib/pwd.rs +++ b/crates/vm/src/stdlib/pwd.rs @@ -5,11 +5,8 @@ pub(crate) use pwd::module_def; #[pymodule] mod pwd { use crate::{ - PyResult, VirtualMachine, - builtins::{PyIntRef, PyUtf8StrRef}, - convert::IntoPyException, - exceptions, - types::PyStructSequence, + PyResult, VirtualMachine, builtins::PyUtf8StrRef, convert::IntoPyException, exceptions, + function::ArgIndex, types::PyStructSequence, }; use core::hint::cold_path; use rustpython_host_env::pwd as host_pwd; @@ -68,7 +65,8 @@ mod pwd { } #[pyfunction] - fn getpwuid(uidobj: PyIntRef, vm: &VirtualMachine) -> PyResult { + fn getpwuid(uidobj: ArgIndex, vm: &VirtualMachine) -> PyResult { + let uidobj = uidobj.into_int_ref(); let uid_t = libc::uid_t::try_from(uidobj.as_bigint()).ok(); let user = uid_t .map(host_pwd::getpwuid) diff --git a/extra_tests/snippets/protocol_index_argument.py b/extra_tests/snippets/protocol_index_argument.py index c67a078ef..ada8be240 100644 --- a/extra_tests/snippets/protocol_index_argument.py +++ b/extra_tests/snippets/protocol_index_argument.py @@ -312,3 +312,65 @@ class HintIndex: with assert_raises(TypeError): operator.length_hint(HintIndex()) + + +# Arguments bound as `int` objects accept `__index__` as well. +assert "abcabc".find("a", Index(1)) == 3 +assert "abcabc".rfind("a", 0, Index(3)) == 0 +assert "abcabc".index("c", Index(3)) == 5 +assert "abcabc".rindex("a", Index(1), Index(4)) == 3 +assert "aaaaaa".count("a", Index(2), Index(-1)) == 3 +assert "abcdef".startswith("d", Index(3)) +assert "abcdef".endswith("c", 0, Index(3)) +assert b"abcabc".find(b"a", Index(1)) == 3 +assert b"abcabc".count(b"b", Index(2)) == 1 +assert b"abcdef".startswith(b"d", Index(3)) +assert bytearray(b"abcabc").rindex(b"a", 0, Index(3)) == 0 +assert bytearray(b"abcdef").endswith(b"c", 0, Index(3)) + +assert list(enumerate("ab", Index(3))) == [(3, "a"), (4, "b")] +assert list(enumerate("ab", start=Index(3))) == [(3, "a"), (4, "b")] + +import itertools + +assert list(itertools.combinations("abc", Index(2))) == [ + ("a", "b"), + ("a", "c"), + ("b", "c"), +] +assert list(itertools.combinations_with_replacement("ab", Index(2))) == [ + ("a", "a"), + ("a", "b"), + ("b", "b"), +] +assert list(itertools.batched("abcde", Index(2))) == [("a", "b"), ("c", "d"), ("e",)] + +assert _thread.stack_size(Index(0)) == 0 + +import mmap + +mapped = mmap.mmap(-1, 6) +mapped.write(b"abcdef") +mapped.move(Index(0), Index(3), Index(3)) +assert mapped[:] == b"defdef" +if hasattr(mapped, "madvise"): + mapped.madvise(mmap.MADV_NORMAL, Index(0), Index(6)) + +if sys.platform != "win32": + import fcntl + import grp + import pwd + import resource + import tempfile + + assert pwd.getpwuid(Index(0)).pw_uid == 0 + assert grp.getgrgid(Index(0)).gr_gid == 0 + + nofile = resource.getrlimit(resource.RLIMIT_NOFILE) + assert resource.getrlimit(Index(resource.RLIMIT_NOFILE)) == nofile + resource.setrlimit(Index(resource.RLIMIT_NOFILE), nofile) + + with tempfile.TemporaryFile() as f: + assert fcntl.fcntl(f, fcntl.F_SETFD, Index(fcntl.FD_CLOEXEC)) == 0 + assert fcntl.fcntl(f, fcntl.F_GETFD) == fcntl.FD_CLOEXEC + fcntl.lockf(f, fcntl.LOCK_SH | fcntl.LOCK_NB, Index(0), Index(0))