diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index d968aa87f..30a24e28d 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1811,7 +1811,6 @@ class MakedirTests(unittest.TestCase): # Issue #25583: A drive root could raise PermissionError on Windows os.makedirs(os.path.abspath('/'), exist_ok=True) - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.umask not implemented yet for all platforms') @unittest.skipIf( support.is_emscripten or support.is_wasi, "Emscripten's/WASI's umask is a stub." @@ -4653,7 +4652,6 @@ class FDInheritanceTests(unittest.TestCase): os.set_inheritable(fd, False) self.assertEqual(os.get_inheritable(fd), False) - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.get_inheritable not implemented yet for all platforms') def test_get_set_inheritable_badf(self): fd = os_helper.make_bad_fd() diff --git a/crates/vm/src/function/fspath.rs b/crates/vm/src/function/fspath.rs index 5e0108986..2bc331844 100644 --- a/crates/vm/src/function/fspath.rs +++ b/crates/vm/src/function/fspath.rs @@ -14,8 +14,26 @@ pub enum FsPath { } impl FsPath { + pub fn try_from_path_like( + obj: PyObjectRef, + check_for_nul: bool, + vm: &VirtualMachine, + ) -> PyResult { + Self::try_from( + obj, + check_for_nul, + "expected str, bytes or os.PathLike object", + vm, + ) + } + // PyOS_FSPath in CPython - pub fn try_from(obj: PyObjectRef, check_for_nul: bool, vm: &VirtualMachine) -> PyResult { + pub fn try_from( + obj: PyObjectRef, + check_for_nul: bool, + msg: &'static str, + vm: &VirtualMachine, + ) -> PyResult { let check_nul = |b: &[u8]| { if !check_for_nul || memchr::memchr(b'\0', b).is_none() { Ok(()) @@ -41,13 +59,16 @@ impl FsPath { Ok(pathlike) => return Ok(pathlike), Err(obj) => obj, }; - let method = - vm.get_method_or_type_error(obj.clone(), identifier!(vm, __fspath__), || { - format!( - "should be string, bytes, os.PathLike or integer, not {}", - obj.class().name() - ) - })?; + let not_pathlike_error = || format!("{msg}, not {}", obj.class().name()); + let method = vm.get_method_or_type_error( + obj.clone(), + identifier!(vm, __fspath__), + not_pathlike_error, + )?; + // If __fspath__ is explicitly set to None, treat it as if it doesn't have __fspath__ + if vm.is_none(&method) { + return Err(vm.new_type_error(not_pathlike_error())); + } let result = method.call((), vm)?; match1(result)?.map_err(|result| { vm.new_type_error(format!( @@ -125,6 +146,6 @@ impl TryFromObject for FsPath { } Err(_) => obj, }; - Self::try_from(obj, true, vm) + Self::try_from_path_like(obj, true, vm) } } diff --git a/crates/vm/src/ospath.rs b/crates/vm/src/ospath.rs index 5083c1df5..add40f9b2 100644 --- a/crates/vm/src/ospath.rs +++ b/crates/vm/src/ospath.rs @@ -55,6 +55,14 @@ impl OsPath { Ok(Self { path, mode }) } + /// Convert an object to OsPath using the os.fspath-style error message. + /// This is used by open() which should report "expected str, bytes or os.PathLike object, not" + /// instead of "should be string, bytes or os.PathLike, not". + pub(crate) fn try_from_fspath(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let fspath = FsPath::try_from_path_like(obj, true, vm)?; + Self::from_fspath(fspath, vm) + } + pub fn as_path(&self) -> &Path { Path::new(&self.path) } @@ -90,7 +98,12 @@ impl AsRef for OsPath { impl TryFromObject for OsPath { // TODO: path_converter with allow_fd=0 in CPython fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let fspath = FsPath::try_from(obj, true, vm)?; + let fspath = FsPath::try_from( + obj, + true, + "should be string, bytes, os.PathLike or integer", + vm, + )?; Self::from_fspath(fspath, vm) } } diff --git a/crates/vm/src/stdlib/io.rs b/crates/vm/src/stdlib/io.rs index 39ea310c9..8efd52a29 100644 --- a/crates/vm/src/stdlib/io.rs +++ b/crates/vm/src/stdlib/io.rs @@ -4340,7 +4340,7 @@ mod fileio { } (fd, None) } else { - let path = OsPath::try_from_object(vm, name.clone())?; + let path = OsPath::try_from_fspath(name.clone(), vm)?; #[cfg(any(unix, target_os = "wasi"))] let fd = crt_fd::open(&path.clone().into_cstring(vm)?, flags, 0o666); #[cfg(windows)] diff --git a/crates/vm/src/stdlib/os.rs b/crates/vm/src/stdlib/os.rs index 378cffd83..0034b087a 100644 --- a/crates/vm/src/stdlib/os.rs +++ b/crates/vm/src/stdlib/os.rs @@ -1022,7 +1022,7 @@ pub(super) mod _os { #[pyfunction] fn fspath(path: PyObjectRef, vm: &VirtualMachine) -> PyResult { - FsPath::try_from(path, false, vm) + FsPath::try_from_path_like(path, false, vm) } #[pyfunction]