Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 24, 2025

SyntaxError.msg was exposed as read-only, causing AttributeError when tools like xonsh attempted to assign to it. The str formatting also ignored a reassigned or missing msg.

  • Writable msg getset: Added a setter for SyntaxError.msg that updates the args tuple consistently for both assignment and deletion.
  • Str formatting: SyntaxError.__str__ now uses the msg attribute (with safe fallback) so string output reflects runtime changes to msg.
  • Regression test: Added a regression snippet in extra_tests/snippets/builtin_exceptions.py covering assigning and deleting SyntaxError.msg, ensuring str(err) reflects updates.

Example:

err = SyntaxError("bad", ("file.py", 1, 2, "src"))
err.msg = "changed"
assert str(err) == "changed (file.py, line 1)"
del err.msg
assert err.msg is None
Original prompt

This section details on the original issue you should resolve

<issue_title>AttributeError: attribute 'msg' of 'SyntaxError' objects is not writable</issue_title>
<issue_description>Hi! I'm trying to run xonsh and sometimes I have this stack trace e.g. in #6489 (comment) where the command ls /:

ls /
Traceback (most recent call last):
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/shells/base_shell.py", line 524, in compile
    compile_empty_tree=False,
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/execer.py", line 131, in compile
    tree = self.parse(input, ctx, mode=mode, filename=filename, transform=transform)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/execer.py", line 87, in parse
    tree, input = self._parse_ctx_free(input, mode=mode, filename=filename)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/execer.py", line 346, in _parse_ctx_free
    return _try_parse(input, greedy=True)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/execer.py", line 344, in _parse_ctx_free
    return _try_parse(input, greedy=False)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/execer.py", line 338, in _try_parse
    input = "\n".join(lines)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/execer.py", line 239, in _try_parse
    debug_level=(self.debug_level >= 2),
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/parsers/base.py", line 505, in parse
    tree = self.parser.parse(input=s, lexer=self.lexer, debug=debug_level)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/parsers/ply/yacc.py", line 335, in parse
    return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/parsers/ply/yacc.py", line 1203, in parseopt_notrack
    tok = call_errorfunc(self.errorfunc, errtoken, self)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/parsers/ply/yacc.py", line 194, in call_errorfunc
    r = errorfunc(token)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/parsers/base.py", line 3685, in p_error
    self._parse_error(msg, self.currloc(lineno=p.lineno, column=p.lexpos))
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/parsers/base.py", line 632, in _parse_error
    raise_parse_error(msg, loc, self._source, self.lines)
  File "/Users/pc/.local/lib/rustpython3.13/site-packages/xonsh/parsers/base.py", line 212, in raise_parse_error
    err.msg = str(msg) if msg else ""
AttributeError: attribute 'msg' of 'SyntaxError' objects is not writable
```</issue_description>

<agent_instructions>Fix PySyntaxError to allow `msg` setter. Ensure `cargo run -- -m test test_exceptions -vv` success</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Summary by CodeRabbit

  • New Features

    • SyntaxError's "msg" field is now mutable and can be modified or deleted.
  • Documentation

    • Updated development guidelines for test placement.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 24, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

This PR makes the SyntaxError.msg attribute writable in RustPython by introducing a custom setter that updates the exception's args[0] when the attribute is modified. It also updates SyntaxError.__str__ to prefer the msg attribute when available. A test case validates the new mutability behavior.

Changes

Cohort / File(s) Summary
Documentation
DEVELOPMENT.md
Added contextual guidance note about placing RustPython-only regression tests in the extra_tests directory rather than under Lib/test.
Exception API Enhancement
crates/vm/src/exceptions.rs
Exported PySetterValue from function module; extended PySyntaxError with a writable getset for the "msg" field; added syntax_error_set_msg() setter function to update args[0] when "msg" is assigned or deleted; modified __str__ to prioritize the "msg" attribute over default formatting.
Test Coverage
extra_tests/snippets/builtin_exceptions.py
Added test block validating SyntaxError.msg mutability: creation, assignment, string representation updates, and attribute deletion.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Fix SyntaxError, UnicodeDecodeError #5807 — Modifies vm/src/exceptions.rs and PySyntaxError initialization; complements this PR's setter/getter changes with slot initialization for location-related attributes.

Poem

🐇 A syntax error once stood quite stern,
Its message locked, with no way to turn—
But now with a setter, so graceful and free,
The msg can be changed, as it ought to be! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: making SyntaxError.msg writable and ensuring string formatting reflects updates to the msg attribute.
Linked Issues check ✅ Passed The pull request fully addresses issue #6492 by implementing a writable setter for SyntaxError.msg, modifying str to reflect changes, and adding comprehensive regression tests.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the SyntaxError.msg writeability objective; the DEVELOPMENT.md documentation update provides appropriate context for where tests belong.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI and others added 2 commits December 24, 2025 14:47
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix AttributeError in xonsh when executing commands Allow SyntaxError.msg to be writable and reflected in string formatting Dec 24, 2025
Copilot AI requested a review from youknowone December 24, 2025 15:02
Copy link
Member

@youknowone youknowone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change looks good.

Check about the comment for the test code location.

Comment on lines 2456 to 2463
def test_msg_attribute_writable(self):
err = SyntaxError("bad bad", ("bad.py", 1, 2, "abcdefg"))
err.msg = "changed"
self.assertEqual(err.msg, "changed")
self.assertEqual(str(err), "changed (bad.py, line 1)")
del err.msg
self.assertIsNone(err.msg)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must not add our own test under Lib/test/.

Please move it to extra_tests/snippets/builtin_exceptions.py

Also, please add a sentence to copilot instruction not to make this happen again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 9ba97e5: moved the SyntaxError msg regression check to extra_tests/snippets/builtin_exceptions.py and added guidance in DEVELOPMENT.md to keep RustPython-specific tests out of Lib/test.

Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
@youknowone
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 24, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
extra_tests/snippets/builtin_exceptions.py (1)

88-93: Consider testing str(err) after deletion and args consistency.

The test validates core functionality but could be more comprehensive:

  1. After del err.msg, verify what str(err) returns (currently untested)
  2. Verify that setting msg also updates args[0] to maintain consistency
Enhanced test with additional assertions
 err = SyntaxError("bad bad", ("bad.py", 1, 2, "abcdefg"))
 err.msg = "changed"
 assert err.msg == "changed"
+assert err.args[0] == "changed", "args[0] should be updated when msg is set"
 assert str(err) == "changed (bad.py, line 1)"
 del err.msg
 assert err.msg is None
+# After deletion, str(err) should handle None gracefully
+assert "None" in str(err) or "bad.py" in str(err), "str(err) should still format after msg deletion"
crates/vm/src/exceptions.rs (1)

2075-2083: Clarify fallback logic or check for None after deletion.

The comment states the fallback handles "if the msg attribute was deleted," but syntax_error_set_msg sets args[0] to None on deletion rather than removing it. This means get_attr("msg", vm) succeeds and returns Ok(None object), so the Err(_) branch never executes for deletion.

After deletion, str(err) will format as "None (file.py, line 1)" rather than falling back to base exception formatting.

Consider either:

  1. Update the comment to reflect actual behavior: "Fallback if attribute lookup fails (e.g., attribute overridden incorrectly)"
  2. Check if msg is None and fall back: Ok(obj) if !vm.is_none(&obj) => ...
Option 2: Check for None and fall back
-            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 = match zelf.as_object().get_attr("msg", vm) {
+                Ok(obj) if !vm.is_none(&obj) => obj
+                    .str(vm)
+                    .unwrap_or_else(|_| vm.ctx.new_str("<msg str() failed>")),
+                _ => {
+                    // Fallback to the base formatting if msg is None/missing
+                    return Py::<PyBaseException>::__str__(zelf, vm);
+                }
             };
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2a7393 and 9ba97e5.

📒 Files selected for processing (3)
  • DEVELOPMENT.md
  • crates/vm/src/exceptions.rs
  • extra_tests/snippets/builtin_exceptions.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.rs: Follow the default rustfmt code style by running cargo fmt to format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by 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

Files:

  • crates/vm/src/exceptions.rs
**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.py: In most cases, Python code should not be edited; bug fixes should be made through Rust code modifications only
Follow PEP 8 style for custom Python code
Use ruff for linting Python code

Files:

  • extra_tests/snippets/builtin_exceptions.py
🧠 Learnings (8)
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to Lib/**/*.py : Add a `# TODO: RUSTPYTHON` comment when modifications are made to files in the `Lib/` directory

Applied to files:

  • DEVELOPMENT.md
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to Lib/test/**/*.py : When modifying test files in `Lib/test/`, use `unittest.skip("TODO: RustPython <reason>")` or `unittest.expectedFailure` with `# TODO: RUSTPYTHON <reason>` comment to mark unsupported features

Applied to files:

  • DEVELOPMENT.md
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to Lib/**/*.py : Minimize modifications to CPython standard library files in the `Lib/` directory; modifications should be minimal and only to work around RustPython limitations

Applied to files:

  • DEVELOPMENT.md
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Run `cargo test --workspace --exclude rustpython_wasm` to execute Rust unit tests

Applied to files:

  • DEVELOPMENT.md
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to **/*.rs : Use the macro system (`pyclass`, `pymodule`, `pyfunction`, etc.) when implementing Python functionality in Rust

Applied to files:

  • DEVELOPMENT.md
  • crates/vm/src/exceptions.rs
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Applies to Lib/** : Do not edit the `Lib/` directory directly; the only allowed operation is copying files from CPython

Applied to files:

  • DEVELOPMENT.md
📚 Learning: 2025-11-29T12:17:28.606Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Use `cargo run -- script.py` instead of the standard `python` command to run and test Python code with RustPython

Applied to files:

  • DEVELOPMENT.md
📚 Learning: 2025-12-09T08:46:58.660Z
Learnt from: youknowone
Repo: RustPython/RustPython PR: 6358
File: crates/vm/src/exception_group.rs:173-185
Timestamp: 2025-12-09T08:46:58.660Z
Learning: In crates/vm/src/exception_group.rs, the derive() method intentionally always creates a BaseExceptionGroup instance rather than preserving the original exception class type. This is a deliberate design decision that differs from CPython's behavior.

Applied to files:

  • crates/vm/src/exceptions.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Run rust tests (macos-latest)
  • GitHub Check: Run rust tests (windows-latest)
  • GitHub Check: Run rust tests (ubuntu-latest)
  • GitHub Check: Ensure compilation on various targets
  • GitHub Check: Run snippets and cpython tests (windows-latest)
  • GitHub Check: Run snippets and cpython tests (macos-latest)
  • GitHub Check: Run snippets and cpython tests (ubuntu-latest)
  • GitHub Check: Check Rust code with clippy
  • GitHub Check: Check the WASM package and demo
🔇 Additional comments (4)
DEVELOPMENT.md (1)

133-134: LGTM! Clear guidance for test placement.

The documentation update clarifies where to place RustPython-specific regression tests, which is helpful for contributors.

crates/vm/src/exceptions.rs (3)

12-12: LGTM! Import addition is correct.

The PySetterValue import is necessary for the new syntax_error_set_msg setter function.


997-1002: LGTM! The msg attribute is now writable.

The change from new_readonly_getset to new_static_getset with a setter enables assignment and deletion of the msg attribute, resolving issue #6492.


1049-1066: Implementation correctly maintains msg/args[0] consistency.

The setter ensures args[0] is always updated when msg is modified. Note that deletion sets msg to None rather than removing it entirely, which maintains the invariant that args[0] (the message slot) always exists for SyntaxError.

This design choice means err.msg returns None after deletion rather than raising AttributeError, which aligns with the test expectations.

@youknowone youknowone marked this pull request as ready for review December 24, 2025 23:59
@youknowone youknowone merged commit be9e44a into main Dec 25, 2025
13 checks passed
@youknowone youknowone deleted the copilot/fix-attribute-error-syntaxerror branch December 25, 2025 00:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AttributeError: attribute 'msg' of 'SyntaxError' objects is not writable

2 participants