diff --git a/resources/test/fixtures/isort/preserve_tabs_2.py b/resources/test/fixtures/isort/preserve_tabs_2.py new file mode 100644 index 0000000000..2abfd4afca --- /dev/null +++ b/resources/test/fixtures/isort/preserve_tabs_2.py @@ -0,0 +1,13 @@ +from numpy import ( + cos, + int8, + int16, + int32, + int64, + sin, + tan, + uint8, + uint16, + uint32, + uint64, +) diff --git a/src/rules/isort/mod.rs b/src/rules/isort/mod.rs index 133105e4f2..cbdcc92558 100644 --- a/src/rules/isort/mod.rs +++ b/src/rules/isort/mod.rs @@ -715,6 +715,7 @@ mod tests { #[test_case(Path::new("preserve_import_star.py"))] #[test_case(Path::new("preserve_indentation.py"))] #[test_case(Path::new("preserve_tabs.py"))] + #[test_case(Path::new("preserve_tabs_2.py"))] #[test_case(Path::new("relative_imports_order.py"))] #[test_case(Path::new("reorder_within_section.py"))] #[test_case(Path::new("separate_first_party_imports.py"))] diff --git a/src/rules/isort/rules/organize_imports.rs b/src/rules/isort/rules/organize_imports.rs index d310647533..74d2a7e2cf 100644 --- a/src/rules/isort/rules/organize_imports.rs +++ b/src/rules/isort/rules/organize_imports.rs @@ -1,8 +1,9 @@ use std::path::Path; +use itertools::{EitherOrBoth, Itertools}; use ruff_macros::derive_message_formats; use rustpython_ast::{Location, Stmt}; -use textwrap::{dedent, indent}; +use textwrap::indent; use super::super::track::Block; use super::super::{comments, format_imports}; @@ -43,6 +44,17 @@ fn extract_indentation_range(body: &[&Stmt]) -> Range { Range::new(Location::new(location.row(), 0), location) } +/// Compares two strings, returning true if they are equal modulo whitespace +/// at the start of each line. +fn matches_ignoring_indentation(val1: &str, val2: &str) -> bool { + val1.lines() + .zip_longest(val2.lines()) + .all(|pair| match pair { + EitherOrBoth::Both(line1, line2) => line1.trim_start() == line2.trim_start(), + _ => false, + }) +} + /// I001 pub fn organize_imports( block: &Block, @@ -112,8 +124,8 @@ pub fn organize_imports( Location::new(range.location.row(), 0), Location::new(range.end_location.row() + 1 + num_trailing_lines, 0), ); - let actual = dedent(locator.slice_source_code_range(&range)); - if actual == dedent(&expected) { + let actual = locator.slice_source_code_range(&range); + if matches_ignoring_indentation(actual, &expected) { None } else { let mut diagnostic = Diagnostic::new(UnsortedImports, range); diff --git a/src/rules/isort/snapshots/ruff__rules__isort__tests__preserve_tabs_2.py.snap b/src/rules/isort/snapshots/ruff__rules__isort__tests__preserve_tabs_2.py.snap new file mode 100644 index 0000000000..40d8799b10 --- /dev/null +++ b/src/rules/isort/snapshots/ruff__rules__isort__tests__preserve_tabs_2.py.snap @@ -0,0 +1,6 @@ +--- +source: src/rules/isort/mod.rs +expression: diagnostics +--- +[] +