Limit `isort.lines-after-imports` to 1 for stub files (#9971)

This commit is contained in:
Micha Reiser 2024-02-28 17:36:51 +01:00 committed by GitHub
parent 317d2e4c75
commit 1791e7d73b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 228 additions and 2 deletions

View File

@ -0,0 +1,16 @@
from __future__ import annotations
from typing import Any
from requests import Session
from my_first_party import my_first_party_object
from . import my_local_folder_object
class Thing(object):
name: str
def __init__(self, name: str):
self.name = name

View File

@ -108,7 +108,17 @@ pub(crate) fn format_imports(
output.push_str(block_output.as_str());
}
let lines_after_imports = settings.lines_after_imports;
let lines_after_imports = if source_type.is_stub() {
// Limit the number of lines after imports in stub files to at most 1 to be compatible with the formatter.
// `isort` does the same when using the profile `isort`
match settings.lines_after_imports {
0 => 0,
_ => 1,
}
} else {
settings.lines_after_imports
};
match trailer {
None => {}
Some(Trailer::Sibling) => {
@ -975,6 +985,7 @@ mod tests {
}
#[test_case(Path::new("lines_after_imports_nothing_after.py"))]
#[test_case(Path::new("lines_after_imports.pyi"))]
#[test_case(Path::new("lines_after_imports_func_after.py"))]
#[test_case(Path::new("lines_after_imports_class_after.py"))]
fn lines_after_imports(path: &Path) -> Result<()> {
@ -995,6 +1006,27 @@ mod tests {
Ok(())
}
#[test_case(Path::new("lines_after_imports.pyi"))]
#[test_case(Path::new("lines_after_imports_func_after.py"))]
#[test_case(Path::new("lines_after_imports_class_after.py"))]
fn lines_after_imports_default_settings(path: &Path) -> Result<()> {
let snapshot = path.to_string_lossy();
let mut diagnostics = test_path(
Path::new("isort").join(path).as_path(),
&LinterSettings {
src: vec![test_resource_path("fixtures/isort")],
isort: super::settings::Settings {
lines_after_imports: -1,
..super::settings::Settings::default()
},
..LinterSettings::for_rule(Rule::UnsortedImports)
},
)?;
diagnostics.sort_by_key(Ranged::start);
assert_messages!(*snapshot, diagnostics);
Ok(())
}
#[test_case(Path::new("lines_between_types.py"))]
fn lines_between_types(path: &Path) -> Result<()> {
let snapshot = format!("lines_between_types{}", path.to_string_lossy());

View File

@ -0,0 +1,41 @@
---
source: crates/ruff_linter/src/rules/isort/mod.rs
---
lines_after_imports.pyi:1:1: I001 [*] Import block is un-sorted or un-formatted
|
1 | / from __future__ import annotations
2 | |
3 | | from typing import Any
4 | |
5 | | from requests import Session
6 | |
7 | | from my_first_party import my_first_party_object
8 | |
9 | | from . import my_local_folder_object
10 | |
11 | |
12 | |
13 | | class Thing(object):
| |_^ I001
14 | name: str
15 | def __init__(self, name: str):
|
= help: Organize imports
Safe fix
2 2 |
3 3 | from typing import Any
4 4 |
5 |-from requests import Session
6 |-
7 5 | from my_first_party import my_first_party_object
6 |+from requests import Session
8 7 |
9 8 | from . import my_local_folder_object
10 |-
11 |-
12 9 |
13 10 | class Thing(object):
14 11 | name: str

View File

@ -0,0 +1,38 @@
---
source: crates/ruff_linter/src/rules/isort/mod.rs
---
lines_after_imports_class_after.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
1 | / from __future__ import annotations
2 | |
3 | | from typing import Any
4 | |
5 | | from requests import Session
6 | |
7 | | from my_first_party import my_first_party_object
8 | |
9 | | from . import my_local_folder_object
10 | | class Thing(object):
| |_^ I001
11 | name: str
12 | def __init__(self, name: str):
|
= help: Organize imports
Safe fix
2 2 |
3 3 | from typing import Any
4 4 |
5 |-from requests import Session
6 |-
7 5 | from my_first_party import my_first_party_object
6 |+from requests import Session
8 7 |
9 8 | from . import my_local_folder_object
9 |+
10 |+
10 11 | class Thing(object):
11 12 | name: str
12 13 | def __init__(self, name: str):

View File

@ -0,0 +1,55 @@
---
source: crates/ruff_linter/src/rules/isort/mod.rs
---
lines_after_imports_func_after.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
1 | / from __future__ import annotations
2 | |
3 | | from typing import Any
4 | |
5 | | from requests import Session
6 | |
7 | | from my_first_party import my_first_party_object
8 | |
9 | | from . import my_local_folder_object
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | | def main():
| |_^ I001
22 | my_local_folder_object.get()
|
= help: Organize imports
Safe fix
2 2 |
3 3 | from typing import Any
4 4 |
5 |-from requests import Session
6 |-
7 5 | from my_first_party import my_first_party_object
6 |+from requests import Session
8 7 |
9 8 | from . import my_local_folder_object
10 |-
11 |-
12 |-
13 |-
14 |-
15 |-
16 |-
17 |-
18 |-
19 9 |
20 10 |
21 11 | def main():

View File

@ -0,0 +1,41 @@
---
source: crates/ruff_linter/src/rules/isort/mod.rs
---
lines_after_imports.pyi:1:1: I001 [*] Import block is un-sorted or un-formatted
|
1 | / from __future__ import annotations
2 | |
3 | | from typing import Any
4 | |
5 | | from requests import Session
6 | |
7 | | from my_first_party import my_first_party_object
8 | |
9 | | from . import my_local_folder_object
10 | |
11 | |
12 | |
13 | | class Thing(object):
| |_^ I001
14 | name: str
15 | def __init__(self, name: str):
|
= help: Organize imports
Safe fix
2 2 |
3 3 | from typing import Any
4 4 |
5 |-from requests import Session
6 |-
7 5 | from my_first_party import my_first_party_object
6 |+from requests import Session
8 7 |
9 8 | from . import my_local_folder_object
10 |-
11 |-
12 9 |
13 10 | class Thing(object):
14 11 | name: str

View File

@ -2049,6 +2049,9 @@ pub struct IsortOptions {
/// The number of blank lines to place after imports.
/// Use `-1` for automatic determination.
///
/// Ruff uses at most one blank line after imports in typing stub files (files with `.pyi` extension) in accordance to
/// the typing style recommendations ([source](https://typing.readthedocs.io/en/latest/source/stubs.html#blank-lines)).
///
/// When 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.
#[option(

2
ruff.schema.json generated
View File

@ -1584,7 +1584,7 @@
]
},
"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\nRuff uses at most one blank line after imports in typing stub files (files with `.pyi` extension) in accordance to the typing style recommendations ([source](https://typing.readthedocs.io/en/latest/source/stubs.html#blank-lines)).\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": [
"integer",
"null"