diff --git a/crates/ruff_linter/resources/test/fixtures/isort/required_imports/whitespace.py b/crates/ruff_linter/resources/test/fixtures/isort/required_imports/whitespace.py new file mode 100644 index 0000000000..73a74680b8 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/required_imports/whitespace.py @@ -0,0 +1,5 @@ +# This is a regression test for https://github.com/astral-sh/ruff/issues/19310 +# there is a (potentially invisible) unicode formfeed character (000C) between "docstring" and the semicolon +"docstring" ; print( + f"{__doc__=}", +) diff --git a/crates/ruff_linter/src/importer/insertion.rs b/crates/ruff_linter/src/importer/insertion.rs index 68ff1214f9..f76bd0a383 100644 --- a/crates/ruff_linter/src/importer/insertion.rs +++ b/crates/ruff_linter/src/importer/insertion.rs @@ -288,7 +288,7 @@ fn match_docstring_end(body: &[Stmt]) -> Option { fn match_semicolon(s: &str) -> Option { for (offset, c) in s.char_indices() { match c { - ' ' | '\t' => continue, + _ if is_python_whitespace(c) => continue, ';' => return Some(TextSize::try_from(offset).unwrap()), _ => break, } diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 642066b0a8..04bfc55c71 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -801,6 +801,7 @@ mod tests { #[test_case(Path::new("existing_import.py"))] #[test_case(Path::new("multiline_docstring.py"))] #[test_case(Path::new("off.py"))] + #[test_case(Path::new("whitespace.py"))] fn required_import(path: &Path) -> Result<()> { let snapshot = format!("required_import_{}", path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_whitespace.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_whitespace.py.snap new file mode 100644 index 0000000000..2ba62fc470 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_whitespace.py.snap @@ -0,0 +1,11 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +whitespace.py:1:1: I002 [*] Missing required import: `from __future__ import annotations` +ℹ Safe fix +1 1 | # This is a regression test for https://github.com/astral-sh/ruff/issues/19310 +2 2 | # there is a (potentially invisible) unicode formfeed character (000C) between "docstring" and the semicolon +3 |-"docstring" ; print( + 3 |+"docstring" ; from __future__ import annotations; print( +4 4 | f"{__doc__=}", +5 5 | )