diff --git a/crates/ruff_linter/resources/test/fixtures/isort/separate_local_folder_imports.py b/crates/ruff_linter/resources/test/fixtures/isort/separate_local_folder_imports.py index beed464c0c..2387c675e9 100644 --- a/crates/ruff_linter/resources/test/fixtures/isort/separate_local_folder_imports.py +++ b/crates/ruff_linter/resources/test/fixtures/isort/separate_local_folder_imports.py @@ -3,3 +3,5 @@ import ruff import leading_prefix import os from . import leading_prefix +from .. import trailing_prefix +from ruff import check diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 59bf5b4fa0..d07017600b 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -471,6 +471,31 @@ mod tests { Ok(()) } + #[test_case(Path::new("separate_local_folder_imports.py"))] + fn known_local_folder_closest(path: &Path) -> Result<()> { + let snapshot = format!("known_local_folder_closest_{}", path.to_string_lossy()); + let diagnostics = test_path( + Path::new("isort").join(path).as_path(), + &LinterSettings { + isort: super::settings::Settings { + known_modules: KnownModules::new( + vec![], + vec![], + vec![pattern("ruff")], + vec![], + FxHashMap::default(), + ), + relative_imports_order: RelativeImportsOrder::ClosestToFurthest, + ..super::settings::Settings::default() + }, + src: vec![test_resource_path("fixtures/isort")], + ..LinterSettings::for_rule(Rule::UnsortedImports) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test_case(Path::new("case_sensitive.py"))] fn case_sensitive(path: &Path) -> Result<()> { let snapshot = format!("case_sensitive_{}", path.to_string_lossy()); diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__known_local_folder_closest_separate_local_folder_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__known_local_folder_closest_separate_local_folder_imports.py.snap new file mode 100644 index 0000000000..8eb419a4a4 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__known_local_folder_closest_separate_local_folder_imports.py.snap @@ -0,0 +1,27 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +separate_local_folder_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import sys +2 | | import ruff +3 | | import leading_prefix +4 | | import os +5 | | from . import leading_prefix +6 | | from .. import trailing_prefix +7 | | from ruff import check + | + = help: Organize imports + +ℹ Safe fix + 1 |+import os +1 2 | import sys + 3 |+ + 4 |+import leading_prefix + 5 |+ +2 6 | import ruff +3 |-import leading_prefix +4 |-import os +5 7 | from . import leading_prefix +6 8 | from .. import trailing_prefix +7 9 | from ruff import check diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__known_local_folder_separate_local_folder_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__known_local_folder_separate_local_folder_imports.py.snap index d8a690be6b..21ed77408c 100644 --- a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__known_local_folder_separate_local_folder_imports.py.snap +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__known_local_folder_separate_local_folder_imports.py.snap @@ -8,6 +8,8 @@ separate_local_folder_imports.py:1:1: I001 [*] Import block is un-sorted or un-f 3 | | import leading_prefix 4 | | import os 5 | | from . import leading_prefix +6 | | from .. import trailing_prefix +7 | | from ruff import check | = help: Organize imports @@ -20,6 +22,7 @@ separate_local_folder_imports.py:1:1: I001 [*] Import block is un-sorted or un-f 2 6 | import ruff 3 |-import leading_prefix 4 |-import os -5 7 | from . import leading_prefix - - + 7 |+from .. import trailing_prefix +5 8 | from . import leading_prefix +6 |-from .. import trailing_prefix +7 9 | from ruff import check diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__separate_local_folder_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__separate_local_folder_imports.py.snap index 23d796602c..88d2f3a1bc 100644 --- a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__separate_local_folder_imports.py.snap +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__separate_local_folder_imports.py.snap @@ -8,18 +8,22 @@ separate_local_folder_imports.py:1:1: I001 [*] Import block is un-sorted or un-f 3 | | import leading_prefix 4 | | import os 5 | | from . import leading_prefix +6 | | from .. import trailing_prefix +7 | | from ruff import check | = help: Organize imports ℹ Safe fix - 1 |+import os -1 2 | import sys - 3 |+ -2 4 | import ruff - 5 |+ -3 6 | import leading_prefix -4 |-import os - 7 |+ -5 8 | from . import leading_prefix - - + 1 |+import os +1 2 | import sys + 3 |+ +2 4 | import ruff + 5 |+from ruff import check + 6 |+ +3 7 | import leading_prefix +4 |-import os + 8 |+ + 9 |+from .. import trailing_prefix +5 10 | from . import leading_prefix +6 |-from .. import trailing_prefix +7 |-from ruff import check diff --git a/crates/ruff_linter/src/rules/isort/sorting.rs b/crates/ruff_linter/src/rules/isort/sorting.rs index 68d899bc61..479b5428d6 100644 --- a/crates/ruff_linter/src/rules/isort/sorting.rs +++ b/crates/ruff_linter/src/rules/isort/sorting.rs @@ -69,6 +69,7 @@ impl<'a> From for NatOrdStr<'a> { pub(crate) enum Distance { Nearest(u32), Furthest(Reverse), + None, } #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] @@ -101,17 +102,20 @@ impl<'a> ModuleKey<'a> { style: ImportStyle, settings: &Settings, ) -> Self { - let level = level.unwrap_or_default(); - let force_to_top = !name.is_some_and(|name| settings.force_to_top.contains(name)); // `false` < `true` so we get forced to top first let maybe_length = (settings.length_sort || (settings.length_sort_straight && style == ImportStyle::Straight)) - .then_some(name.map(str::width).unwrap_or_default() + level as usize); + .then_some( + name.map(str::width).unwrap_or_default() + level.unwrap_or_default() as usize, + ); - let distance = match settings.relative_imports_order { - RelativeImportsOrder::ClosestToFurthest => Distance::Nearest(level), - RelativeImportsOrder::FurthestToClosest => Distance::Furthest(Reverse(level)), + let distance = match level { + None | Some(0) => Distance::None, + Some(level) => match settings.relative_imports_order { + RelativeImportsOrder::ClosestToFurthest => Distance::Nearest(level), + RelativeImportsOrder::FurthestToClosest => Distance::Furthest(Reverse(level)), + }, }; let maybe_lowercase_name = name.and_then(|name| {