mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Allow SyntaxError.msg to be writable and reflected in string formatting (#6493)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
This commit is contained in:
@@ -130,7 +130,8 @@ repository's structure:
|
||||
- `stdlib`: Standard library parts implemented in rust.
|
||||
- `src`: using the other subcrates to bring rustpython to life.
|
||||
- `wasm`: Binary crate and resources for WebAssembly build
|
||||
- `extra_tests`: extra integration test snippets as a supplement to `Lib/test`
|
||||
- `extra_tests`: extra integration test snippets as a supplement to `Lib/test`.
|
||||
Add new RustPython-only regression tests here; do not place new tests under `Lib/test`.
|
||||
|
||||
## Understanding Internals
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
},
|
||||
class::{PyClassImpl, StaticType},
|
||||
convert::{ToPyException, ToPyObject},
|
||||
function::{ArgIterable, FuncArgs, IntoFuncArgs},
|
||||
function::{ArgIterable, FuncArgs, IntoFuncArgs, PySetterValue},
|
||||
py_io::{self, Write},
|
||||
stdlib::sys,
|
||||
suggestion::offer_suggestions,
|
||||
@@ -994,7 +994,12 @@ impl ExceptionZoo {
|
||||
extend_exception!(PyRecursionError, ctx, excs.recursion_error);
|
||||
|
||||
extend_exception!(PySyntaxError, ctx, excs.syntax_error, {
|
||||
"msg" => ctx.new_readonly_getset("msg", excs.syntax_error, make_arg_getter(0)),
|
||||
"msg" => ctx.new_static_getset(
|
||||
"msg",
|
||||
excs.syntax_error,
|
||||
make_arg_getter(0),
|
||||
syntax_error_set_msg,
|
||||
),
|
||||
// TODO: members
|
||||
"filename" => ctx.none(),
|
||||
"lineno" => ctx.none(),
|
||||
@@ -1041,6 +1046,25 @@ fn make_arg_getter(idx: usize) -> impl Fn(PyBaseExceptionRef) -> Option<PyObject
|
||||
move |exc| exc.get_arg(idx)
|
||||
}
|
||||
|
||||
fn syntax_error_set_msg(
|
||||
exc: PyBaseExceptionRef,
|
||||
value: PySetterValue,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let mut args = exc.args.write();
|
||||
let mut new_args = args.as_slice().to_vec();
|
||||
// Ensure the message slot at index 0 always exists for SyntaxError.args.
|
||||
if new_args.is_empty() {
|
||||
new_args.push(vm.ctx.none());
|
||||
}
|
||||
match value {
|
||||
PySetterValue::Assign(value) => new_args[0] = value,
|
||||
PySetterValue::Delete => new_args[0] = vm.ctx.none(),
|
||||
}
|
||||
*args = PyTuple::new_ref(new_args, &vm.ctx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn system_exit_code(exc: PyBaseExceptionRef) -> Option<PyObjectRef> {
|
||||
exc.args.read().first().map(|code| {
|
||||
match_class!(match code {
|
||||
@@ -2048,15 +2072,14 @@ pub(super) mod types {
|
||||
.unwrap_or_else(|_| vm.ctx.new_str("<filename str() failed>"))
|
||||
});
|
||||
|
||||
let args = zelf.args();
|
||||
|
||||
let msg = if args.len() == 1 {
|
||||
vm.exception_args_as_string(args, false)
|
||||
.into_iter()
|
||||
.exactly_one()
|
||||
.unwrap()
|
||||
} else {
|
||||
return zelf.__str__(vm);
|
||||
let msg = match zelf.as_object().get_attr("msg", vm) {
|
||||
Ok(obj) => obj
|
||||
.str(vm)
|
||||
.unwrap_or_else(|_| vm.ctx.new_str("<msg str() failed>")),
|
||||
Err(_) => {
|
||||
// Fallback to the base formatting if the msg attribute was deleted or attribute lookup fails for any reason.
|
||||
return Py::<PyBaseException>::__str__(zelf, vm);
|
||||
}
|
||||
};
|
||||
|
||||
let msg_with_location_info: String = match (maybe_lineno, maybe_filename) {
|
||||
|
||||
@@ -85,6 +85,13 @@ assert exc.lineno is None
|
||||
assert exc.offset is None
|
||||
assert exc.text is None
|
||||
|
||||
err = SyntaxError("bad bad", ("bad.py", 1, 2, "abcdefg"))
|
||||
err.msg = "changed"
|
||||
assert err.msg == "changed"
|
||||
assert str(err) == "changed (bad.py, line 1)"
|
||||
del err.msg
|
||||
assert err.msg is None
|
||||
|
||||
# Regression to:
|
||||
# https://github.com/RustPython/RustPython/issues/2779
|
||||
|
||||
|
||||
Reference in New Issue
Block a user