From d00bb85d8e11f09a3461b314031df143e6d186a4 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Tue, 13 Feb 2024 09:30:29 +0100 Subject: [PATCH] Limit `isort.lines-after-imports` to 1 for stub files --- .../fixtures/isort/lines_after_imports.pyi | 16 ++++++++ crates/ruff_linter/src/rules/isort/mod.rs | 10 ++++- ...after_imports_lines_after_imports.pyi.snap | 41 +++++++++++++++++++ crates/ruff_workspace/src/options.rs | 3 ++ ruff.schema.json | 2 +- 5 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/lines_after_imports.pyi create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__lines_after_imports_lines_after_imports.pyi.snap diff --git a/crates/ruff_linter/resources/test/fixtures/isort/lines_after_imports.pyi b/crates/ruff_linter/resources/test/fixtures/isort/lines_after_imports.pyi new file mode 100644 index 00000000000000..83d24dd8b11f22 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/lines_after_imports.pyi @@ -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 diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index d77a818aa8fff3..9526a9e770eff2 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -108,7 +108,14 @@ 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 1 to be compatible with the formatter similar to `isort` + // when using the profile `black`. + settings.lines_after_imports.min(1) + } else { + settings.lines_after_imports + }; + match trailer { None => {} Some(Trailer::Sibling) => { @@ -978,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<()> { diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__lines_after_imports_lines_after_imports.pyi.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__lines_after_imports_lines_after_imports.pyi.snap new file mode 100644 index 00000000000000..3cb4eb573c315c --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__lines_after_imports_lines_after_imports.pyi.snap @@ -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 + + diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 89be64b5ebed17..42ebefc1dfbb32 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2049,6 +2049,9 @@ pub struct IsortOptions { /// The number of blank lines to place after imports. /// Use `-1` for automatic determination. /// + /// The number of blank lines in typing stub files with `.pyi` extension is limited to at most one in accordance to + /// the stub file style recommendations ([source](https://github.com/python/typeshed/blob/main/CONTRIBUTING.md#stub-file-coding-style)). + /// /// 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( diff --git a/ruff.schema.json b/ruff.schema.json index 369c973256cc50..19870b3459af2a 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -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\nThe number of blank lines in typing stub files with `.pyi` extension is limited to at most one in accordance to the stub file style recommendations ([source](https://github.com/python/typeshed/blob/main/CONTRIBUTING.md#stub-file-coding-style)).\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"