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
9 changes: 5 additions & 4 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ def test_closefd_attr(self):
file = self.open(f.fileno(), "r", encoding="utf-8", closefd=False)
self.assertEqual(file.buffer.raw.closefd, False)

@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON; cyclic GC not supported, causes file locking')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_garbage_collection(self):
# FileIO objects are collected, and collecting them flushes
Expand Down Expand Up @@ -1795,6 +1796,7 @@ def test_misbehaved_io_read(self):
# checking this is not so easy.
self.assertRaises(OSError, bufio.read, 10)

@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON; cyclic GC not supported, causes file locking')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_garbage_collection(self):
# C BufferedReader objects are collected.
Expand Down Expand Up @@ -2166,6 +2168,7 @@ def test_initialization(self):
self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1)
self.assertRaises(ValueError, bufio.write, b"def")

@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON; cyclic GC not supported, causes file locking')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_garbage_collection(self):
# C BufferedWriter objects are collected, and collecting them flushes
Expand Down Expand Up @@ -2677,6 +2680,7 @@ def test_interleaved_readline_write(self):
class CBufferedRandomTest(BufferedRandomTest, SizeofTest):
tp = io.BufferedRandom

@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON; cyclic GC not supported, causes file locking')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_garbage_collection(self):
CBufferedReaderTest.test_garbage_collection(self)
Expand Down Expand Up @@ -4122,6 +4126,7 @@ def test_initialization(self):
t = self.TextIOWrapper.__new__(self.TextIOWrapper)
self.assertRaises(Exception, repr, t)

@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON; cyclic GC not supported, causes file locking')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_garbage_collection(self):
# C TextIOWrapper objects are collected, and collecting them flushes
Expand Down Expand Up @@ -4271,10 +4276,6 @@ def test_reconfigure_write_through(self):
def test_repr(self):
return super().test_repr()

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_telling(self):
return super().test_telling()

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_uninitialized(self):
return super().test_uninitialized()
Expand Down
143 changes: 135 additions & 8 deletions crates/vm/src/stdlib/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1753,11 +1753,23 @@ mod _io {
}

#[pyclass(
with(Constructor, BufferedMixin, BufferedReadable),
with(Constructor, BufferedMixin, BufferedReadable, Destructor),
flags(BASETYPE, HAS_DICT)
)]
impl BufferedReader {}

impl Destructor for BufferedReader {
fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
let _ = vm.call_method(zelf, "close", ());
Ok(())
}

#[cold]
fn del(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
unreachable!("slot_del is implemented")
}
}

impl DefaultConstructor for BufferedReader {}

#[pyclass]
Expand Down Expand Up @@ -1810,11 +1822,23 @@ mod _io {
}

#[pyclass(
with(Constructor, BufferedMixin, BufferedWritable),
with(Constructor, BufferedMixin, BufferedWritable, Destructor),
flags(BASETYPE, HAS_DICT)
)]
impl BufferedWriter {}

impl Destructor for BufferedWriter {
fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
let _ = vm.call_method(zelf, "close", ());
Ok(())
}

#[cold]
fn del(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
unreachable!("slot_del is implemented")
}
}

impl DefaultConstructor for BufferedWriter {}

#[pyattr]
Expand Down Expand Up @@ -1852,11 +1876,29 @@ mod _io {
}

#[pyclass(
with(Constructor, BufferedMixin, BufferedReadable, BufferedWritable),
with(
Constructor,
BufferedMixin,
BufferedReadable,
BufferedWritable,
Destructor
),
flags(BASETYPE, HAS_DICT)
)]
impl BufferedRandom {}

impl Destructor for BufferedRandom {
fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
let _ = vm.call_method(zelf, "close", ());
Ok(())
}

#[cold]
fn del(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
unreachable!("slot_del is implemented")
}
}

impl DefaultConstructor for BufferedRandom {}

#[pyattr]
Expand Down Expand Up @@ -1900,7 +1942,13 @@ mod _io {
}

#[pyclass(
with(Constructor, Initializer, BufferedReadable, BufferedWritable),
with(
Constructor,
Initializer,
BufferedReadable,
BufferedWritable,
Destructor
),
flags(BASETYPE, HAS_DICT)
)]
impl BufferedRWPair {
Expand Down Expand Up @@ -1942,6 +1990,18 @@ mod _io {
}
}

impl Destructor for BufferedRWPair {
fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
let _ = vm.call_method(zelf, "close", ());
Ok(())
}

#[cold]
fn del(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
unreachable!("slot_del is implemented")
}
}

#[derive(FromArgs)]
struct TextIOWrapperArgs {
#[pyarg(any, default)]
Expand Down Expand Up @@ -2413,7 +2473,10 @@ mod _io {
vm.call_method(&textio.buffer, "flush", ())
}

#[pyclass(with(Constructor, Initializer), flags(BASETYPE))]
#[pyclass(
with(Constructor, Initializer, Destructor, Iterable, IterNext),
flags(BASETYPE)
)]
impl TextIOWrapper {
#[pymethod]
fn reconfigure(&self, args: TextIOWrapperArgs, vm: &VirtualMachine) -> PyResult<()> {
Expand Down Expand Up @@ -3276,6 +3339,57 @@ mod _io {
}
}

impl Destructor for TextIOWrapper {
fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
let _ = vm.call_method(zelf, "close", ());
Ok(())
}

#[cold]
fn del(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
unreachable!("slot_del is implemented")
}
}

impl Iterable for TextIOWrapper {
fn slot_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
check_closed(&zelf, vm)?;
Ok(zelf)
}

fn iter(_zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult {
unreachable!("slot_iter is implemented")
}
}

impl IterNext for TextIOWrapper {
fn slot_iternext(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
// Set telling = false during iteration (matches CPython behavior)
let textio_ref: PyRef<TextIOWrapper> =
zelf.downcast_ref::<TextIOWrapper>().unwrap().to_owned();
{
let mut textio = textio_ref.lock(vm)?;
textio.telling = false;
}

let line = vm.call_method(zelf, "readline", ())?;

if !line.clone().try_to_bool(vm)? {
// Restore telling on StopIteration
let mut textio = textio_ref.lock(vm)?;
textio.snapshot = None;
textio.telling = textio.seekable;
Ok(PyIterReturn::StopIteration(None))
} else {
Ok(PyIterReturn::Return(line))
}
}

fn next(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyIterReturn> {
unreachable!("slot_iternext is implemented")
}
}

#[pyattr]
#[pyclass(name)]
#[derive(Debug, PyPayload, Default)]
Expand Down Expand Up @@ -4166,14 +4280,15 @@ mod _io {
mod fileio {
use super::{_io::*, Offset};
use crate::{
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
VirtualMachine,
builtins::{PyBaseExceptionRef, PyUtf8Str, PyUtf8StrRef},
common::crt_fd,
convert::{IntoPyException, ToPyException},
function::{ArgBytesLike, ArgMemoryBuffer, OptionalArg, OptionalOption},
ospath::{IOErrorBuilder, OsPath, OsPathOrFd},
stdlib::os,
types::{Constructor, DefaultConstructor, Initializer, Representable},
types::{Constructor, DefaultConstructor, Destructor, Initializer, Representable},
};
use crossbeam_utils::atomic::AtomicCell;
use std::io::{Read, Write};
Expand Down Expand Up @@ -4433,7 +4548,7 @@ mod fileio {
}

#[pyclass(
with(Constructor, Initializer, Representable),
with(Constructor, Initializer, Representable, Destructor),
flags(BASETYPE, HAS_DICT)
)]
impl FileIO {
Expand Down Expand Up @@ -4649,4 +4764,16 @@ mod fileio {
Err(vm.new_type_error(format!("cannot pickle '{}' object", zelf.class().name())))
}
}

impl Destructor for FileIO {
fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
let _ = vm.call_method(zelf, "close", ());
Ok(())
}

#[cold]
fn del(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
unreachable!("slot_del is implemented")
}
}
}
Loading