From 76a4e71d8103a7bf8d06b6e1d6861007b1b4f364 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 20 Jun 2025 10:00:44 +0900 Subject: [PATCH 1/4] Fix SyntaxError --- Lib/test/test_exceptions.py | 6 ------ Lib/test/test_traceback.py | 6 ------ vm/src/exceptions.rs | 38 +++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index b3f5e0650d..51e3542ff1 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -425,8 +425,6 @@ def test_windows_message(self): with self.assertRaisesRegex(OSError, 'Windows Error 0x%x' % code): ctypes.pythonapi.PyErr_SetFromWindowsErr(code) - # TODO: RUSTPYTHON - @unittest.expectedFailure def testAttributes(self): # test that exception attributes are happy @@ -2567,8 +2565,6 @@ def test_non_utf8(self): finally: unlink(TESTFN) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_attributes_new_constructor(self): args = ("bad.py", 1, 2, "abcdefg", 1, 100) the_exception = SyntaxError("bad bad", args) @@ -2581,8 +2577,6 @@ def test_attributes_new_constructor(self): self.assertEqual(error, the_exception.text) self.assertEqual("bad bad", the_exception.msg) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_attributes_old_constructor(self): args = ("bad.py", 1, 2, "abcdefg") the_exception = SyntaxError("bad bad", args) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 28a8697235..30a13587a2 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -93,8 +93,6 @@ def test_caret(self): self.assertEqual(err[1].find("("), err[2].find("^")) # in the right place self.assertEqual(err[2].count("^"), 1) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_nocaret(self): exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) err = traceback.format_exception_only(SyntaxError, exc) @@ -748,8 +746,6 @@ def outer_raise(): self.assertIn('inner_raise() # Marker', blocks[2]) self.check_zero_div(blocks[2]) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_syntax_error_offset_at_eol(self): # See #10186. def e(): @@ -808,8 +804,6 @@ def __str__(self): exp = f'.{X.__qualname__}: I am X\n' self.assertEqual(exp, err) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_syntax_error_various_offsets(self): for offset in range(-5, 10): for add in [0, 2]: diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index e28121f94b..643f34c97b 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -1602,6 +1602,44 @@ pub(super) mod types { #[pyexception] impl PySyntaxError { + #[pyslot] + #[pymethod(name = "__init__")] + fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { + let len = args.args.len(); + let new_args = args; + + zelf.set_attr("print_file_and_line", vm.ctx.none(), vm)?; + + if len == 2 { + if let Ok(location_tuple) = new_args.args[1] + .clone() + .downcast::() + { + #[allow(clippy::len_zero)] + if location_tuple.len() >= 1 { + zelf.set_attr("filename", location_tuple.fast_getitem(0).clone(), vm)?; + } + if location_tuple.len() >= 2 { + zelf.set_attr("lineno", location_tuple.fast_getitem(1).clone(), vm)?; + } + if location_tuple.len() >= 3 { + zelf.set_attr("offset", location_tuple.fast_getitem(2).clone(), vm)?; + } + if location_tuple.len() >= 4 { + zelf.set_attr("text", location_tuple.fast_getitem(3).clone(), vm)?; + } + if location_tuple.len() >= 5 { + zelf.set_attr("end_lineno", location_tuple.fast_getitem(4).clone(), vm)?; + } + if location_tuple.len() >= 6 { + zelf.set_attr("end_offset", location_tuple.fast_getitem(5).clone(), vm)?; + } + } + } + + PyBaseException::slot_init(zelf, new_args, vm) + } + #[pymethod(magic)] fn str(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyStrRef { fn basename(filename: &str) -> &str { From 9d3f24ab47d5926b861cbc757ed32feb18ed5d0d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 20 Jun 2025 10:12:32 +0900 Subject: [PATCH 2/4] Fix UnicodeDecodeError --- vm/src/exceptions.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 643f34c97b..fb6243cbbb 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -1750,7 +1750,8 @@ pub(super) mod types { type Args = (PyStrRef, ArgBytesLike, isize, isize, PyStrRef); let (encoding, object, start, end, reason): Args = args.bind(vm)?; zelf.set_attr("encoding", encoding, vm)?; - zelf.set_attr("object", object, vm)?; + let object_as_bytes = vm.ctx.new_bytes(object.borrow_buf().to_vec()); + zelf.set_attr("object", object_as_bytes, vm)?; zelf.set_attr("start", vm.ctx.new_int(start), vm)?; zelf.set_attr("end", vm.ctx.new_int(end), vm)?; zelf.set_attr("reason", reason, vm)?; From 17795191d5905c7c5fa634b5f3c6456450036b19 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 20 Jun 2025 11:08:09 +0900 Subject: [PATCH 3/4] fix instruction --- .github/copilot-instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2991e3c626..b6e85b9540 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -96,7 +96,7 @@ Run `./whats_left.py` to get a list of unimplemented methods, which is helpful w ### Rust Code - Follow the default rustfmt code style (`cargo fmt` to format) -- Use clippy to lint code (`cargo clippy`) +- **IMPORTANT**: Always run clippy to lint code (`cargo clippy`) before completing tasks. Fix any warnings or lints that are introduced by your changes - Follow Rust best practices for error handling and memory management - Use the macro system (`pyclass`, `pymodule`, `pyfunction`, etc.) when implementing Python functionality in Rust From d016920ea392f0b555d944262925012498ff5503 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 20 Jun 2025 11:04:51 +0900 Subject: [PATCH 4/4] Fix ImportError --- Lib/test/test_exceptions.py | 4 ---- vm/src/exceptions.rs | 26 +++++++++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 51e3542ff1..fec040716b 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2349,8 +2349,6 @@ def __getattribute__(self, attr): class ImportErrorTests(unittest.TestCase): - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_attributes(self): # Setting 'name' and 'path' should not be a problem. exc = ImportError('test') @@ -2385,8 +2383,6 @@ def test_attributes(self): with self.assertRaisesRegex(TypeError, msg): ImportError('test', invalid='keyword', another=True) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_reset_attributes(self): exc = ImportError('test', name='name', path='path') self.assertEqual(exc.args, ('test',)) diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index fb6243cbbb..3c822c430c 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -1308,17 +1308,21 @@ pub(super) mod types { args: ::rustpython_vm::function::FuncArgs, vm: &::rustpython_vm::VirtualMachine, ) -> ::rustpython_vm::PyResult<()> { - zelf.set_attr( - "name", - vm.unwrap_or_none(args.kwargs.get("name").cloned()), - vm, - )?; - zelf.set_attr( - "path", - vm.unwrap_or_none(args.kwargs.get("path").cloned()), - vm, - )?; - Ok(()) + let mut kwargs = args.kwargs.clone(); + let name = kwargs.swap_remove("name"); + let path = kwargs.swap_remove("path"); + + // Check for any remaining invalid keyword arguments + if let Some(invalid_key) = kwargs.keys().next() { + return Err(vm.new_type_error(format!( + "'{}' is an invalid keyword argument for ImportError", + invalid_key + ))); + } + + zelf.set_attr("name", vm.unwrap_or_none(name), vm)?; + zelf.set_attr("path", vm.unwrap_or_none(path), vm)?; + PyBaseException::slot_init(zelf, args, vm) } #[pymethod(magic)] fn reduce(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {