mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:48 +00:00
Use single newlines in .pyi import sorting (#1142)
This commit is contained in:
parent
e338d9acbe
commit
49df43bb78
6 changed files with 148 additions and 25 deletions
41
resources/test/fixtures/isort/insert_empty_lines.pyi
vendored
Normal file
41
resources/test/fixtures/isort/insert_empty_lines.pyi
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import a
|
||||||
|
import b
|
||||||
|
x = 1
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
if True:
|
||||||
|
x = 1
|
||||||
|
import collections
|
||||||
|
import typing
|
||||||
|
class X: pass
|
||||||
|
y = 1
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
"""Docstring"""
|
||||||
|
|
||||||
|
if True:
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if True:
|
||||||
|
import os
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
|
||||||
|
if True:
|
||||||
|
x = 1
|
||||||
|
import collections
|
||||||
|
import typing
|
||||||
|
class X: pass
|
||||||
|
|
||||||
|
if True:
|
||||||
|
x = 1
|
||||||
|
import collections
|
||||||
|
import typing
|
||||||
|
def f(): pass
|
|
@ -1,5 +1,7 @@
|
||||||
//! Lint rules based on import analysis.
|
//! Lint rules based on import analysis.
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use rustpython_parser::ast::Suite;
|
use rustpython_parser::ast::Suite;
|
||||||
|
|
||||||
use crate::ast::visitor::Visitor;
|
use crate::ast::visitor::Visitor;
|
||||||
|
@ -33,8 +35,9 @@ pub fn check_imports(
|
||||||
directives: &IsortDirectives,
|
directives: &IsortDirectives,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
autofix: bool,
|
autofix: bool,
|
||||||
|
path: &Path,
|
||||||
) -> Vec<Check> {
|
) -> Vec<Check> {
|
||||||
let mut tracker = ImportTracker::new(directives);
|
let mut tracker = ImportTracker::new(directives, path);
|
||||||
for stmt in python_ast {
|
for stmt in python_ast {
|
||||||
tracker.visit_stmt(stmt);
|
tracker.visit_stmt(stmt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -559,6 +559,7 @@ mod tests {
|
||||||
#[test_case(Path::new("force_wrap_aliases.py"))]
|
#[test_case(Path::new("force_wrap_aliases.py"))]
|
||||||
#[test_case(Path::new("import_from_after_import.py"))]
|
#[test_case(Path::new("import_from_after_import.py"))]
|
||||||
#[test_case(Path::new("insert_empty_lines.py"))]
|
#[test_case(Path::new("insert_empty_lines.py"))]
|
||||||
|
#[test_case(Path::new("insert_empty_lines.pyi"))]
|
||||||
#[test_case(Path::new("leading_prefix.py"))]
|
#[test_case(Path::new("leading_prefix.py"))]
|
||||||
#[test_case(Path::new("no_reorder_within_section.py"))]
|
#[test_case(Path::new("no_reorder_within_section.py"))]
|
||||||
#[test_case(Path::new("no_wrap_star.py"))]
|
#[test_case(Path::new("no_wrap_star.py"))]
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
---
|
||||||
|
source: src/isort/mod.rs
|
||||||
|
expression: checks
|
||||||
|
---
|
||||||
|
- kind: UnsortedImports
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 3
|
||||||
|
column: 0
|
||||||
|
fix:
|
||||||
|
content: "import a\nimport b\n\n"
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 3
|
||||||
|
column: 0
|
||||||
|
- kind: UnsortedImports
|
||||||
|
location:
|
||||||
|
row: 4
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 6
|
||||||
|
column: 0
|
||||||
|
fix:
|
||||||
|
content: "import os\nimport sys\n\n"
|
||||||
|
location:
|
||||||
|
row: 4
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 6
|
||||||
|
column: 0
|
||||||
|
- kind: UnsortedImports
|
||||||
|
location:
|
||||||
|
row: 14
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 16
|
||||||
|
column: 0
|
||||||
|
fix:
|
||||||
|
content: "import os\nimport sys\n\n"
|
||||||
|
location:
|
||||||
|
row: 14
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 16
|
||||||
|
column: 0
|
||||||
|
- kind: UnsortedImports
|
||||||
|
location:
|
||||||
|
row: 33
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 35
|
||||||
|
column: 0
|
||||||
|
fix:
|
||||||
|
content: " import collections\n import typing\n\n"
|
||||||
|
location:
|
||||||
|
row: 33
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 35
|
||||||
|
column: 0
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use rustpython_ast::{
|
use rustpython_ast::{
|
||||||
Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler,
|
Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler,
|
||||||
ExcepthandlerKind, Expr, ExprContext, Keyword, MatchCase, Operator, Pattern, Stmt, StmtKind,
|
ExcepthandlerKind, Expr, ExprContext, Keyword, MatchCase, Operator, Pattern, Stmt, StmtKind,
|
||||||
|
@ -20,16 +22,18 @@ pub struct Block<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ImportTracker<'a> {
|
pub struct ImportTracker<'a> {
|
||||||
blocks: Vec<Block<'a>>,
|
|
||||||
directives: &'a IsortDirectives,
|
directives: &'a IsortDirectives,
|
||||||
|
pyi: bool,
|
||||||
|
blocks: Vec<Block<'a>>,
|
||||||
split_index: usize,
|
split_index: usize,
|
||||||
nested: bool,
|
nested: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ImportTracker<'a> {
|
impl<'a> ImportTracker<'a> {
|
||||||
pub fn new(directives: &'a IsortDirectives) -> Self {
|
pub fn new(directives: &'a IsortDirectives, path: &'a Path) -> Self {
|
||||||
Self {
|
Self {
|
||||||
directives,
|
directives,
|
||||||
|
pyi: path.extension().map_or(false, |ext| ext == "pyi"),
|
||||||
blocks: vec![Block::default()],
|
blocks: vec![Block::default()],
|
||||||
split_index: 0,
|
split_index: 0,
|
||||||
nested: false,
|
nested: false,
|
||||||
|
@ -41,6 +45,34 @@ impl<'a> ImportTracker<'a> {
|
||||||
self.blocks[index].imports.push(stmt);
|
self.blocks[index].imports.push(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trailer_for(&self, stmt: &'a Stmt) -> Option<Trailer> {
|
||||||
|
if self.pyi {
|
||||||
|
// Black treats interface files differently, limiting to one newline
|
||||||
|
// (`Trailing::Sibling`), and avoiding inserting any newlines in nested function
|
||||||
|
// blocks.
|
||||||
|
if self.nested
|
||||||
|
&& matches!(
|
||||||
|
stmt.node,
|
||||||
|
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. }
|
||||||
|
)
|
||||||
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Trailer::Sibling)
|
||||||
|
}
|
||||||
|
} else if self.nested {
|
||||||
|
Some(Trailer::Sibling)
|
||||||
|
} else {
|
||||||
|
Some(match &stmt.node {
|
||||||
|
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
|
||||||
|
Trailer::FunctionDef
|
||||||
|
}
|
||||||
|
StmtKind::ClassDef { .. } => Trailer::ClassDef,
|
||||||
|
_ => Trailer::Sibling,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn finalize(&mut self, trailer: Option<Trailer>) {
|
fn finalize(&mut self, trailer: Option<Trailer>) {
|
||||||
let index = self.blocks.len() - 1;
|
let index = self.blocks.len() - 1;
|
||||||
if !self.blocks[index].imports.is_empty() {
|
if !self.blocks[index].imports.is_empty() {
|
||||||
|
@ -62,17 +94,7 @@ where
|
||||||
// Track manual splits.
|
// Track manual splits.
|
||||||
while self.split_index < self.directives.splits.len() {
|
while self.split_index < self.directives.splits.len() {
|
||||||
if stmt.location.row() >= self.directives.splits[self.split_index] {
|
if stmt.location.row() >= self.directives.splits[self.split_index] {
|
||||||
self.finalize(Some(if self.nested {
|
self.finalize(self.trailer_for(stmt));
|
||||||
Trailer::Sibling
|
|
||||||
} else {
|
|
||||||
match &stmt.node {
|
|
||||||
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
|
|
||||||
Trailer::FunctionDef
|
|
||||||
}
|
|
||||||
StmtKind::ClassDef { .. } => Trailer::ClassDef,
|
|
||||||
_ => Trailer::Sibling,
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
self.split_index += 1;
|
self.split_index += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -87,17 +109,7 @@ where
|
||||||
{
|
{
|
||||||
self.track_import(stmt);
|
self.track_import(stmt);
|
||||||
} else {
|
} else {
|
||||||
self.finalize(Some(if self.nested {
|
self.finalize(self.trailer_for(stmt));
|
||||||
Trailer::Sibling
|
|
||||||
} else {
|
|
||||||
match &stmt.node {
|
|
||||||
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
|
|
||||||
Trailer::FunctionDef
|
|
||||||
}
|
|
||||||
StmtKind::ClassDef { .. } => Trailer::ClassDef,
|
|
||||||
_ => Trailer::Sibling,
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track scope.
|
// Track scope.
|
||||||
|
|
|
@ -92,6 +92,7 @@ pub(crate) fn check_path(
|
||||||
&directives.isort,
|
&directives.isort,
|
||||||
settings,
|
settings,
|
||||||
autofix,
|
autofix,
|
||||||
|
path,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue