Skip to content

Commit

Permalink
isort: Add support for the from-first setting
Browse files Browse the repository at this point in the history
This setting behaves similarly to the ``from_first`` setting in isort
upstream, and sorts "from X import Y" type imports before straight
imports.

Fixes #8662
  • Loading branch information
jelmer committed Nov 13, 2023
1 parent 3592f44 commit bbebe81
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from __future__import blah

from os import path

import os
40 changes: 35 additions & 5 deletions crates/ruff_linter/src/rules/isort/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,23 @@ fn format_import_block(

let imports = order_imports(import_block, settings);

let imports = imports
.import
.into_iter()
.map(Import)
.chain(imports.import_from.into_iter().map(ImportFrom));
let imports = if settings.from_first {
Box::new(
imports
.import_from
.into_iter()
.map(ImportFrom)
.chain(imports.import.into_iter().map(Import)),
) as Box<dyn Iterator<Item = EitherImport>>
} else {
Box::new(
imports
.import
.into_iter()
.map(Import)
.chain(imports.import_from.into_iter().map(ImportFrom)),
) as Box<dyn Iterator<Item = EitherImport>>
};
let imports: Vec<EitherImport> = if settings.force_sort_within_sections {
imports
.sorted_by_cached_key(|import| match import {
Expand Down Expand Up @@ -844,6 +856,24 @@ mod tests {
Ok(())
}

#[test_case(Path::new("from_first.py"))]
fn from_first(path: &Path) -> Result<()> {
let snapshot = format!("from_first_{}", path.to_string_lossy());
let diagnostics = test_path(
Path::new("isort").join(path).as_path(),
&LinterSettings {
isort: super::settings::Settings {
from_first: true,
..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("relative_imports_order.py"))]
fn closest_to_furthest(path: &Path) -> Result<()> {
let snapshot = format!("closest_to_furthest_{}", path.to_string_lossy());
Expand Down
2 changes: 2 additions & 0 deletions crates/ruff_linter/src/rules/isort/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub struct Settings {
pub lines_between_types: usize,
pub forced_separate: Vec<String>,
pub section_order: Vec<ImportSection>,
pub from_first: bool,
}

impl Default for Settings {
Expand All @@ -82,6 +83,7 @@ impl Default for Settings {
lines_between_types: 0,
forced_separate: Vec::new(),
section_order: ImportType::iter().map(ImportSection::Known).collect(),
from_first: false,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/isort/mod.rs
---

12 changes: 12 additions & 0 deletions crates/ruff_workspace/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1994,6 +1994,16 @@ pub struct IsortOptions {
)]
pub detect_same_package: Option<bool>,

/// Sort "from .. import .." imports before straight imports
#[option(
default = r#"false"#,
value_type = "bool",
example = r#"
from-first = true
"#
)]
pub from_first: Option<bool>,

// Tables are required to go last.
/// A list of mappings from section names to modules.
/// By default custom sections are output last, but this can be overridden with `section-order`.
Expand Down Expand Up @@ -2062,6 +2072,7 @@ impl IsortOptions {
.map_err(isort::settings::SettingsError::InvalidExtraStandardLibrary)?
.unwrap_or_default();
let no_lines_before = self.no_lines_before.unwrap_or_default();
let from_first = self.from_first.unwrap_or_default();
let sections = self.sections.unwrap_or_default();

// Verify that `sections` doesn't contain any built-in sections.
Expand Down Expand Up @@ -2169,6 +2180,7 @@ impl IsortOptions {
lines_between_types: self.lines_between_types.unwrap_or_default(),
forced_separate: Vec::from_iter(self.forced_separate.unwrap_or_default()),
section_order,
from_first,
})
}
}
Expand Down
7 changes: 7 additions & 0 deletions ruff.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit bbebe81

Please sign in to comment.