Skip to content

Conversation

@youknowone
Copy link
Member

@youknowone youknowone commented Dec 17, 2025

Summary by CodeRabbit

  • Bug Fixes
    • Improved accuracy of OSError messages with better error details formatting
    • Enhanced error handling for blocking I/O operations

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

Walkthrough

This PR refactors OSError exception formatting in exceptions.rs to derive string output directly from OSError fields (errno, strerror, filename, filename2, and winerror on Windows) via conditional logic based on field presence, while updating io.rs to construct non-blocking write errors using a new error construction path.

Changes

Cohort / File(s) Summary
OSError string representation
crates/vm/src/exceptions.rs
Refactored __str__ method to conditionally format output based on available fields: WinError-based formatting (Windows), errno/strerror/filename formatting, or fallback to BaseException. Added explicit field retrieval via object attributes and updated arg truncation logic to be tied to filename presence.
IO error construction
crates/vm/src/stdlib/io.rs
Updated non-blocking write error handling to use new_os_subtype_error with blocking_io_error subtype instead of direct new_exception_msg call.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • exceptions.rs: Multiple conditional branches with Windows-specific handling and field presence checks requiring separate reasoning for each scenario
  • Field extraction logic: Understanding of how errno, strerror, filename, filename2, and winerror interact across platforms
  • Initialization alignment: Verification that slot_init changes maintain compatibility with the new formatting logic

Possibly related PRs

Suggested reviewers

  • coolreader18
  • arihant2math
  • ShaharNaveh

Poem

🐰 A rabbit hops through error streams,
Where OSError fields now reign supreme,
Windows winerror, strerror too,
Filenames formatted fresh and true,
Exception strings now shine so bright!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix winerror handling' is specific and directly related to the primary changes in the pull request, which involve adjusting OSError string representation with conditional branches for winerror handling on Windows.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

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

@youknowone youknowone marked this pull request as ready for review December 17, 2025 11:46
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)
crates/vm/src/stdlib/io.rs (1)

1076-1093: Use of new_os_subtype_error for non‑blocking write looks correct; consider passing errno/written later.

Switching to vm.new_os_subtype_error(vm.ctx.exceptions.blocking_io_error.to_owned(), None, "write could not complete without blocking".to_owned()) keeps this in the OSError hierarchy and aligns with the new OSErrorBuilder/PyOSError::__str__ flow; behavior for now is equivalent to the old “message‑only” BlockingIOError. When you get to the TODO, it would be good to thread through the underlying errno and the number of bytes written so you can construct the full BlockingIOError(errno, msg, written) tuple for CPython parity, but that can be a separate change.

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

1721-1810: New PyOSError::__str__ formatting is consistent and field‑driven; edge cases mostly handled well.

The new implementation:

  • Reads errno, strerror, filename, filename2, and (on Windows) winerror via attributes and ignores values that are None, which is robust to partially‑initialized instances.
  • On Windows, prefers winerror and produces:
    • [WinError N] msg: filename -> filename2 when both filenames are present,
    • [WinError N] msg: filename when only one is present,
    • [WinError N] msg when only winerror/strerror are present.
  • Otherwise (or when no winerror), uses errno‑driven formats:
    • [Errno N] msg: filename -> filename2,
    • [Errno N] msg: filename,
    • [Errno N] msg (no filename),
    • and finally falls back to BaseException.__str__ when neither errno nor strerror is available.

This lines up well with CPython’s user‑facing strings and works correctly with the updated OSErrorBuilder/slot_init behavior (e.g., your new BlockingIOError path in io.rs still falls back to the single‑argument BaseException formatting when no errno/filename are set). No functional issues stand out here.

📜 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 9d2dd17 and b273d53.

📒 Files selected for processing (2)
  • crates/vm/src/exceptions.rs (2 hunks)
  • crates/vm/src/stdlib/io.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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/stdlib/io.rs
  • crates/vm/src/exceptions.rs
🧠 Learnings (3)
📓 Common learnings
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 : Follow Rust best practices for error handling and memory management
📚 Learning: 2025-11-10T06:27:41.954Z
Learnt from: youknowone
Repo: RustPython/RustPython PR: 6243
File: vm/src/function/buffer.rs:123-129
Timestamp: 2025-11-10T06:27:41.954Z
Learning: In vm/src/function/buffer.rs, line 36 in the try_rw_bytes_like method intentionally uses TypeError (not BufferError) for the "buffer is not a read-write bytes-like object" error case, even though a similar error message in ArgMemoryBuffer::try_from_borrowed_object uses BufferError. The TypeError is the intended exception type for this specific code path.

Applied to files:

  • crates/vm/src/stdlib/io.rs
📚 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/stdlib/io.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). (1)
  • GitHub Check: Run snippets and cpython tests (windows-latest)
🔇 Additional comments (1)
crates/vm/src/exceptions.rs (1)

1665-1717: The downcast_ref::<PyOSError>() invariant is well-documented and maintained by the macro pattern.

The concern about panicking is mitigated: all OSError subclasses in the codebase use #[repr(transparent)] wrapping PyOSError, and this pattern is enforced by the #[pyexception(base = PyOSError, ...)] macro. The existing safety comment already documents this invariant clearly.

However, a runtime debug assertion (e.g., before the unwrap()) checking cls.fast_issubclass(os_error) would provide an extra safety layer for detecting violations at runtime, should someone accidentally introduce a subclass without the #[repr(transparent)] wrapper in the future.

The field population, Windows winerror-to-errno conversion, and arg truncation logic all look correct:

  • Arguments 2–5 are properly mapped to errno/strerror/filename/winerror/filename2.
  • Arg truncation only occurs when both len ∈ [3, 5] and filename is non-None, matching CPython behavior.
  • The __str__ formatting correctly prioritizes Windows winerror, falls back to errno, and respects filenames with proper representation.

@youknowone youknowone merged commit 0412dfd into RustPython:main Dec 17, 2025
13 checks passed
@youknowone youknowone deleted the winerror branch December 17, 2025 11:57
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.

1 participant