From 9ccd5d6980723a657f34f090f7e55e566072caa0 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Tue, 3 Feb 2026 08:18:04 +0900 Subject: [PATCH] more windows impl --- Lib/test/test_genericpath.py | 1 - Lib/test/test_os.py | 1 - Lib/test/test_posix.py | 1 - crates/vm/src/ospath.rs | 15 ++++++++++- crates/vm/src/stdlib/posix.rs | 48 ++++++++++++++++++++++++++++++++--- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index ab580dfad..1a44cedcd 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -170,7 +170,6 @@ class GenericTest: os.close(w) self.assertFalse(self.pathmodule.exists(r)) - @unittest.expectedFailure # TODO: RUSTPYTHON def test_exists_bool(self): for fd in False, True: with self.assertWarnsRegex(RuntimeWarning, diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 488e91d28..f1119d2d1 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2554,7 +2554,6 @@ class TestInvalidFD(unittest.TestCase): def test_fchown(self): self.check(os.fchown, -1, -1) - @unittest.expectedFailure # TODO: RUSTPYTHON; OSError: [Errno 22] Invalid argument: 0 @unittest.skipUnless(hasattr(os, 'fpathconf'), 'test needs os.fpathconf()') def test_fpathconf(self): self.assertIn("PC_NAME_MAX", os.pathconf_names) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index c133a4286..4589180d7 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1349,7 +1349,6 @@ class PosixTester(unittest.TestCase): param = posix.sched_param(sched_priority=-large) self.assertRaises(OverflowError, posix.sched_setparam, 0, param) - @unittest.expectedFailureIf(sys.platform == 'linux', "TODO: RUSTPYTHON; TypeError: cannot pickle 'sched_param' object") @requires_sched def test_sched_param(self): param = posix.sched_param(1) diff --git a/crates/vm/src/ospath.rs b/crates/vm/src/ospath.rs index 25fcafb74..b9efccde3 100644 --- a/crates/vm/src/ospath.rs +++ b/crates/vm/src/ospath.rs @@ -1,8 +1,9 @@ use rustpython_common::crt_fd; use crate::{ - PyObjectRef, PyResult, VirtualMachine, + AsObject, PyObjectRef, PyResult, VirtualMachine, builtins::{PyBytes, PyStr}, + class::StaticType, convert::{IntoPyException, ToPyException, ToPyObject, TryFromObject}, function::FsPath, }; @@ -80,6 +81,18 @@ impl PathConverter { ) -> PyResult> { // Handle fd (before __fspath__ check, like CPython) if let Some(int) = obj.try_index_opt(vm) { + // Warn if bool is used as a file descriptor + if obj + .class() + .is(crate::builtins::bool_::PyBool::static_type()) + { + crate::stdlib::warnings::warn( + vm.ctx.exceptions.runtime_warning, + "bool is used as a file descriptor".to_owned(), + 1, + vm, + )?; + } let fd = int?.try_to_primitive(vm)?; return unsafe { crt_fd::Borrowed::try_borrow_raw(fd) } .map(OsPathOrFd::Fd) diff --git a/crates/vm/src/stdlib/posix.rs b/crates/vm/src/stdlib/posix.rs index 72efe1614..82a5532ab 100644 --- a/crates/vm/src/stdlib/posix.rs +++ b/crates/vm/src/stdlib/posix.rs @@ -19,7 +19,7 @@ pub fn set_inheritable(fd: BorrowedFd<'_>, inheritable: bool) -> nix::Result<()> pub mod module { use crate::{ AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, - builtins::{PyDictRef, PyInt, PyListRef, PyStr, PyStrRef, PyTupleRef, PyType}, + builtins::{PyDictRef, PyInt, PyListRef, PyStr, PyTupleRef, PyType}, convert::{IntoPyException, ToPyObject, TryFromObject}, exceptions::OSErrorBuilder, function::{Either, KwArgs, OptionalArg}, @@ -29,8 +29,14 @@ pub mod module { warn_if_bool_fd, }, types::{Constructor, Representable}, - utils::ToCString, }; + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" + ))] + use crate::{builtins::PyStrRef, utils::ToCString}; use alloc::ffi::CString; use bitflags::bitflags; use core::ffi::CStr; @@ -281,6 +287,7 @@ pub mod module { impl TryFromObject for BorrowedFd<'_> { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + crate::stdlib::os::warn_if_bool_fd(&obj, vm)?; let fd = i32::try_from_object(vm, obj)?; if fd == -1 { return Err(io::Error::from_raw_os_error(libc::EBADF).into_pyexception(vm)); @@ -904,6 +911,37 @@ pub mod module { self.sched_priority.clone().to_pyobject(vm) } + #[pymethod] + fn __reduce__(zelf: crate::PyRef, vm: &VirtualMachine) -> PyTupleRef { + vm.new_tuple((zelf.class().to_owned(), (zelf.sched_priority.clone(),))) + } + + #[pymethod] + fn __replace__( + zelf: crate::PyRef, + args: crate::function::FuncArgs, + vm: &VirtualMachine, + ) -> PyResult { + if !args.args.is_empty() { + return Err( + vm.new_type_error("__replace__() takes no positional arguments".to_owned()) + ); + } + let sched_priority = match args.kwargs.get("sched_priority") { + Some(v) => v.clone(), + None => zelf.sched_priority.clone(), + }; + // Check for unexpected keyword arguments + for key in args.kwargs.keys() { + if key.as_str() != "sched_priority" { + return Err(vm.new_type_error(format!( + "__replace__() got an unexpected keyword argument '{key}'" + ))); + } + } + Ok(Self { sched_priority }) + } + #[cfg(any( target_os = "linux", target_os = "netbsd", @@ -2091,7 +2129,11 @@ pub mod module { let i = match obj.downcast::() { Ok(int) => int.try_to_primitive(vm)?, Err(obj) => { - let s = PyStrRef::try_from_object(vm, obj)?; + let s = obj.downcast::().map_err(|_| { + vm.new_type_error( + "configuration names must be strings or integers".to_owned(), + ) + })?; s.as_str() .parse::() .map_err(|_| vm.new_value_error("unrecognized configuration name"))?