| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting. Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: e671f40a-9c4d-4cfd-969b-1e2d65d0058f 📥 CommitsReviewing files that changed from the base of the PR and between c0fccaa and fc3a36f. 📒 Files selected for processing (2)
📝 Walkthrough WalkthroughChangesException handling
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: z-ca-2026 Suggested reviewers: youknowone 🚥 Pre-merge checks | ✅ 5 ✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. ❤️ ShareComment @coderabbitai help to get the list of available commands. |
Sorry, something went wrong.
📦 Library DependenciesThe following Lib/ modules were modified. Here are their dependencies: [x] test: cpython/Lib/test/test_exceptions.py (TODO: 22) dependencies: dependent tests: (no tests depend on exception) Legend:
|
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agentsVerify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Inline comments: In `@crates/vm/src/exceptions.rs`: - Around line 2784-2792: Update the SyntaxError argument handling around msg and location_tuple to coerce the second argument through the generic sequence protocol rather than downcasting specifically to PyTuple; accept sequence inputs such as lists, and propagate TypeError for non-sequences instead of silently treating them as absent.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 068691d7-638d-45e0-860e-5eefd748527c
📥 CommitsReviewing files that changed from the base of the PR and between dd9bce5 and a540419.
⛔ Files ignored due to path filters (1)
Sorry, something went wrong.
|
Thanks for taking on part of #8345 ! 😁 |
Sorry, something went wrong.
Convert PySyntaxError from a #[repr(transparent)] newtype into a #[repr(C)] struct holding msg, filename, lineno, offset, text, end_lineno, end_offset and print_file_and_line as PyAtomicRef fields exposed through pygetset, following the PyStopIteration/PyOSError pattern. Re-initialization now resets end_lineno/end_offset so a 4-tuple __init__ clears previously set values (gh-146250). msg is initialized in the constructor so subclasses whose __init__ slot is not reached (e.g. TabError) still render it. new_exception() now routes exception types with additional payload through invoke_exception() so the compile-error path constructs a fully initialized SyntaxError payload. Unmark test_exceptions' test_syntax_error_memory_leak. Assisted-by: Claude Code:claude-fable-5
The second argument to SyntaxError(msg, ...) is now coerced from any sequence like CPython's PySequence_Tuple, so a list works and a non-sequence raises TypeError, instead of the exact-tuple downcast that silently dropped both cases. Assisted-by: Claude Code:claude-fable-5
|
@kangdora could you please review this patch? you recently worked on this series. you must be the one who know this the best. Thank you in advance! |
Sorry, something went wrong.
There was a problem hiding this comment.
Congrats on your first contribution, and thank you for taking this on! 🎉
I went through the whole patch. The SyntaxError conversion itself looks correctly implemented to me. Things I specifically verified:
Apart from SyntaxError itself, I'd like other opinions on the new_exception change.
Some change there is unavoidable — the existing debug_assert would now fire for SyntaxError. I see two options:
(1) The current global size-based fallback. It conveniently covers the remaining #8345 conversions ahead of time, but at two costs:
(2) A dedicated constructor path for this type — the pattern already used by new_stop_iteration and OSErrorBuilder. This keeps the existing guard and avoids the panic path above.
I don't think this trade-off is mine to decide — @youknowone , could you weigh in?
Sorry, something went wrong.
| let base_exception = PyBaseException::new(args.args, vm); | ||
| Ok(Self { | ||
| base: PyException(base_exception), | ||
| msg: msg.into(), |
There was a problem hiding this comment.
Nit: setting msg here is redundant — slot_init sets it again — and diverges slightly from CPython, where __new__ leaves msg unset (SyntaxError.__new__(SyntaxError, "x").msg is None there, since only __init__ assigns it). msg: None.into() would match.
Sorry, something went wrong.
There was a problem hiding this comment.
You're right about the CPython __new__ behavior, but msg: None.into() brings back a CI failure from earlier in this PR.
Since TabError (a second-level subclass) never reaches PySyntaxError::slot_init, TabError("error", …) renders as TabError: <no detail available> in tracebacks, which breaks test_doctest's test_syntax_error_with_note.
Setting it in py_new is a workaround until slot inheritance works properly for second-level subclasses.
Sorry, something went wrong.
If invoke_exception fails because the exception type's __init__ raises (e.g. a 5-element SyntaxError location tuple), return that exception rather than panicking with a misleading message. Also document why PySyntaxError::py_new sets msg: second-level subclasses such as TabError never reach slot_init. Assisted-by: Claude Code:claude-fable-5
|
LGTM! 👍 Nice catch documenting the msg set in py_new. |
Sorry, something went wrong.
| if exc_type.slots.basicsize != core::mem::size_of::<PyBaseException>() { | ||
| // If constructing the exception raises (e.g. __init__ rejects the | ||
| // args), surface that exception instead of panicking. | ||
| return self.invoke_exception(&exc_type, args).unwrap_or_else(|e| e); |
There was a problem hiding this comment.
unwrap_or_else is wrong folding here.
The result of invoke_exception return error instance of given exc_type. But unwrapped error is not. it is error caused during the process of raising error.
in my opinion, new_exception must not call invoke_exception for a few reason
new_exception is fast exception creation path for types which doesn't require python invoke. the reason why this function can skip returning Err is based on the restriction.
If we allow to invoke exception initializer, the restriction goes broken. we have to keep this as thin and fast path.
Note: it doesn't mean i am justifying the name new_exception and invoke_exception. if anyone can suggest good names that shows this difference, welcome.
Sorry, something went wrong.
There was a problem hiding this comment.
Agreed on keeping new_exception thin.
I prototyped a dedicated payload path that skips PyType::call, for the internal builders that know their type at compile time:
pub fn new_payload_exception<T>(&self, cls: PyTypeRef, args: FuncArgs) -> PyResult<PyRef<T>>
where
T: Constructor<Args = FuncArgs> + Initializer,
{
let payload = T::py_new(&cls, args.clone(), self)?;
let exc = payload
.into_ref_with_type_lazy_dict(self, cls)
.expect("new_payload_exception: cls is not a matching subtype of T");
T::slot_init(exc.as_object().to_owned(), args, self)?;
Ok(exc)
}I verified it by routing both StopIteration and OSError through it — behaves identically, vm tests pass, and it simplifies OSErrorBuilder. new_exception stays untouched, and invoke_exception still handles the runtime-typed / user-subclass path.
If you're on board with this direction, I'd open it as a separate draft to work on further.
Sorry, something went wrong.
There was a problem hiding this comment.
sounds good, let's try it
Sorry, something went wrong.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Part of #8345
Summary
SyntaxError's members were stored as None class-attribute placeholders plus per-instance __dict__ entries, so SyntaxError('m').__dict__ was non-empty ({'print_file_and_line': None}, plus filename/lineno/offset/text for the (msg, tuple) form) unlike CPython, and they weren't backed by descriptors. They're now struct fields on PySyntaxError (#[repr(C)] + base field, the same approach as SystemExit in #8282 and StopIteration in #8301), exposed via #[pygetset] — writable, deletable, independent from args, with an empty __dict__ as in CPython. IndentationError, TabError, and _IncompleteInputError inherit the fields.
Re-initialization now resets end_lineno/end_offset, so a 4-element location tuple after a 6-element one no longer keeps stale values (matches CPython's gh-146250 fix):
new_exception is also routed through the real constructor for exception types that carry additional payload (now including SyntaxError), instead of building a base-sized PyBaseException. Without this, the compile-error path (new_exception_msg(syntax_error, …), ~15 call sites) would allocate a wrong-sized payload — a debug-assert panic, and out-of-bounds reads in release.
Test plan
Verified against CPython 3.14.6: msg/filename/lineno/offset/text/end_lineno/end_offset for SyntaxError(), the 4-tuple, and the 6-tuple forms; write/delete; re-init reset; empty __dict__; IndentationError/TabError inheritance; and the compile-error path (compile("1 +", ...) renders the caret and sets lineno/msg).
Notes:
Assisted-by: Claude Code:claude-fable-5
Summary by CodeRabbit