mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 22:54:42 +00:00
Always place non-relative imports after relative imports (#10669)
## Summary When `relative-imports-order = "closest-to-furthest"` is set, we should _still_ put non-relative imports after relative imports. It's rare for them to be in the same section, but _possible_ if you use `known-local-folder`. Closes https://github.com/astral-sh/ruff/issues/10655. ## Test Plan New tests. Also sorted this file: ```python from ..models import ABC from .models import Question from .utils import create_question from django_polls.apps.polls.models import Choice ``` With both: - `isort view.py` - `ruff check view.py --select I --fix` And the following `pyproject.toml`: ```toml [tool.ruff.lint.isort] order-by-type = false relative-imports-order = "closest-to-furthest" known-local-folder = ["django_polls"] [tool.isort] profile = "black" reverse_relative = true known_local_folder = ["django_polls"] ``` I verified that Ruff and isort gave the same result, and that they _still_ gave the same result when removing the relevant setting: ```toml [tool.ruff.lint.isort] order-by-type = false known-local-folder = ["django_polls"] [tool.isort] profile = "black" known_local_folder = ["django_polls"] ```
This commit is contained in:
parent
fc54f53662
commit
75e01420fa
6 changed files with 85 additions and 20 deletions
|
@ -3,3 +3,5 @@ import ruff
|
|||
import leading_prefix
|
||||
import os
|
||||
from . import leading_prefix
|
||||
from .. import trailing_prefix
|
||||
from ruff import check
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -69,6 +69,7 @@ impl<'a> From<String> for NatOrdStr<'a> {
|
|||
pub(crate) enum Distance {
|
||||
Nearest(u32),
|
||||
Furthest(Reverse<u32>),
|
||||
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| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue