Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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
34 changes: 33 additions & 1 deletion crates/ruff_linter/src/rules/isort/mod.rs
Expand Up @@ -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) => {
Expand Down Expand Up @@ -978,6 +988,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<()> {
Expand All @@ -998,6 +1009,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());
Expand Down
@@ -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


@@ -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):


@@ -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():


@@ -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


3 changes: 3 additions & 0 deletions crates/ruff_workspace/src/options.rs
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion ruff.schema.json

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