Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ an Abstract Syntax Tree (AST):
- The Parser relies on `LALRPOP`, a Rust parser generator framework. The
LALRPOP definition of Python's grammar is in `parser/src/python.lalrpop`.
- More information on parsers and a tutorial can be found in the
[LALRPOP book](https://lalrpop.github.io/lalrpop/README.html).
[LALRPOP book](https://lalrpop.github.io/lalrpop/).
- AST: `ast/` implements in Rust the Python types and expressions
represented by the AST nodes.

Expand Down
8 changes: 0 additions & 8 deletions Lib/test/test_itertools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1169,8 +1169,6 @@ def test_product_issue_25021(self):
p.__setstate__((0, 0, 0x1000)) # will access tuple element 1 if not clamped
self.assertRaises(StopIteration, next, p)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_repeat(self):
self.assertEqual(list(repeat(object='a', times=3)), ['a', 'a', 'a'])
self.assertEqual(lzip(range(3),repeat('a')),
Expand All @@ -1197,8 +1195,6 @@ def test_repeat(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
self.pickletest(proto, repeat(object='a', times=10))

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_repeat_with_negative_times(self):
self.assertEqual(repr(repeat('a', -1)), "repeat('a', 0)")
self.assertEqual(repr(repeat('a', -2)), "repeat('a', 0)")
Expand Down Expand Up @@ -2181,15 +2177,11 @@ def test_tee(self):

class LengthTransparency(unittest.TestCase):

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_repeat(self):
self.assertEqual(operator.length_hint(repeat(None, 50)), 50)
self.assertEqual(operator.length_hint(repeat(None, 0)), 0)
self.assertEqual(operator.length_hint(repeat(None), 12), 12)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_repeat_with_negative_times(self):
self.assertEqual(operator.length_hint(repeat(None, -1)), 0)
self.assertEqual(operator.length_hint(repeat(None, -2)), 0)
Expand Down
4 changes: 0 additions & 4 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -1878,10 +1878,6 @@ def helper(self):
if hasattr(os, f):
self.check(getattr(os, f))

# TODO: RUSTPYTHON; io.FileIO(fd) should check if the fd passed is valid
if f == "fdopen":
# this is test_fdopen
helper = unittest.expectedFailure(helper)

return helper
for f in singles:
Expand Down
8 changes: 6 additions & 2 deletions vm/src/builtins/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ impl PySetInner {

PySetIterator {
dict: PyRc::clone(&self.content),
elements: self.content.keys(),
size_info: AtomicCell::new(set_size),
}
}
Expand Down Expand Up @@ -763,6 +764,7 @@ struct SetSizeInfo {
#[pyclass(module = false, name = "set_iterator")]
pub(crate) struct PySetIterator {
dict: PyRc<SetContentType>,
elements: Vec<PyObjectRef>,
size_info: AtomicCell<SetSizeInfo>,
}

Expand Down Expand Up @@ -796,8 +798,10 @@ impl PyIter for PySetIterator {
if let Some(set_size) = size_info.size {
if set_size == zelf.dict.len() {
let index = size_info.position;
let keys = zelf.dict.keys();
let item = keys.get(index).ok_or_else(|| vm.new_stop_iteration())?;
let item = zelf
.elements
.get(index)
.ok_or_else(|| vm.new_stop_iteration())?;
size_info.position += 1;
zelf.size_info.store(size_info);
return Ok(item.clone());
Expand Down
9 changes: 9 additions & 0 deletions vm/src/stdlib/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ cfg_if::cfg_if! {
type Offset = i64;
}
}

#[cfg(unix)]
use crate::stdlib::os::{errno_err, PathOrFd};
use crate::VirtualMachine;
use crate::{PyObjectRef, PyResult, TryFromObject};
pub(crate) use _io::io_open as open;
Expand Down Expand Up @@ -3571,6 +3574,12 @@ mod _io {
}
}

// check file descriptor validity
#[cfg(unix)]
if let Ok(PathOrFd::Fd(fd)) = PathOrFd::try_from_object(vm, file.clone()) {
nix::fcntl::fcntl(fd, nix::fcntl::F_GETFD).map_err(|_| errno_err(vm))?;
}

// Construct a FileIO (subclass of RawIOBase)
// This is subsequently consumed by a Buffered Class.
let file_io_class = {
Expand Down
67 changes: 54 additions & 13 deletions vm/src/stdlib/itertools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ mod decl {
#[derive(Debug)]
struct PyItertoolsRepeat {
object: PyObjectRef,
times: Option<PyRwLock<BigInt>>,
times: Option<PyRwLock<usize>>,
}

impl PyValue for PyItertoolsRepeat {
Expand All @@ -269,40 +269,81 @@ mod decl {
}
}

#[pyimpl(with(PyIter))]
#[derive(FromArgs)]
struct PyRepeatNewArgs {
#[pyarg(any)]
object: PyObjectRef,
#[pyarg(any, optional)]
times: OptionalArg<PyIntRef>,
}

#[pyimpl(with(PyIter), flags(BASETYPE))]
impl PyItertoolsRepeat {
#[pyslot]
fn tp_new(
cls: PyTypeRef,
object: PyObjectRef,
times: OptionalArg<PyIntRef>,
PyRepeatNewArgs { object, times }: PyRepeatNewArgs,
vm: &VirtualMachine,
) -> PyResult<PyRef<Self>> {
let times = times
.into_option()
.map(|int| PyRwLock::new(int.as_bigint().clone()));

let times = match times.into_option() {
Some(int) => {
let val = int.as_bigint();
if *val > BigInt::from(isize::MAX) {
return Err(vm.new_overflow_error("Cannot fit in isize.".to_owned()));
}
// times always >= 0.
Some(PyRwLock::new(val.to_usize().unwrap_or(0)))
}
None => None,
};
PyItertoolsRepeat { object, times }.into_ref_with_type(vm, cls)
}

#[pymethod(name = "__length_hint__")]
fn length_hint(&self, vm: &VirtualMachine) -> PyObjectRef {
fn length_hint(&self, vm: &VirtualMachine) -> PyResult {
match self.times {
Some(ref times) => vm.ctx.new_int(times.read().clone()),
None => vm.ctx.new_int(0),
Some(ref times) => Ok(vm.ctx.new_int(*times.read())),
// Return TypeError, length_hint picks this up and returns the default.
None => Err(vm.new_type_error("length of unsized object.".to_owned())),
}
}

#[pymethod(magic)]
fn reduce(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
let cls = zelf.clone_class().into_pyobject(vm);
Ok(match zelf.times {
Some(ref times) => vm.ctx.new_tuple(vec![
cls,
vm.ctx.new_tuple(vec![
zelf.object.clone(),
vm.ctx.new_int(*times.read()).into_pyobject(vm),
]),
]),
None => vm
.ctx
.new_tuple(vec![cls, vm.ctx.new_tuple(vec![zelf.object.clone()])]),
})
}

#[pymethod(magic)]
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
let mut fmt = format!("{}", vm.to_repr(&self.object)?);
if let Some(ref times) = self.times {
fmt.push_str(&format!(", {}", times.read()));
}
Ok(format!("repeat({})", fmt))
}
}

impl PyIter for PyItertoolsRepeat {
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
if let Some(ref times) = zelf.times {
let mut times = times.write();
if !times.is_positive() {
if *times == 0 {
return Err(vm.new_stop_iteration());
}
*times -= 1;
}

Ok(zelf.object.clone())
}
}
Expand Down
2 changes: 1 addition & 1 deletion vm/src/stdlib/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl TryFromObject for PyPathLike {
}
}

enum PathOrFd {
pub(crate) enum PathOrFd {
Path(PyPathLike),
Fd(i32),
}
Expand Down