-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
F401 Deletes import, cause EOF error #5156
Comments
Yeah the general problem here is that a file can't end in a backslash, I think (even a newline is sufficient). |
Ah, thanks for the info, I was pretty bewildered by this xd |
I wonder what the right thing to do is when a simple change ends up with an incorrect program? |
We should of course fix it, but it's worth noting that this is a fairly unlikely case to hit in the wild. Continuations themselves are relatively rare, and most editors don't even let you save a file without a trailing newline :) |
I actually thought we did handle this case already: pub(crate) fn delete_stmt(
stmt: &Stmt,
parent: Option<&Stmt>,
locator: &Locator,
indexer: &Indexer,
stylist: &Stylist,
) -> Edit {
if parent
.map(|parent| is_lone_child(stmt, parent))
.unwrap_or_default()
{
// If removing this node would lead to an invalid syntax tree, replace
// it with a `pass`.
Edit::range_replacement("pass".to_string(), stmt.range())
} else {
if let Some(semicolon) = trailing_semicolon(stmt, locator) {
let next = next_stmt_break(semicolon, locator);
Edit::deletion(stmt.start(), next)
} else if helpers::has_leading_content(stmt, locator) {
Edit::range_deletion(stmt.range())
} else if helpers::preceded_by_continuation(stmt, indexer, locator) {
if is_end_of_file(stmt, locator) && locator.is_at_start_of_line(stmt.start()) {
// Special-case: a file can't end in a continuation.
Edit::range_replacement(stylist.line_ending().to_string(), stmt.range())
} else {
Edit::range_deletion(stmt.range())
}
} else {
let range = locator.full_lines_range(stmt.range());
Edit::range_deletion(range)
}
}
} Note the branch that says |
I think the safest and most general fix is to extend the deletion to include the continuation character itself. |
I'm pretty sure that the trailing newline is what's causing a similar issue #4404. We attempt to strip the newline, then on the next iteration, the file ends in a |
Did a quick debug, it turns out that specific continuation offset is not being stored here: ruff/crates/ruff_python_ast/src/source_code/indexer.rs Lines 14 to 15 in 653a0eb
Edit: It seems to be happening whenever the continuation character is at the start of the line because these continuation offsets are not being considered: \
import sys
\
import os ruff/crates/ruff_python_ast/src/source_code/indexer.rs Lines 51 to 57 in 653a0eb
The logic says that if the previous token is not a newline or not at the start, only then consider this for the continuation offset. |
Is that only a start-of-file problem? I wonder if that match should allow |
No, sorry I updated the comment. It's occurring whenever the continuation character is at the start of line. This means the previous token was either a newline or |
## Summary Given: ```python \ import os ``` Deleting `import os` leaves a syntax error: a file can't end in a continuation. We have code to handle this case, but it failed to pick up continuations at the _very start_ of a file. Closes #5156.
With this program:
(possibly importantly w/ the lack of a return character after
ost
outputs this when run w/
--fix
:Found via #4822, run against main (be107da)
The text was updated successfully, but these errors were encountered: