From a18bad2ca38bc63dd67865d90d2169860163fd1d Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Sun, 2 Oct 2022 18:20:45 +0200 Subject: [PATCH] Fill OSError attributes --- Lib/test/test_exception_hierarchy.py | 5 ++-- Lib/test/test_fileio.py | 2 -- Lib/test/test_subprocess.py | 2 -- extra_tests/snippets/builtin_exceptions.py | 34 ++++++++++++++++++++++ vm/src/exceptions.rs | 30 +++++++++++++++---- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_exception_hierarchy.py b/Lib/test/test_exception_hierarchy.py index ff21cc6b0c2..85a7dd8b2a9 100644 --- a/Lib/test/test_exception_hierarchy.py +++ b/Lib/test/test_exception_hierarchy.py @@ -5,6 +5,7 @@ import unittest import errno from errno import EEXIST +import sys class SubOSError(OSError): @@ -130,8 +131,8 @@ def test_windows_error(self): else: self.assertNotIn('winerror', dir(OSError)) - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.skip("TODO: RUSTPYTHON") + @unittest.skipIf(sys.platform == 'win32', 'winerror not filled yet') def test_posix_error(self): e = OSError(EEXIST, "File already exists", "foo.txt") self.assertEqual(e.errno, EEXIST) diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py index 8577c48c73e..f878fce1dc2 100644 --- a/Lib/test/test_fileio.py +++ b/Lib/test/test_fileio.py @@ -391,8 +391,6 @@ class PyAutoFileTests(AutoFileTests, unittest.TestCase): FileIO = _pyio.FileIO modulename = '_pyio' - # TODO: RUSTPYTHON - @unittest.expectedFailure def testOpendir(self): super().testOpendir() diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 5ade946b57b..73e0ea5472e 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1547,8 +1547,6 @@ def test_failed_child_execute_fd_leak(self): fds_after_exception = os.listdir(fd_directory) self.assertEqual(fds_before_popen, fds_after_exception) - # TODO: RUSTPYTHON - @unittest.expectedFailure @unittest.skipIf(mswindows, "behavior currently not supported on Windows") def test_file_not_found_includes_filename(self): with self.assertRaises(FileNotFoundError) as c: diff --git a/extra_tests/snippets/builtin_exceptions.py b/extra_tests/snippets/builtin_exceptions.py index 564a5c9d066..902393ce5b8 100644 --- a/extra_tests/snippets/builtin_exceptions.py +++ b/extra_tests/snippets/builtin_exceptions.py @@ -264,6 +264,40 @@ class SubError(MyError): assert OSError(1, 2).errno assert OSError(1, 2).strerror + +# OSError Unexpected number of arguments +w = OSError() +assert w.errno == None +assert not sys.platform.startswith("win") or w.winerror == None +assert w.strerror == None +assert w.filename == None +assert w.filename2 == None +assert str(w) == "" + +w = OSError(0) +assert w.errno == None +assert not sys.platform.startswith("win") or w.winerror == None +assert w.strerror == None +assert w.filename == None +assert w.filename2 == None +assert str(w) == "0" + +w = OSError('foo') +assert w.errno == None +assert not sys.platform.startswith("win") or w.winerror == None +assert w.strerror == None +assert w.filename == None +assert w.filename2 == None +assert str(w) == "foo" + +w = OSError('a', 'b', 'c', 'd', 'e', 'f') +assert w.errno == None +assert not sys.platform.startswith("win") or w.winerror == None +assert w.strerror == None +assert w.filename == None +assert w.filename2 == None +assert str(w) == "('a', 'b', 'c', 'd', 'e', 'f')" + # Custom `__new__` and `__init__`: assert ImportError.__init__.__qualname__ == 'ImportError.__init__' assert ImportError(name='a').name == 'a' diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 09f64d8e88d..e5629fa41a6 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -752,13 +752,22 @@ impl ExceptionZoo { let errno_getter = ctx.new_readonly_getset("errno", excs.os_error, |exc: PyBaseExceptionRef| { let args = exc.args(); - args.get(0).filter(|_| args.len() > 1).cloned() + args.get(0) + .filter(|_| args.len() > 1 && args.len() <= 5) + .cloned() + }); + let strerror_getter = + ctx.new_readonly_getset("strerror", excs.os_error, |exc: PyBaseExceptionRef| { + let args = exc.args(); + args.get(1) + .filter(|_| args.len() >= 2 && args.len() <= 5) + .cloned() }); extend_exception!(PyOSError, ctx, excs.os_error, { // POSIX exception code "errno" => errno_getter.clone(), // exception strerror - "strerror" => ctx.new_readonly_getset("strerror", excs.os_error, make_arg_getter(1)), + "strerror" => strerror_getter.clone(), // exception filename "filename" => ctx.none(), // second exception filename @@ -1260,7 +1269,7 @@ pub(super) mod types { os_error, "Base class for I/O related errors.", os_error_new, - base_exception_init, + os_error_init, } #[cfg(not(target_arch = "wasm32"))] fn os_error_optional_new( @@ -1268,7 +1277,7 @@ pub(super) mod types { vm: &VirtualMachine, ) -> Option { let len = args.len(); - if len >= 2 { + if (2..=5).contains(&len) { let errno = &args[0]; errno .payload_if_subclass::(vm) @@ -1297,9 +1306,18 @@ pub(super) mod types { fn os_error_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { PyBaseException::slot_new(cls, args, vm) } + fn os_error_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { + let len = args.args.len(); + let mut new_args = args; + if (3..=5).contains(&len) { + zelf.set_attr("filename", new_args.args[2].clone(), vm)?; + if len == 5 { + zelf.set_attr("filename2", new_args.args[4].clone(), vm)?; + } - fn base_exception_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { - PyBaseException::init(zelf, args, vm) + new_args.args.truncate(2); + } + PyBaseException::init(zelf, new_args, vm) } define_exception! {