Resolve PathLike via os.fspath in io.open (#7743)

CPython splits PathLike resolution across two layers: _io.FileIO
preserves the raw argument on .name (low-level contract), while
the high-level open() wrapper resolves it via os.fspath before
delegating. RustPython's io_open skipped that step, so
builtins.open(PathLike).name returned the PathLike object instead
of the resolved str/bytes.

Match Lib/_pyio.py:193-194 by resolving non-int inputs at the
io_open boundary, leaving _io.FileIO unchanged.
This commit is contained in:
Changjoon authored and GitHub committed 2026-05-01 19:44:10 +09:00
1 parent 987b065a16
commit 79c8a0afef
3 files changed
+11 -5

No files matched your search

-1
View File
@@ -740,7 +740,6 @@ class BZ2FileTest(BaseTest):
self.assertEqual(f.read(), self.DATA)
self.assertEqual(f.name, str_filename)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: <FakePath 'Z:\\TEMP\\tmphoipjcen'> != 'Z:\\TEMP\\tmphoipjcen'
def testOpenPathLikeFilename(self):
filename = FakePath(self.filename)
with BZ2File(filename, "wb") as f:
-2
View File
@@ -555,7 +555,6 @@ class FileTestCase(unittest.TestCase):
self.assertIsInstance(f, LZMAFile)
self.assertEqual(f.mode, "wb")
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: <FakePath '@test_23396_tmp챈'> != '@test_23396_tmp챈'
def test_init_with_PathLike_filename(self):
filename = FakePath(TESTFN)
with TempFile(filename, COMPRESSED_XZ):
@@ -1438,7 +1437,6 @@ class OpenTestCase(unittest.TestCase):
with lzma.open(TESTFN, "rb") as f:
self.assertEqual(f.read(), INPUT * 2)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: <FakePath '@test_23396_tmp챈'> != '@test_23396_tmp챈'
def test_with_pathlike_filename(self):
filename = FakePath(TESTFN)
with TempFile(filename):
+11 -2
View File
@@ -121,8 +121,8 @@ mod _io {
convert::ToPyObject,
exceptions::cstring_error,
function::{
ArgBytesLike, ArgIterable, ArgMemoryBuffer, ArgSize, Either, FuncArgs, IntoFuncArgs,
OptionalArg, OptionalOption, PySetterValue,
ArgBytesLike, ArgIterable, ArgMemoryBuffer, ArgSize, Either, FsPath, FuncArgs,
IntoFuncArgs, OptionalArg, OptionalOption, PySetterValue,
},
protocol::{
BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, PyIterReturn, VecBuffer,
@@ -5069,6 +5069,15 @@ mod _io {
}
}
// Match CPython's _pyio.open (Lib/_pyio.py): resolve PathLike here so
// _io.FileIO still receives (and preserves on .name) the raw argument
// when called directly.
let file = if file.fast_isinstance(vm.ctx.types.int_type) {
file
} else {
FsPath::try_from_path_like(file, true, vm)?.to_pyobject(vm)
};
// check file descriptor validity
#[cfg(all(unix, feature = "host_env"))]
if let Ok(crate::ospath::OsPathOrFd::Fd(fd)) = file.clone().try_into_value(vm) {