diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py index 8ea2484ae..205697cb2 100644 --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -203,8 +203,6 @@ Content-Length: 3 self.addCleanup(cgi.closelog) cgi.log("Testing log 4") - # TODO RUSTPYTHON - @unittest.expectedFailure def test_fieldstorage_readline(self): # FieldStorage uses readline, which has the capacity to read all # contents of the input file into memory; we use readline's size argument @@ -294,8 +292,6 @@ Content-Length: 3 got = getattr(fs.list[x], k) self.assertEqual(got, exp) - # TODO RUSTPYTHON - @unittest.expectedFailure def test_fieldstorage_multipart_maxline(self): # Issue #18167 maxline = 1 << 16 diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index ba514814f..6bb61b6da 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -732,8 +732,6 @@ class IOTest(unittest.TestCase): self.assertRaises(ValueError, self.open, support.TESTFN, 'w', closefd=False) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_read_closed(self): with self.open(support.TESTFN, "w") as f: f.write("egg\n") @@ -893,8 +891,6 @@ class IOTest(unittest.TestCase): open('non-existent', 'r', opener=badopener) self.assertEqual(str(cm.exception), 'opener returned -2') - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_fileio_closefd(self): # Issue #4841 with self.open(__file__, 'rb') as f1, \ diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py index 368694c6f..51e52bc4f 100644 --- a/Lib/test/test_iter.py +++ b/Lib/test/test_iter.py @@ -768,9 +768,6 @@ class TestCase(unittest.TestCase): self.assertEqual(indexOf(iclass, i), i) self.assertRaises(ValueError, indexOf, iclass, -1) - # Test iterators with file.writelines(). - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_writelines(self): f = open(TESTFN, "w") diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 12b439746..43d93f58b 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -190,8 +190,6 @@ class FileTests(unittest.TestCase): new = sys.getrefcount(path) self.assertEqual(old, new) - # TODO: RUSTPYTHON (OSError: Bad file descriptor (os error 9)) - @unittest.expectedFailure def test_read(self): with open(support.TESTFN, "w+b") as fobj: fobj.write(b"spam") diff --git a/Lib/test/test_raise.py b/Lib/test/test_raise.py index 062b8fcc1..8a22369b7 100644 --- a/Lib/test/test_raise.py +++ b/Lib/test/test_raise.py @@ -376,8 +376,6 @@ class TestContext(unittest.TestCase): else: self.fail("No exception raised") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_raise_finally(self): try: try: @@ -389,8 +387,6 @@ class TestContext(unittest.TestCase): else: self.fail("No exception raised") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_context_manager(self): class ContextManager: def __enter__(self): diff --git a/src/main.rs b/src/main.rs index 28709e017..51649c270 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use rustpython_vm::{ match_class, pyobject::{BorrowValue, ItemProtocol, PyResult, TypeProtocol}, scope::Scope, - util, InitParameter, Interpreter, PySettings, VirtualMachine, + sysmodule, util, InitParameter, Interpreter, PySettings, VirtualMachine, }; use std::convert::TryInto; @@ -56,6 +56,8 @@ fn main() { let exitcode = interp.enter(move |vm| { let res = run_rustpython(vm, &matches); + flush_std(vm); + #[cfg(feature = "flame-it")] { main_guard.end(); @@ -103,12 +105,23 @@ fn main() { let _ = vm.run_atexit_funcs(); + flush_std(vm); + exitcode }); process::exit(exitcode); } +fn flush_std(vm: &VirtualMachine) { + if let Ok(stdout) = sysmodule::get_stdout(vm) { + let _ = vm.call_method(&stdout, "flush", ()); + } + if let Ok(stderr) = sysmodule::get_stderr(vm) { + let _ = vm.call_method(&stderr, "flush", ()); + } +} + fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { let app = app .setting(AppSettings::TrailingVarArg) diff --git a/vm/src/lib.rs b/vm/src/lib.rs index ad94fff03..082f4b61b 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -69,7 +69,7 @@ mod sequence; mod sliceable; pub mod slots; pub mod stdlib; -mod sysmodule; +pub mod sysmodule; pub mod types; pub mod util; mod version; diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 1c75a751f..aa3127eca 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -887,7 +887,11 @@ mod _io { match res { Some(n) => { written += n; - remaining -= n; + if let Some(r) = remaining.checked_sub(n) { + remaining = r + } else { + break; + } vm.check_signals()?; } None => { @@ -1923,6 +1927,14 @@ mod _io { let buffer = self.lock(vm)?.buffer.clone(); vm.get_attribute(buffer, "name") } + #[pyproperty] + fn encoding(&self, vm: &VirtualMachine) -> PyResult { + Ok(self.lock(vm)?.encoding.clone()) + } + #[pyproperty] + fn errors(&self, vm: &VirtualMachine) -> PyResult { + Ok(self.lock(vm)?.errors.clone()) + } #[pymethod] fn fileno(&self, vm: &VirtualMachine) -> PyResult { diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index b2e9bd7a7..11481bc65 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -114,6 +114,12 @@ fn fs_metadata>(path: P, follow_symlink: bool) -> io::Result for PyPathLike { + fn as_ref(&self) -> &Path { + &self.path + } +} + impl TryFromObject for PyPathLike { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { let match1 = |obj: &PyObjectRef| { @@ -924,6 +930,23 @@ mod _os { Ok(()) } + #[pyfunction] + fn truncate(path: PyObjectRef, length: Offset, vm: &VirtualMachine) -> PyResult<()> { + if let Ok(fd) = i64::try_from_object(vm, path.clone()) { + return ftruncate(fd, length, vm); + } + let path = PyPathLike::try_from_object(vm, path)?; + // TODO: just call libc::truncate() on POSIX + let f = OpenOptions::new() + .write(true) + .open(&path) + .map_err(|e| e.into_pyexception(vm))?; + f.set_len(length as u64) + .map_err(|e| e.into_pyexception(vm))?; + drop(f); + Ok(()) + } + #[pyattr] #[pyclass(module = "os", name = "terminal_size")] #[derive(PyStructSequence)] diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index 654e7fef8..50941462d 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -403,7 +403,7 @@ const ABIFLAGS: &str = ""; // https://github.com/python/cpython/blob/3.8/configure.ac#L725 const MULTIARCH: &str = env!("RUSTPYTHON_TARGET_TRIPLE"); -pub fn sysconfigdata_name() -> String { +pub(crate) fn sysconfigdata_name() -> String { format!("_sysconfigdata_{}_{}_{}", ABIFLAGS, PLATFORM, MULTIARCH) } @@ -484,7 +484,7 @@ impl PyIntInfo { }; } -pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectRef) { +pub(crate) fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectRef) { let ctx = &vm.ctx; let _flags_type = SysFlags::make_class(ctx);