Skip to content

Commit 172095a

Browse files
committed
win
1 parent b1c3b40 commit 172095a

File tree

8 files changed

+297
-90
lines changed

8 files changed

+297
-90
lines changed

Lib/test/test_os.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,6 @@ def check_file_attributes(self, result):
714714
self.assertTrue(isinstance(result.st_file_attributes, int))
715715
self.assertTrue(0 <= result.st_file_attributes <= 0xFFFFFFFF)
716716

717-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.stat return value doesnt have st_file_attributes attribute')
718717
@unittest.skipUnless(sys.platform == "win32",
719718
"st_file_attributes is Win32 specific")
720719
def test_file_attributes(self):
@@ -736,7 +735,6 @@ def test_file_attributes(self):
736735
result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY,
737736
stat.FILE_ATTRIBUTE_DIRECTORY)
738737

739-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.stat (PermissionError: [Errno 5] Access is denied.)')
740738
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
741739
def test_access_denied(self):
742740
# Default to FindFirstFile WIN32_FIND_DATA when access is
@@ -759,7 +757,6 @@ def test_access_denied(self):
759757
self.assertNotEqual(result.st_size, 0)
760758
self.assertTrue(os.path.isfile(fname))
761759

762-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.stat (PermissionError: [Errno 1] Incorrect function.)')
763760
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
764761
def test_stat_block_device(self):
765762
# bpo-38030: os.stat fails for block devices
@@ -817,7 +814,6 @@ def _test_utime(self, set_time, filename=None):
817814
self.assertEqual(st.st_atime_ns, atime_ns)
818815
self.assertEqual(st.st_mtime_ns, mtime_ns)
819816

820-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: 2.002003 != 1.002003 within 1e-06 delta (1.0000000000000002 difference))')
821817
def test_utime(self):
822818
def set_time(filename, ns):
823819
# test the ns keyword parameter
@@ -883,7 +879,6 @@ def set_time(filename, ns):
883879
os.utime(name, dir_fd=dirfd, ns=ns)
884880
self._test_utime(set_time)
885881

886-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: 2.002003 != 1.002003 within 1e-06 delta (1.0000000000000002 difference))')
887882
def test_utime_directory(self):
888883
def set_time(filename, ns):
889884
# test calling os.utime() on a directory
@@ -912,21 +907,18 @@ def _test_utime_current(self, set_time):
912907
self.assertAlmostEqual(st.st_mtime, current,
913908
delta=delta, msg=msg)
914909

915-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: 3359485824.516508 != 1679742912.516503 within 0.05 delta (1679742912.000005 difference) : st_time=3359485824.516508, current=1679742912.516503, dt=1679742912.000005)')
916910
def test_utime_current(self):
917911
def set_time(filename):
918912
# Set to the current time in the new way
919913
os.utime(self.fname)
920914
self._test_utime_current(set_time)
921915

922-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: 3359485824.5186944 != 1679742912.5186892 within 0.05 delta (1679742912.0000052 difference) : st_time=3359485824.5186944, current=1679742912.5186892, dt=1679742912.0000052)')
923916
def test_utime_current_old(self):
924917
def set_time(filename):
925918
# Set to the current time in the old explicit way.
926919
os.utime(self.fname, None)
927920
self._test_utime_current(set_time)
928921

929-
@unittest.expectedFailure # TODO: RUSTPYTHON
930922
def test_utime_nonexistent(self):
931923
now = time.time()
932924
filename = 'nonexistent'
@@ -958,7 +950,6 @@ def test_large_time(self):
958950
os.utime(self.fname, (large, large))
959951
self.assertEqual(os.stat(self.fname).st_mtime, large)
960952

961-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: NotImplementedError not raised)')
962953
def test_utime_invalid_arguments(self):
963954
# seconds and nanoseconds parameters are mutually exclusive
964955
with self.assertRaises(ValueError):
@@ -1161,7 +1152,6 @@ def test_putenv_unsetenv(self):
11611152
self.assertEqual(proc.stdout.rstrip(), repr(None))
11621153

11631154
# On OS X < 10.6, unsetenv() doesn't return a value (bpo-13415).
1164-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: ValueError not raised by putenv)')
11651155
@support.requires_mac_ver(10, 6)
11661156
def test_putenv_unsetenv_error(self):
11671157
# Empty variable name is invalid.
@@ -1796,7 +1786,6 @@ def test_mode(self):
17961786
self.assertEqual(os.stat(path).st_mode & 0o777, 0o555)
17971787
self.assertEqual(os.stat(parent).st_mode & 0o777, 0o775)
17981788

1799-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.umask not implemented yet for all platforms')
18001789
@unittest.skipIf(
18011790
support.is_emscripten or support.is_wasi,
18021791
"Emscripten's/WASI's umask is a stub."
@@ -1815,7 +1804,6 @@ def test_exist_ok_existing_directory(self):
18151804
# Issue #25583: A drive root could raise PermissionError on Windows
18161805
os.makedirs(os.path.abspath('/'), exist_ok=True)
18171806

1818-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.umask not implemented yet for all platforms')
18191807
@unittest.skipIf(
18201808
support.is_emscripten or support.is_wasi,
18211809
"Emscripten's/WASI's umask is a stub."
@@ -2102,7 +2090,6 @@ def test_urandom_failure(self):
21022090
"""
21032091
assert_python_ok('-c', code)
21042092

2105-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; on Windows (ModuleNotFoundError: No module named 'os')")
21062093
def test_urandom_fd_closed(self):
21072094
# Issue #21207: urandom() should reopen its fd to /dev/urandom if
21082095
# closed.
@@ -2117,7 +2104,6 @@ def test_urandom_fd_closed(self):
21172104
"""
21182105
rc, out, err = assert_python_ok('-Sc', code)
21192106

2120-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; (ModuleNotFoundError: No module named 'os'")
21212107
def test_urandom_fd_reopened(self):
21222108
# Issue #21207: urandom() should detect its fd to /dev/urandom
21232109
# changed to something else, and reopen it.
@@ -2205,7 +2191,6 @@ def test_execv_with_bad_arglist(self):
22052191
self.assertRaises(ValueError, os.execv, 'notepad', ('',))
22062192
self.assertRaises(ValueError, os.execv, 'notepad', [''])
22072193

2208-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.execve not implemented yet for all platforms')
22092194
def test_execvpe_with_bad_arglist(self):
22102195
self.assertRaises(ValueError, os.execvpe, 'notepad', [], None)
22112196
self.assertRaises(ValueError, os.execvpe, 'notepad', [], {})
@@ -2265,7 +2250,6 @@ def test_internal_execvpe_str(self):
22652250
if os.name != "nt":
22662251
self._test_internal_execvpe(bytes)
22672252

2268-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.execve not implemented yet for all platforms')
22692253
def test_execve_invalid_env(self):
22702254
args = [sys.executable, '-c', 'pass']
22712255

@@ -2287,7 +2271,6 @@ def test_execve_invalid_env(self):
22872271
with self.assertRaises(ValueError):
22882272
os.execve(args[0], args, newenv)
22892273

2290-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.execve not implemented yet for all platforms')
22912274
@unittest.skipUnless(sys.platform == "win32", "Win32-specific test")
22922275
def test_execve_with_empty_path(self):
22932276
# bpo-32890: Check GetLastError() misuse
@@ -3221,7 +3204,6 @@ def test_getfinalpathname_handles(self):
32213204

32223205
self.assertEqual(0, handle_delta)
32233206

3224-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.stat (PermissionError: [Errno 5] Access is denied.)')
32253207
@support.requires_subprocess()
32263208
def test_stat_unlink_race(self):
32273209
# bpo-46785: the implementation of os.stat() falls back to reading
@@ -3431,7 +3413,6 @@ def test_waitstatus_to_exitcode(self):
34313413
with self.assertRaises(TypeError):
34323414
os.waitstatus_to_exitcode(0.0)
34333415

3434-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.spawnv not implemented yet for all platforms')
34353416
@unittest.skipUnless(sys.platform == 'win32', 'win32-specific test')
34363417
def test_waitpid_windows(self):
34373418
# bpo-40138: test os.waitpid() and os.waitstatus_to_exitcode()
@@ -3440,7 +3421,6 @@ def test_waitpid_windows(self):
34403421
code = f'import _winapi; _winapi.ExitProcess({STATUS_CONTROL_C_EXIT})'
34413422
self.check_waitpid(code, exitcode=STATUS_CONTROL_C_EXIT)
34423423

3443-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (OverflowError: Python int too large to convert to Rust i32)')
34443424
@unittest.skipUnless(sys.platform == 'win32', 'win32-specific test')
34453425
def test_waitstatus_to_exitcode_windows(self):
34463426
max_exitcode = 2 ** 32 - 1
@@ -4661,7 +4641,6 @@ def test_get_set_inheritable_o_path(self):
46614641
os.set_inheritable(fd, False)
46624642
self.assertEqual(os.get_inheritable(fd), False)
46634643

4664-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.get_inheritable not implemented yet for all platforms')
46654644
def test_get_set_inheritable_badf(self):
46664645
fd = os_helper.make_bad_fd()
46674646

@@ -4842,7 +4821,6 @@ class PathTConverterTests(unittest.TestCase):
48424821
('open', False, (os.O_RDONLY,), getattr(os, 'close', None)),
48434822
]
48444823

4845-
@unittest.expectedFailure # TODO: RUSTPYTHON; (AssertionError: TypeError not raised)
48464824
def test_path_t_converter(self):
48474825
str_filename = os_helper.TESTFN
48484826
if os.name == 'nt':
@@ -4927,7 +4905,6 @@ def setUp(self):
49274905
self.addCleanup(os_helper.rmtree, self.path)
49284906
os.mkdir(self.path)
49294907

4930-
@unittest.expectedFailure # TODO: RUSTPYTHON; (AssertionError: TypeError not raised by DirEntry)
49314908
def test_uninstantiable(self):
49324909
self.assertRaises(TypeError, os.DirEntry)
49334910

@@ -4976,7 +4953,6 @@ def assert_stat_equal(self, stat1, stat2, skip_fields):
49764953
else:
49774954
self.assertEqual(stat1, stat2)
49784955

4979-
@unittest.expectedFailure # TODO: RUSTPYTHON; (AssertionError: TypeError not raised by ScandirIter)
49804956
def test_uninstantiable(self):
49814957
scandir_iter = os.scandir(self.path)
49824958
self.assertRaises(TypeError, type(scandir_iter))
@@ -5119,7 +5095,6 @@ def test_fspath_protocol_bytes(self):
51195095
self.assertEqual(fspath,
51205096
os.path.join(os.fsencode(self.path),bytes_filename))
51215097

5122-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; entry.is_dir() is False')
51235098
def test_removed_dir(self):
51245099
path = os.path.join(self.path, 'dir')
51255100

@@ -5142,7 +5117,6 @@ def test_removed_dir(self):
51425117
self.assertRaises(FileNotFoundError, entry.stat)
51435118
self.assertRaises(FileNotFoundError, entry.stat, follow_symlinks=False)
51445119

5145-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; entry.is_file() is False')
51465120
def test_removed_file(self):
51475121
entry = self.create_file_entry()
51485122
os.unlink(entry.path)
@@ -5230,7 +5204,6 @@ def test_fd(self):
52305204
st = os.stat(entry.name, dir_fd=fd, follow_symlinks=False)
52315205
self.assertEqual(entry.stat(follow_symlinks=False), st)
52325206

5233-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: FileNotFoundError not raised by scandir)')
52345207
@unittest.skipIf(support.is_wasi, "WASI maps '' to cwd")
52355208
def test_empty_path(self):
52365209
self.assertRaises(FileNotFoundError, os.scandir, '')
@@ -5367,7 +5340,6 @@ def __fspath__(self):
53675340
return ''
53685341
self.assertFalse(hasattr(A(), '__dict__'))
53695342

5370-
@unittest.expectedFailure # TODO: RUSTPYTHON
53715343
def test_fspath_set_to_None(self):
53725344
class Foo:
53735345
__fspath__ = None

crates/vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ features = [
129129
"Win32_Globalization",
130130
"Win32_Networking_WinSock",
131131
"Win32_Security",
132+
"Win32_Security_Authorization",
132133
"Win32_Storage_FileSystem",
133134
"Win32_System_Console",
134135
"Win32_System_Diagnostics_Debug",

crates/vm/src/function/fspath.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,28 @@ pub enum FsPath {
1313
Bytes(PyBytesRef),
1414
}
1515

16+
/// Controls which error message format to use when path conversion fails.
17+
/// CPython uses different error messages depending on the context.
18+
#[derive(Clone, Copy, PartialEq, Eq)]
19+
pub enum FsPathErrorFormat {
20+
/// "expected str, bytes or os.PathLike object, not {}" - used by os.fspath and open()
21+
OsFspath,
22+
/// "should be string, bytes or os.PathLike, not {}" - used by path arguments (os.rename, etc.)
23+
PathArg,
24+
}
25+
1626
impl FsPath {
1727
// PyOS_FSPath in CPython
1828
pub fn try_from(obj: PyObjectRef, check_for_nul: bool, vm: &VirtualMachine) -> PyResult<Self> {
29+
Self::try_from_ext(obj, check_for_nul, FsPathErrorFormat::OsFspath, vm)
30+
}
31+
32+
pub fn try_from_ext(
33+
obj: PyObjectRef,
34+
check_for_nul: bool,
35+
error_format: FsPathErrorFormat,
36+
vm: &VirtualMachine,
37+
) -> PyResult<Self> {
1938
let check_nul = |b: &[u8]| {
2039
if !check_for_nul || memchr::memchr(b'\0', b).is_none() {
2140
Ok(())
@@ -41,13 +60,29 @@ impl FsPath {
4160
Ok(pathlike) => return Ok(pathlike),
4261
Err(obj) => obj,
4362
};
44-
let method =
45-
vm.get_method_or_type_error(obj.clone(), identifier!(vm, __fspath__), || {
63+
let not_pathlike_error = || match error_format {
64+
FsPathErrorFormat::OsFspath => {
4665
format!(
47-
"should be string, bytes, os.PathLike or integer, not {}",
66+
"expected str, bytes or os.PathLike object, not {}",
4867
obj.class().name()
4968
)
50-
})?;
69+
}
70+
FsPathErrorFormat::PathArg => {
71+
format!(
72+
"should be string, bytes or os.PathLike, not {}",
73+
obj.class().name()
74+
)
75+
}
76+
};
77+
let method = vm.get_method_or_type_error(
78+
obj.clone(),
79+
identifier!(vm, __fspath__),
80+
not_pathlike_error,
81+
)?;
82+
// If __fspath__ is explicitly set to None, treat it as if it doesn't have __fspath__
83+
if vm.is_none(&method) {
84+
return Err(vm.new_type_error(not_pathlike_error()));
85+
}
5186
let result = method.call((), vm)?;
5287
match1(result)?.map_err(|result| {
5388
vm.new_type_error(format!(

crates/vm/src/function/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub use arithmetic::{PyArithmeticValue, PyComparisonValue};
1717
pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike};
1818
pub use builtin::{IntoPyNativeFn, PyNativeFn, static_func, static_raw_func};
1919
pub use either::Either;
20-
pub use fspath::FsPath;
20+
pub use fspath::{FsPath, FsPathErrorFormat};
2121
pub use getset::PySetterValue;
2222
pub(super) use getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetterFunc, PySetterFunc};
2323
pub use method::{HeapMethodDef, PyMethodDef, PyMethodFlags};

crates/vm/src/ospath.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
PyObjectRef, PyResult, VirtualMachine,
55
builtins::PyBaseExceptionRef,
66
convert::{IntoPyException, ToPyException, ToPyObject, TryFromObject},
7-
function::FsPath,
7+
function::{FsPath, FsPathErrorFormat},
88
object::AsObject,
99
};
1010
use std::path::{Path, PathBuf};
@@ -55,6 +55,14 @@ impl OsPath {
5555
Ok(Self { path, mode })
5656
}
5757

58+
/// Convert an object to OsPath using the os.fspath-style error message.
59+
/// This is used by open() which should report "expected str, bytes or os.PathLike object, not"
60+
/// instead of "should be string, bytes or os.PathLike, not".
61+
pub(crate) fn try_from_fspath(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
62+
let fspath = FsPath::try_from_ext(obj, true, FsPathErrorFormat::OsFspath, vm)?;
63+
Self::from_fspath(fspath, vm)
64+
}
65+
5866
pub fn as_path(&self) -> &Path {
5967
Path::new(&self.path)
6068
}
@@ -90,7 +98,7 @@ impl AsRef<Path> for OsPath {
9098
impl TryFromObject for OsPath {
9199
// TODO: path_converter with allow_fd=0 in CPython
92100
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
93-
let fspath = FsPath::try_from(obj, true, vm)?;
101+
let fspath = FsPath::try_from_ext(obj, true, FsPathErrorFormat::PathArg, vm)?;
94102
Self::from_fspath(fspath, vm)
95103
}
96104
}

crates/vm/src/stdlib/io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4340,7 +4340,7 @@ mod fileio {
43404340
}
43414341
(fd, None)
43424342
} else {
4343-
let path = OsPath::try_from_object(vm, name.clone())?;
4343+
let path = OsPath::try_from_fspath(name.clone(), vm)?;
43444344
#[cfg(any(unix, target_os = "wasi"))]
43454345
let fd = crt_fd::open(&path.clone().into_cstring(vm)?, flags, 0o666);
43464346
#[cfg(windows)]

0 commit comments

Comments
 (0)