Skip to content

Allow multiple indented blocks in REPL #6097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jackoconnordev
Copy link
Contributor

@jackoconnordev jackoconnordev commented Aug 15, 2025

Description

Allow nested indented blocks in RustPython REPL.

Additional comments

There aren't any tests but being able to do nested for loops seems like a pretty big win to me so I'm going to put up for review.

The original returned boolean clearly had false positives for detecting bad errors for things like nested if and for statements. What is less clear is if there are any true positives which I am no longer catching with the updated return value.

Questions

I have seen reference to something called ctypes that if fixed would allow the use of pyrepl which is implemented in Python. Is there any way I could help with the ctypes work?

Manual testing

Before

>>>>> for i in range(2):
.....   for j in range(2):
  File "<stdin>", line 2
    for j in range(2):
                      ^
IndentationError: expected an indented block after `for` statement

After

>>>>> for i in range(2):
.....   for j in range(2):
.....     print(i, j)
.....
0 0
0 1
1 0
1 1

Summary by CodeRabbit

  • Bug Fixes
    • Improved REPL behavior when entering multi-line blocks: inputs that require an indented block now consistently prompt for continuation instead of throwing an error.
    • Reduced sporadic parse errors during block entry, resulting in smoother multi-line editing and fewer interruptions.
    • Ensured consistent handling of indentation-related messages so users can complete block constructs without unexpected failures.

There aren't any tests but being able to do nested for loops seems like
a pretty big win to me so I'm going to put up for review.

The original returned boolean clearly had **false positives** for
detecting bad errors for things like nested `if` and `for` statements.
What is less clear is if there are any **true positives** which I am no
longer catching with the updated return value.
Copy link
Contributor

coderabbitai bot commented Aug 15, 2025

Walkthrough

Updates shell_exec’s error handling in src/shell.rs: for OtherError messages starting with "Expected an indented block", the REPL now always returns ContinueBlock, independent of continuing_block. IndentationError handling remains tied to continuing_block; other errors still yield PyErr.

Changes

Cohort / File(s) Summary of Changes
REPL error handling
src/shell.rs
Simplified branch: for OtherError whose message starts with "Expected an indented block", always return ContinueBlock; removed dependency on continuing_block. IndentationError still respects continuing_block; other errors remain PyErr.

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant R as REPL
  participant P as Parser
  participant H as Error Handler (shell_exec)

  U->>R: Enter code
  R->>P: Parse input
  P-->>H: Error
  alt IndentationError
    H->>H: Use continuing_block to decide
    H-->>R: ContinueBlock or PyErr
  else OtherError starts with "Expected an indented block"
    H-->>R: ContinueBlock (always)
  else OtherError (other)
    H-->>R: PyErr
  end
  R-->>U: Outcome
Loading

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

I thump my paw: “Indent ahead!”
Blocks march on where once they fled.
No wobble now, the path is clear—
ContinueBlock, we persevere.
In REPL burrows, tidy flow,
The rabbit nods: “Alright, let’s go.” 🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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 (3)
src/shell.rs (3)

77-81: Refresh the comment to match the actual behavior and remove stale ‘dedent’ note

The current comment mentions column checks and dedent handling that aren’t reflected in the code anymore. Updating the comment helps future maintainers.

Apply this diff to align the comment with the current logic:

-            // bad_error == true if we are handling an error that should be thrown even if we are continuing
-            // if its an indentation error, set to true if we are continuing and the error is on column 0,
-            // since indentations errors on columns other than 0 should be ignored.
-            // if its an unrecognized token for dedent, set to false
+            // bad_error is true when the error should be raised immediately (fatal), even while building a block.
+            // - IndentationError: fatal iff we are already continuing a block (pressing an empty line still raises).
+            // - "Expected an indented block": non-fatal — always ContinueBlock to allow nested/nested blocks.
+            // - All other parse errors: fatal.

82-95: Avoid brittle string literal; centralize the prefix used for detection

To reduce the risk of typos and make future updates easier if the message text changes slightly, centralize the prefix in a constant and reference it here.

Apply this diff within this match arm:

-                        ParseErrorType::OtherError(msg) => {
-                            !msg.starts_with("Expected an indented block")
-                        }
+                        ParseErrorType::OtherError(msg) => {
+                            !msg.starts_with(EXPECTED_INDENTED_BLOCK_PREFIX)
+                        }

Add this constant near the top of the file (e.g., after imports):

const EXPECTED_INDENTED_BLOCK_PREFIX: &str = "Expected an indented block";

97-103: Add targeted tests to lock in behavior (nested blocks and blank-line error)

The new behavior is desirable; please add tests that assert:

  • ContinueBlock after a single “for …:” line.
  • ContinueBlock after a nested “for …:” line when already in a continuing block.
  • PyErr when an empty line is submitted while still expecting an indented block (matches CPython).

I can help scaffold tests around shell_exec in a #[cfg(test)] module to exercise these cases.

Would you like me to draft the tests?

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a9a9e3b and 135ccae.

📒 Files selected for processing (1)
  • src/shell.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 (cargo fmt to format)
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

Files:

  • src/shell.rs
🔇 Additional comments (2)
src/shell.rs (2)

88-90: Always ContinueBlock on “Expected an indented block” — correct fix to enable nested blocks

This change ensures nested for/if blocks are accepted even when already inside a continuing block. The blank-line case still raises (due to the empty_line_given check), which matches CPython REPL behavior.


88-90: Update error-check prefix to match parser output

The guard in src/shell.rs is using the truncated prefix "Expected an indented block", but the parser emits "Expected an indented block after". This mismatch causes the intended errors to slip through.

• src/shell.rs:89

-   !msg.starts_with("Expected an indented block")
+   !msg.starts_with("Expected an indented block after")

Likely an incorrect or invalid review comment.

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