From 73a86c18abb45027aa9eeea8c3557b9c511eef12 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Fri, 12 Dec 2025 09:38:45 +0900 Subject: [PATCH] Fix test_runpy --- Lib/test/test_runpy.py | 6 ------ Lib/test/test_signal.py | 2 -- crates/common/src/os.rs | 20 +++++++++++++++++++- crates/vm/src/vm/interpreter.rs | 4 ++-- crates/vm/src/vm/mod.rs | 13 +++++++++---- examples/generator.rs | 2 +- examples/package_embed.rs | 2 +- src/lib.rs | 2 +- 8 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index 2492abff019..c1e255e7af3 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -801,11 +801,9 @@ def assertSigInt(self, cmd, *args, **kwargs): self.assertTrue(proc.stderr.endswith("\nKeyboardInterrupt\n"), proc.stderr) self.assertEqual(proc.returncode, self.EXPECTED_CODE) - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ") def test_pymain_run_file(self): self.assertSigInt([self.ham]) - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ") def test_pymain_run_file_runpy_run_module(self): tmp = self.ham.parent run_module = tmp / "run_module.py" @@ -819,7 +817,6 @@ def test_pymain_run_file_runpy_run_module(self): ) self.assertSigInt([run_module], cwd=tmp) - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ") def test_pymain_run_file_runpy_run_module_as_main(self): tmp = self.ham.parent run_module_as_main = tmp / "run_module_as_main.py" @@ -833,14 +830,12 @@ def test_pymain_run_file_runpy_run_module_as_main(self): ) self.assertSigInt([run_module_as_main], cwd=tmp) - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ") def test_pymain_run_command_run_module(self): self.assertSigInt( ["-c", "import runpy; runpy.run_module('ham')"], cwd=self.ham.parent, ) - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ") def test_pymain_run_command(self): self.assertSigInt(["-c", "import ham"], cwd=self.ham.parent) @@ -848,7 +843,6 @@ def test_pymain_run_command(self): def test_pymain_run_stdin(self): self.assertSigInt([], input="import ham", cwd=self.ham.parent) - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ") def test_pymain_run_module(self): ham = self.ham self.assertSigInt(["-m", ham.stem], cwd=ham.parent) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index e05467f7762..5fbb26df831 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -224,8 +224,6 @@ def test_issue9324(self): with self.assertRaises(ValueError): signal.signal(7, handler) - # TODO: RUSTPYTHON - @unittest.expectedFailure @unittest.skipUnless(sys.executable, "sys.executable required.") @support.requires_subprocess() def test_keyboard_interrupt_exit_code(self): diff --git a/crates/common/src/os.rs b/crates/common/src/os.rs index 2d82b1a6ccc..e77a81fd94f 100644 --- a/crates/common/src/os.rs +++ b/crates/common/src/os.rs @@ -1,7 +1,25 @@ // spell-checker:disable // TODO: we can move more os-specific bindings/interfaces from stdlib::{os, posix, nt} to here -use std::{io, str::Utf8Error}; +use std::{io, process::ExitCode, str::Utf8Error}; + +/// Convert exit code to std::process::ExitCode +/// +/// On Windows, this supports the full u32 range including STATUS_CONTROL_C_EXIT (0xC000013A). +/// On other platforms, only the lower 8 bits are used. +pub fn exit_code(code: u32) -> ExitCode { + #[cfg(windows)] + { + // For large exit codes like STATUS_CONTROL_C_EXIT (0xC000013A), + // we need to call std::process::exit() directly since ExitCode::from(u8) + // would truncate the value, and ExitCode::from_raw() is still unstable. + // FIXME: side effect in exit_code is not ideal. + if code > u8::MAX as u32 { + std::process::exit(code as i32) + } + } + ExitCode::from(code as u8) +} pub trait ErrorExt { fn posix_errno(&self) -> i32; diff --git a/crates/vm/src/vm/interpreter.rs b/crates/vm/src/vm/interpreter.rs index efe06d24171..05613d43384 100644 --- a/crates/vm/src/vm/interpreter.rs +++ b/crates/vm/src/vm/interpreter.rs @@ -96,7 +96,7 @@ impl Interpreter { /// /// See [`Interpreter::finalize`] for the finalization steps. /// See also [`Interpreter::enter`] for pure function call to obtain Python exception. - pub fn run(self, f: F) -> u8 + pub fn run(self, f: F) -> u32 where F: FnOnce(&VirtualMachine) -> PyResult<()>, { @@ -113,7 +113,7 @@ impl Interpreter { /// 1. Mark vm as finalized. /// /// Note that calling `finalize` is not necessary by purpose though. - pub fn finalize(self, exc: Option) -> u8 { + pub fn finalize(self, exc: Option) -> u32 { self.enter(|vm| { vm.flush_std(); diff --git a/crates/vm/src/vm/mod.rs b/crates/vm/src/vm/mod.rs index 0d21d708ac8..fd37b2494dd 100644 --- a/crates/vm/src/vm/mod.rs +++ b/crates/vm/src/vm/mod.rs @@ -841,7 +841,7 @@ impl VirtualMachine { } } - pub fn handle_exit_exception(&self, exc: PyBaseExceptionRef) -> u8 { + pub fn handle_exit_exception(&self, exc: PyBaseExceptionRef) -> u32 { if exc.fast_isinstance(self.ctx.exceptions.system_exit) { let args = exc.args(); let msg = match args.as_slice() { @@ -849,7 +849,7 @@ impl VirtualMachine { [arg] => match_class!(match arg { ref i @ PyInt => { use num_traits::cast::ToPrimitive; - return i.as_bigint().to_u8().unwrap_or(0); + return i.as_bigint().to_u32().unwrap_or(0); } arg => { if self.is_none(arg) { @@ -883,9 +883,14 @@ impl VirtualMachine { kill(getpid(), SIGINT).expect("Expect to be killed."); } - (libc::SIGINT as u8) + 128u8 + (libc::SIGINT as u32) + 128 } - #[cfg(not(unix))] + #[cfg(windows)] + { + // STATUS_CONTROL_C_EXIT - same as CPython + 0xC000013A + } + #[cfg(not(any(unix, windows)))] { 1 } diff --git a/examples/generator.rs b/examples/generator.rs index 937687ab8fa..27733a1913d 100644 --- a/examples/generator.rs +++ b/examples/generator.rs @@ -46,5 +46,5 @@ fn main() -> ExitCode { vm.add_native_modules(rustpython_stdlib::get_module_inits()); }); let result = py_main(&interp); - ExitCode::from(interp.run(|_vm| result)) + vm::common::os::exit_code(interp.run(|_vm| result)) } diff --git a/examples/package_embed.rs b/examples/package_embed.rs index 975e734593d..e82e71f5ceb 100644 --- a/examples/package_embed.rs +++ b/examples/package_embed.rs @@ -26,5 +26,5 @@ fn main() -> ExitCode { let result = result.map(|result| { println!("name: {result}"); }); - ExitCode::from(interp.run(|_vm| result)) + vm::common::os::exit_code(interp.run(|_vm| result)) } diff --git a/src/lib.rs b/src/lib.rs index 40e50ab84c6..84a774ab029 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,7 @@ pub fn run(init: impl FnOnce(&mut VirtualMachine) + 'static) -> ExitCode { let interp = config.interpreter(); let exitcode = interp.run(move |vm| run_rustpython(vm, run_mode)); - ExitCode::from(exitcode) + rustpython_vm::common::os::exit_code(exitcode) } fn setup_main_module(vm: &VirtualMachine) -> PyResult {