mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 15:15:33 +00:00
[isort
] Add support for length-sort settings (#8841)
## Summary Closes #1567. Add both `length-sort` and `length-sort-straight` settings for isort. Here are a few notable points: - The length is determined using the [`unicode_width`](https://crates.io/crates/unicode-width) crate, i.e. we are talking about displayed length (this is explicitly mentioned in the description of the setting) - The dots are taken into account in the length to be compatible with the original isort - I had to reorder a few fields of the module key struct for it all to make sense (notably the `force_to_top` field is now the first one) ## Test Plan I added tests for the following cases: - Basic tests for length-sort with ASCII characters only - Tests with non-ASCII characters - Tests with relative imports - Tests for length-sort-straight
This commit is contained in:
parent
ed14fd9163
commit
578ddf1bb1
22 changed files with 417 additions and 12 deletions
3
crates/ruff_linter/resources/test/fixtures/isort/length_sort_from_imports.py
vendored
Normal file
3
crates/ruff_linter/resources/test/fixtures/isort/length_sort_from_imports.py
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from mediuuuuuuuuuuum import a
|
||||||
|
from short import b
|
||||||
|
from loooooooooooooooooooooog import c
|
11
crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_members.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_members.py
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from module1 import (
|
||||||
|
loooooooooooooong,
|
||||||
|
σηορτ,
|
||||||
|
mediuuuuum,
|
||||||
|
shoort,
|
||||||
|
looooooooooooooong,
|
||||||
|
μεδιυυυυυμ,
|
||||||
|
short,
|
||||||
|
mediuuuuuum,
|
||||||
|
λοοοοοοοοοοοοοονγ,
|
||||||
|
)
|
9
crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_modules.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_modules.py
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import loooooooooooooong
|
||||||
|
import mediuuuuuum
|
||||||
|
import short
|
||||||
|
import σηορτ
|
||||||
|
import shoort
|
||||||
|
import mediuuuuum
|
||||||
|
import λοοοοοοοοοοοοοονγ
|
||||||
|
import μεδιυυυυυμ
|
||||||
|
import looooooooooooooong
|
6
crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_and_from_imports.py
vendored
Normal file
6
crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_and_from_imports.py
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import mediuuuuuum
|
||||||
|
import short
|
||||||
|
import looooooooooooooooong
|
||||||
|
from looooooooooooooong import a
|
||||||
|
from mediuuuum import c
|
||||||
|
from short import b
|
4
crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_imports.py
vendored
Normal file
4
crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_imports.py
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import mediuuuuuumb
|
||||||
|
import short
|
||||||
|
import looooooooooooooooong
|
||||||
|
import mediuuuuuuma
|
7
crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_relative_imports.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_relative_imports.py
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from ..looooooooooooooong import a
|
||||||
|
from ...mediuuuum import b
|
||||||
|
from .short import c
|
||||||
|
from ....short import c
|
||||||
|
from . import d
|
||||||
|
from .mediuuuum import a
|
||||||
|
from ......short import b
|
3
crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_star_import.py
vendored
Normal file
3
crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_star_import.py
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from looooooooooooooong import a
|
||||||
|
from mediuuuum import *
|
||||||
|
from short import *
|
|
@ -1138,4 +1138,47 @@ mod tests {
|
||||||
assert_messages!(diagnostics);
|
assert_messages!(diagnostics);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(Path::new("length_sort_straight_imports.py"))]
|
||||||
|
#[test_case(Path::new("length_sort_from_imports.py"))]
|
||||||
|
#[test_case(Path::new("length_sort_straight_and_from_imports.py"))]
|
||||||
|
#[test_case(Path::new("length_sort_non_ascii_members.py"))]
|
||||||
|
#[test_case(Path::new("length_sort_non_ascii_modules.py"))]
|
||||||
|
#[test_case(Path::new("length_sort_with_relative_imports.py"))]
|
||||||
|
fn length_sort(path: &Path) -> Result<()> {
|
||||||
|
let snapshot = format!("length_sort__{}", path.to_string_lossy());
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("isort").join(path).as_path(),
|
||||||
|
&LinterSettings {
|
||||||
|
isort: super::settings::Settings {
|
||||||
|
length_sort: 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("length_sort_straight_imports.py"))]
|
||||||
|
#[test_case(Path::new("length_sort_from_imports.py"))]
|
||||||
|
#[test_case(Path::new("length_sort_straight_and_from_imports.py"))]
|
||||||
|
fn length_sort_straight(path: &Path) -> Result<()> {
|
||||||
|
let snapshot = format!("length_sort_straight__{}", path.to_string_lossy());
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("isort").join(path).as_path(),
|
||||||
|
&LinterSettings {
|
||||||
|
isort: super::settings::Settings {
|
||||||
|
length_sort_straight: true,
|
||||||
|
..super::settings::Settings::default()
|
||||||
|
},
|
||||||
|
src: vec![test_resource_path("fixtures/isort")],
|
||||||
|
..LinterSettings::for_rule(Rule::UnsortedImports)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
assert_messages!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::rules::isort::sorting::ImportStyle;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::settings::Settings;
|
use super::settings::Settings;
|
||||||
|
@ -56,21 +57,34 @@ pub(crate) fn order_imports<'a>(
|
||||||
.map(Import)
|
.map(Import)
|
||||||
.chain(from_imports.map(ImportFrom))
|
.chain(from_imports.map(ImportFrom))
|
||||||
.sorted_by_cached_key(|import| match import {
|
.sorted_by_cached_key(|import| match import {
|
||||||
Import((alias, _)) => {
|
Import((alias, _)) => ModuleKey::from_module(
|
||||||
ModuleKey::from_module(Some(alias.name), alias.asname, None, None, settings)
|
Some(alias.name),
|
||||||
}
|
alias.asname,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
ImportStyle::Straight,
|
||||||
|
settings,
|
||||||
|
),
|
||||||
ImportFrom((import_from, _, _, aliases)) => ModuleKey::from_module(
|
ImportFrom((import_from, _, _, aliases)) => ModuleKey::from_module(
|
||||||
import_from.module,
|
import_from.module,
|
||||||
None,
|
None,
|
||||||
import_from.level,
|
import_from.level,
|
||||||
aliases.first().map(|(alias, _)| (alias.name, alias.asname)),
|
aliases.first().map(|(alias, _)| (alias.name, alias.asname)),
|
||||||
|
ImportStyle::From,
|
||||||
settings,
|
settings,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let ordered_straight_imports = straight_imports.sorted_by_cached_key(|(alias, _)| {
|
let ordered_straight_imports = straight_imports.sorted_by_cached_key(|(alias, _)| {
|
||||||
ModuleKey::from_module(Some(alias.name), alias.asname, None, None, settings)
|
ModuleKey::from_module(
|
||||||
|
Some(alias.name),
|
||||||
|
alias.asname,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
ImportStyle::Straight,
|
||||||
|
settings,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
let ordered_from_imports =
|
let ordered_from_imports =
|
||||||
from_imports.sorted_by_cached_key(|(import_from, _, _, aliases)| {
|
from_imports.sorted_by_cached_key(|(import_from, _, _, aliases)| {
|
||||||
|
@ -79,6 +93,7 @@ pub(crate) fn order_imports<'a>(
|
||||||
None,
|
None,
|
||||||
import_from.level,
|
import_from.level,
|
||||||
aliases.first().map(|(alias, _)| (alias.name, alias.asname)),
|
aliases.first().map(|(alias, _)| (alias.name, alias.asname)),
|
||||||
|
ImportStyle::From,
|
||||||
settings,
|
settings,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,6 +58,8 @@ pub struct Settings {
|
||||||
pub section_order: Vec<ImportSection>,
|
pub section_order: Vec<ImportSection>,
|
||||||
pub no_sections: bool,
|
pub no_sections: bool,
|
||||||
pub from_first: bool,
|
pub from_first: bool,
|
||||||
|
pub length_sort: bool,
|
||||||
|
pub length_sort_straight: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
|
@ -86,6 +88,8 @@ impl Default for Settings {
|
||||||
section_order: ImportType::iter().map(ImportSection::Known).collect(),
|
section_order: ImportType::iter().map(ImportSection::Known).collect(),
|
||||||
no_sections: false,
|
no_sections: false,
|
||||||
from_first: false,
|
from_first: false,
|
||||||
|
length_sort: false,
|
||||||
|
length_sort_straight: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / from mediuuuuuuuuuuum import a
|
||||||
|
2 | | from short import b
|
||||||
|
3 | | from loooooooooooooooooooooog import c
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |+from short import b
|
||||||
|
1 2 | from mediuuuuuuuuuuum import a
|
||||||
|
2 |-from short import b
|
||||||
|
3 3 | from loooooooooooooooooooooog import c
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_non_ascii_members.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / from module1 import (
|
||||||
|
2 | | loooooooooooooong,
|
||||||
|
3 | | σηορτ,
|
||||||
|
4 | | mediuuuuum,
|
||||||
|
5 | | shoort,
|
||||||
|
6 | | looooooooooooooong,
|
||||||
|
7 | | μεδιυυυυυμ,
|
||||||
|
8 | | short,
|
||||||
|
9 | | mediuuuuuum,
|
||||||
|
10 | | λοοοοοοοοοοοοοονγ,
|
||||||
|
11 | | )
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | from module1 import (
|
||||||
|
2 |- loooooooooooooong,
|
||||||
|
2 |+ short,
|
||||||
|
3 3 | σηορτ,
|
||||||
|
4 |+ shoort,
|
||||||
|
4 5 | mediuuuuum,
|
||||||
|
5 |- shoort,
|
||||||
|
6 |- looooooooooooooong,
|
||||||
|
7 6 | μεδιυυυυυμ,
|
||||||
|
8 |- short,
|
||||||
|
9 7 | mediuuuuuum,
|
||||||
|
8 |+ loooooooooooooong,
|
||||||
|
10 9 | λοοοοοοοοοοοοοονγ,
|
||||||
|
10 |+ looooooooooooooong,
|
||||||
|
11 11 | )
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_non_ascii_modules.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import loooooooooooooong
|
||||||
|
2 | | import mediuuuuuum
|
||||||
|
3 | | import short
|
||||||
|
4 | | import σηορτ
|
||||||
|
5 | | import shoort
|
||||||
|
6 | | import mediuuuuum
|
||||||
|
7 | | import λοοοοοοοοοοοοοονγ
|
||||||
|
8 | | import μεδιυυυυυμ
|
||||||
|
9 | | import looooooooooooooong
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |-import loooooooooooooong
|
||||||
|
2 |-import mediuuuuuum
|
||||||
|
3 1 | import short
|
||||||
|
4 2 | import σηορτ
|
||||||
|
5 3 | import shoort
|
||||||
|
6 4 | import mediuuuuum
|
||||||
|
5 |+import μεδιυυυυυμ
|
||||||
|
6 |+import mediuuuuuum
|
||||||
|
7 |+import loooooooooooooong
|
||||||
|
7 8 | import λοοοοοοοοοοοοοονγ
|
||||||
|
8 |-import μεδιυυυυυμ
|
||||||
|
9 9 | import looooooooooooooong
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_straight_and_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import mediuuuuuum
|
||||||
|
2 | | import short
|
||||||
|
3 | | import looooooooooooooooong
|
||||||
|
4 | | from looooooooooooooong import a
|
||||||
|
5 | | from mediuuuum import c
|
||||||
|
6 | | from short import b
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |+import short
|
||||||
|
1 2 | import mediuuuuuum
|
||||||
|
2 |-import short
|
||||||
|
3 3 | import looooooooooooooooong
|
||||||
|
4 |-from looooooooooooooong import a
|
||||||
|
4 |+from short import b
|
||||||
|
5 5 | from mediuuuum import c
|
||||||
|
6 |-from short import b
|
||||||
|
6 |+from looooooooooooooong import a
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_straight_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import mediuuuuuumb
|
||||||
|
2 | | import short
|
||||||
|
3 | | import looooooooooooooooong
|
||||||
|
4 | | import mediuuuuuuma
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |+import short
|
||||||
|
2 |+import mediuuuuuuma
|
||||||
|
1 3 | import mediuuuuuumb
|
||||||
|
2 |-import short
|
||||||
|
3 4 | import looooooooooooooooong
|
||||||
|
4 |-import mediuuuuuuma
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_with_relative_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / from ..looooooooooooooong import a
|
||||||
|
2 | | from ...mediuuuum import b
|
||||||
|
3 | | from .short import c
|
||||||
|
4 | | from ....short import c
|
||||||
|
5 | | from . import d
|
||||||
|
6 | | from .mediuuuum import a
|
||||||
|
7 | | from ......short import b
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |-from ..looooooooooooooong import a
|
||||||
|
2 |-from ...mediuuuum import b
|
||||||
|
1 |+from . import d
|
||||||
|
3 2 | from .short import c
|
||||||
|
4 3 | from ....short import c
|
||||||
|
5 |-from . import d
|
||||||
|
6 4 | from .mediuuuum import a
|
||||||
|
7 5 | from ......short import b
|
||||||
|
6 |+from ...mediuuuum import b
|
||||||
|
7 |+from ..looooooooooooooong import a
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / from mediuuuuuuuuuuum import a
|
||||||
|
2 | | from short import b
|
||||||
|
3 | | from loooooooooooooooooooooog import c
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |+from loooooooooooooooooooooog import c
|
||||||
|
1 2 | from mediuuuuuuuuuuum import a
|
||||||
|
2 3 | from short import b
|
||||||
|
3 |-from loooooooooooooooooooooog import c
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_straight_and_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import mediuuuuuum
|
||||||
|
2 | | import short
|
||||||
|
3 | | import looooooooooooooooong
|
||||||
|
4 | | from looooooooooooooong import a
|
||||||
|
5 | | from mediuuuum import c
|
||||||
|
6 | | from short import b
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |+import short
|
||||||
|
1 2 | import mediuuuuuum
|
||||||
|
2 |-import short
|
||||||
|
3 3 | import looooooooooooooooong
|
||||||
|
4 4 | from looooooooooooooong import a
|
||||||
|
5 5 | from mediuuuum import c
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/isort/mod.rs
|
||||||
|
---
|
||||||
|
length_sort_straight_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import mediuuuuuumb
|
||||||
|
2 | | import short
|
||||||
|
3 | | import looooooooooooooooong
|
||||||
|
4 | | import mediuuuuuuma
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 |+import short
|
||||||
|
2 |+import mediuuuuuuma
|
||||||
|
1 3 | import mediuuuuuumb
|
||||||
|
2 |-import short
|
||||||
|
3 4 | import looooooooooooooooong
|
||||||
|
4 |-import mediuuuuuuma
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use std::{borrow::Cow, cmp::Ordering, cmp::Reverse};
|
use std::{borrow::Cow, cmp::Ordering, cmp::Reverse};
|
||||||
|
|
||||||
use natord;
|
use natord;
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use ruff_python_stdlib::str;
|
use ruff_python_stdlib::str;
|
||||||
|
|
||||||
|
@ -64,18 +65,27 @@ impl<'a> From<String> for NatOrdStr<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
pub(crate) enum Distance {
|
pub(crate) enum Distance {
|
||||||
Nearest(u32),
|
Nearest(u32),
|
||||||
Furthest(Reverse<u32>),
|
Furthest(Reverse<u32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
|
pub(crate) enum ImportStyle {
|
||||||
|
// Ex) `import foo`
|
||||||
|
Straight,
|
||||||
|
// Ex) `from foo import bar`
|
||||||
|
From,
|
||||||
|
}
|
||||||
|
|
||||||
/// A comparable key to capture the desired sorting order for an imported module (e.g.,
|
/// A comparable key to capture the desired sorting order for an imported module (e.g.,
|
||||||
/// `foo` in `from foo import bar`).
|
/// `foo` in `from foo import bar`).
|
||||||
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
pub(crate) struct ModuleKey<'a> {
|
pub(crate) struct ModuleKey<'a> {
|
||||||
|
force_to_top: bool,
|
||||||
|
maybe_length: Option<usize>,
|
||||||
distance: Distance,
|
distance: Distance,
|
||||||
force_to_top: Option<bool>,
|
|
||||||
maybe_lowercase_name: Option<NatOrdStr<'a>>,
|
maybe_lowercase_name: Option<NatOrdStr<'a>>,
|
||||||
module_name: Option<NatOrdStr<'a>>,
|
module_name: Option<NatOrdStr<'a>>,
|
||||||
first_alias: Option<MemberKey<'a>>,
|
first_alias: Option<MemberKey<'a>>,
|
||||||
|
@ -88,26 +98,39 @@ impl<'a> ModuleKey<'a> {
|
||||||
asname: Option<&'a str>,
|
asname: Option<&'a str>,
|
||||||
level: Option<u32>,
|
level: Option<u32>,
|
||||||
first_alias: Option<(&'a str, Option<&'a str>)>,
|
first_alias: Option<(&'a str, Option<&'a str>)>,
|
||||||
|
style: ImportStyle,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let level = level.unwrap_or_default();
|
||||||
|
|
||||||
|
let force_to_top = !name
|
||||||
|
.map(|name| settings.force_to_top.contains(name))
|
||||||
|
.unwrap_or_default(); // `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);
|
||||||
|
|
||||||
let distance = match settings.relative_imports_order {
|
let distance = match settings.relative_imports_order {
|
||||||
RelativeImportsOrder::ClosestToFurthest => Distance::Nearest(level.unwrap_or_default()),
|
RelativeImportsOrder::ClosestToFurthest => Distance::Nearest(level),
|
||||||
RelativeImportsOrder::FurthestToClosest => {
|
RelativeImportsOrder::FurthestToClosest => Distance::Furthest(Reverse(level)),
|
||||||
Distance::Furthest(Reverse(level.unwrap_or_default()))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let force_to_top = name.map(|name| !settings.force_to_top.contains(name)); // `false` < `true` so we get forced to top first
|
|
||||||
let maybe_lowercase_name = name.and_then(|name| {
|
let maybe_lowercase_name = name.and_then(|name| {
|
||||||
(!settings.case_sensitive).then_some(NatOrdStr(maybe_lowercase(name)))
|
(!settings.case_sensitive).then_some(NatOrdStr(maybe_lowercase(name)))
|
||||||
});
|
});
|
||||||
|
|
||||||
let module_name = name.map(NatOrdStr::from);
|
let module_name = name.map(NatOrdStr::from);
|
||||||
|
|
||||||
let asname = asname.map(NatOrdStr::from);
|
let asname = asname.map(NatOrdStr::from);
|
||||||
|
|
||||||
let first_alias =
|
let first_alias =
|
||||||
first_alias.map(|(name, asname)| MemberKey::from_member(name, asname, settings));
|
first_alias.map(|(name, asname)| MemberKey::from_member(name, asname, settings));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
distance,
|
|
||||||
force_to_top,
|
force_to_top,
|
||||||
|
maybe_length,
|
||||||
|
distance,
|
||||||
maybe_lowercase_name,
|
maybe_lowercase_name,
|
||||||
module_name,
|
module_name,
|
||||||
first_alias,
|
first_alias,
|
||||||
|
@ -122,6 +145,7 @@ impl<'a> ModuleKey<'a> {
|
||||||
pub(crate) struct MemberKey<'a> {
|
pub(crate) struct MemberKey<'a> {
|
||||||
not_star_import: bool,
|
not_star_import: bool,
|
||||||
member_type: Option<MemberType>,
|
member_type: Option<MemberType>,
|
||||||
|
maybe_length: Option<usize>,
|
||||||
maybe_lowercase_name: Option<NatOrdStr<'a>>,
|
maybe_lowercase_name: Option<NatOrdStr<'a>>,
|
||||||
module_name: NatOrdStr<'a>,
|
module_name: NatOrdStr<'a>,
|
||||||
asname: Option<NatOrdStr<'a>>,
|
asname: Option<NatOrdStr<'a>>,
|
||||||
|
@ -133,6 +157,7 @@ impl<'a> MemberKey<'a> {
|
||||||
let member_type = settings
|
let member_type = settings
|
||||||
.order_by_type
|
.order_by_type
|
||||||
.then_some(member_type(name, settings));
|
.then_some(member_type(name, settings));
|
||||||
|
let maybe_length = settings.length_sort.then_some(name.width());
|
||||||
let maybe_lowercase_name =
|
let maybe_lowercase_name =
|
||||||
(!settings.case_sensitive).then_some(NatOrdStr(maybe_lowercase(name)));
|
(!settings.case_sensitive).then_some(NatOrdStr(maybe_lowercase(name)));
|
||||||
let module_name = NatOrdStr::from(name);
|
let module_name = NatOrdStr::from(name);
|
||||||
|
@ -141,6 +166,7 @@ impl<'a> MemberKey<'a> {
|
||||||
Self {
|
Self {
|
||||||
not_star_import,
|
not_star_import,
|
||||||
member_type,
|
member_type,
|
||||||
|
maybe_length,
|
||||||
maybe_lowercase_name,
|
maybe_lowercase_name,
|
||||||
module_name,
|
module_name,
|
||||||
asname,
|
asname,
|
||||||
|
|
|
@ -2047,6 +2047,40 @@ pub struct IsortOptions {
|
||||||
)]
|
)]
|
||||||
pub from_first: Option<bool>,
|
pub from_first: Option<bool>,
|
||||||
|
|
||||||
|
/// Sort imports by their string length, such that shorter imports appear
|
||||||
|
/// before longer imports. For example, by default, imports will be sorted
|
||||||
|
/// alphabetically, as in:
|
||||||
|
/// ```python
|
||||||
|
/// import collections
|
||||||
|
/// import os
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Setting `length-sort = true` will instead sort such that shorter imports
|
||||||
|
/// appear before longer imports, as in:
|
||||||
|
/// ```python
|
||||||
|
/// import os
|
||||||
|
/// import collections
|
||||||
|
/// ```
|
||||||
|
#[option(
|
||||||
|
default = r#"false"#,
|
||||||
|
value_type = "bool",
|
||||||
|
example = r#"
|
||||||
|
length-sort = true
|
||||||
|
"#
|
||||||
|
)]
|
||||||
|
pub length_sort: Option<bool>,
|
||||||
|
|
||||||
|
/// Sort straight imports by their string length. Similar to `length-sort`,
|
||||||
|
/// but applies only to straight imports and doesn't affect `from` imports.
|
||||||
|
#[option(
|
||||||
|
default = r#"false"#,
|
||||||
|
value_type = "bool",
|
||||||
|
example = r#"
|
||||||
|
length-sort-straight = true
|
||||||
|
"#
|
||||||
|
)]
|
||||||
|
pub length_sort_straight: Option<bool>,
|
||||||
|
|
||||||
// Tables are required to go last.
|
// Tables are required to go last.
|
||||||
/// A list of mappings from section names to modules.
|
/// A list of mappings from section names to modules.
|
||||||
/// By default custom sections are output last, but this can be overridden with `section-order`.
|
/// By default custom sections are output last, but this can be overridden with `section-order`.
|
||||||
|
@ -2234,6 +2268,8 @@ impl IsortOptions {
|
||||||
section_order,
|
section_order,
|
||||||
no_sections,
|
no_sections,
|
||||||
from_first,
|
from_first,
|
||||||
|
length_sort: self.length_sort.unwrap_or(false),
|
||||||
|
length_sort_straight: self.length_sort_straight.unwrap_or(false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
ruff.schema.json
generated
14
ruff.schema.json
generated
|
@ -1477,6 +1477,20 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"length-sort": {
|
||||||
|
"description": "Sort imports by their string length, such that shorter imports appear before longer imports. For example, by default, imports will be sorted alphabetically, as in: ```python import collections import os ```\n\nSetting `length-sort = true` will instead sort such that shorter imports appear before longer imports, as in: ```python import os import collections ```",
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"length-sort-straight": {
|
||||||
|
"description": "Sort straight imports by their string length. Similar to `length-sort`, but applies only to straight imports and doesn't affect `from` imports.",
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
"lines-after-imports": {
|
"lines-after-imports": {
|
||||||
"description": "The number of blank lines to place after imports. Use `-1` for automatic determination.\n\nWhen using the formatter, only the values `-1`, `1`, and `2` are compatible because it enforces at least one empty and at most two empty lines after imports.",
|
"description": "The number of blank lines to place after imports. Use `-1` for automatic determination.\n\nWhen using the formatter, only the values `-1`, `1`, and `2` are compatible because it enforces at least one empty and at most two empty lines after imports.",
|
||||||
"type": [
|
"type": [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue