fspath try from (#6359)

This commit is contained in:
Jeong, YunWon
2025-12-09 05:44:21 +09:00
committed by GitHub
parent b200f0e8d2
commit bb4e30a6df
5 changed files with 46 additions and 14 deletions

2
Lib/test/test_os.py vendored
View File

@@ -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()

View File

@@ -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> {
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<Self> {
pub fn try_from(
obj: PyObjectRef,
check_for_nul: bool,
msg: &'static str,
vm: &VirtualMachine,
) -> PyResult<Self> {
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)
}
}

View File

@@ -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<Self> {
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<Path> for OsPath {
impl TryFromObject for OsPath {
// TODO: path_converter with allow_fd=0 in CPython
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
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)
}
}

View File

@@ -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)]

View File

@@ -1022,7 +1022,7 @@ pub(super) mod _os {
#[pyfunction]
fn fspath(path: PyObjectRef, vm: &VirtualMachine) -> PyResult<FsPath> {
FsPath::try_from(path, false, vm)
FsPath::try_from_path_like(path, false, vm)
}
#[pyfunction]