mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 22:31:47 +00:00
[pycodestyle
] Respect isort
settings in blank line rules (E3*
) (#10096)
## Summary This PR changes the `E3*` rules to respect the `isort` `lines-after-imports` and `lines-between-types` settings. Specifically, the following rules required changing * `TooManyBlannkLines` : Respects both settings. * `BlankLinesTopLevel`: Respects `lines-after-imports`. Doesn't need to respect `lines-between-types` because it only applies to classes and functions The downside of this approach is that `isort` and the blank line rules emit a diagnostic when there are too many blank lines. The fixes aren't identical, the blank line is less opinionated, but blank lines accepts the fix of `isort`. <details> <summary>Outdated approach</summary> Fixes https://github.com/astral-sh/ruff/issues/10077#issuecomment-1961266981 This PR changes the blank line rules to not enforce the number of blank lines after imports (top-level) if isort is enabled and leave it to isort to enforce the right number of lines (depends on the `isort.lines-after-imports` and `isort.lines-between-types` settings). The reason to give `isort` precedence over the blank line rules is that they are configurable. Users that always want to blank lines after imports can use `isort.lines-after-imports=2` to enforce that (specifically for imports). This PR does not fix the incompatibility with the formatter in pyi files that only uses 0 to 1 blank lines. I'll address this separately. </details> ## Review The first commit is a small refactor that simplified implementing the fix (and makes it easier to reason about what's mutable and what's not). ## Test Plan I added a new test and verified that it fails with an error that the fix never converges. I verified the snapshot output after implementing the fix. --------- Co-authored-by: Hoël Bagard <34478245+hoel-bagard@users.noreply.github.com>
This commit is contained in:
parent
d441338358
commit
46ab9dec18
16 changed files with 1601 additions and 284 deletions
8
crates/ruff_linter/resources/test/fixtures/pycodestyle/.editorconfig
vendored
Normal file
8
crates/ruff_linter/resources/test/fixtures/pycodestyle/.editorconfig
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# These rules test for intentional "odd" formatting. Using a formatter fixes that
|
||||||
|
[E{1,2,3}*.py]
|
||||||
|
generated_code = true
|
||||||
|
ij_formatter_enabled = false
|
||||||
|
|
||||||
|
[W*.py]
|
||||||
|
generated_code = true
|
||||||
|
ij_formatter_enabled = false
|
62
crates/ruff_linter/resources/test/fixtures/pycodestyle/E30_isort.py
vendored
Normal file
62
crates/ruff_linter/resources/test/fixtures/pycodestyle/E30_isort.py
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from typing import Any, Sequence
|
||||||
|
|
||||||
|
|
||||||
|
class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
|
||||||
|
|
||||||
|
class BackendProxy:
|
||||||
|
backend_module: str
|
||||||
|
backend_object: str | None
|
||||||
|
backend: Any
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import abcd
|
||||||
|
|
||||||
|
|
||||||
|
abcd.foo()
|
||||||
|
|
||||||
|
def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from typing_extensions import TypeAlias
|
||||||
|
|
||||||
|
|
||||||
|
abcd.foo()
|
||||||
|
|
||||||
|
def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
...
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing_extensions import TypeAlias
|
||||||
|
|
||||||
|
def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def _exit(self) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
|
def _optional_commands(self) -> dict[str, bool]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def run(argv: Sequence[str]) -> int: ...
|
||||||
|
|
||||||
|
|
||||||
|
def read_line(fd: int = 0) -> bytearray: ...
|
||||||
|
|
||||||
|
|
||||||
|
def flush() -> None: ...
|
||||||
|
|
||||||
|
|
||||||
|
from typing import Any, Sequence
|
||||||
|
|
||||||
|
class MissingCommand(TypeError): ... # noqa: N818
|
|
@ -41,14 +41,7 @@ pub(crate) fn check_tokens(
|
||||||
Rule::BlankLinesAfterFunctionOrClass,
|
Rule::BlankLinesAfterFunctionOrClass,
|
||||||
Rule::BlankLinesBeforeNestedDefinition,
|
Rule::BlankLinesBeforeNestedDefinition,
|
||||||
]) {
|
]) {
|
||||||
let mut blank_lines_checker = BlankLinesChecker::default();
|
BlankLinesChecker::new(locator, stylist, settings).check_lines(tokens, &mut diagnostics);
|
||||||
blank_lines_checker.check_lines(
|
|
||||||
tokens,
|
|
||||||
locator,
|
|
||||||
stylist,
|
|
||||||
settings.tab_size,
|
|
||||||
&mut diagnostics,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::BlanketNOQA) {
|
if settings.rules.enabled(Rule::BlanketNOQA) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::line_width::LineLength;
|
use crate::line_width::LineLength;
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
use crate::rules::pycodestyle;
|
use crate::rules::{isort, pycodestyle};
|
||||||
use crate::settings::types::PreviewMode;
|
use crate::settings::types::PreviewMode;
|
||||||
use crate::test::test_path;
|
use crate::test::test_path;
|
||||||
use crate::{assert_messages, settings};
|
use crate::{assert_messages, settings};
|
||||||
|
@ -138,14 +138,23 @@ mod tests {
|
||||||
Path::new("E25.py")
|
Path::new("E25.py")
|
||||||
)]
|
)]
|
||||||
#[test_case(Rule::MissingWhitespaceAroundParameterEquals, Path::new("E25.py"))]
|
#[test_case(Rule::MissingWhitespaceAroundParameterEquals, Path::new("E25.py"))]
|
||||||
|
fn logical(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
|
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("pycodestyle").join(path).as_path(),
|
||||||
|
&settings::LinterSettings::for_rule(rule_code),
|
||||||
|
)?;
|
||||||
|
assert_messages!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test_case(Rule::BlankLineBetweenMethods, Path::new("E30.py"))]
|
#[test_case(Rule::BlankLineBetweenMethods, Path::new("E30.py"))]
|
||||||
#[test_case(Rule::BlankLinesTopLevel, Path::new("E30.py"))]
|
#[test_case(Rule::BlankLinesTopLevel, Path::new("E30.py"))]
|
||||||
#[test_case(Rule::TooManyBlankLines, Path::new("E30.py"))]
|
#[test_case(Rule::TooManyBlankLines, Path::new("E30.py"))]
|
||||||
#[test_case(Rule::BlankLineAfterDecorator, Path::new("E30.py"))]
|
#[test_case(Rule::BlankLineAfterDecorator, Path::new("E30.py"))]
|
||||||
#[test_case(Rule::BlankLinesAfterFunctionOrClass, Path::new("E30.py"))]
|
#[test_case(Rule::BlankLinesAfterFunctionOrClass, Path::new("E30.py"))]
|
||||||
#[test_case(Rule::BlankLinesBeforeNestedDefinition, Path::new("E30.py"))]
|
#[test_case(Rule::BlankLinesBeforeNestedDefinition, Path::new("E30.py"))]
|
||||||
|
fn blank_lines(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
fn logical(rule_code: Rule, path: &Path) -> Result<()> {
|
|
||||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||||
let diagnostics = test_path(
|
let diagnostics = test_path(
|
||||||
Path::new("pycodestyle").join(path).as_path(),
|
Path::new("pycodestyle").join(path).as_path(),
|
||||||
|
@ -155,6 +164,64 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tests the compatibility of the blank line top level rule and isort.
|
||||||
|
#[test_case(-1, 0)]
|
||||||
|
#[test_case(1, 1)]
|
||||||
|
#[test_case(0, 0)]
|
||||||
|
#[test_case(4, 4)]
|
||||||
|
fn blank_lines_top_level_isort_compatibility(
|
||||||
|
lines_after_imports: isize,
|
||||||
|
lines_between_types: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
let snapshot = format!(
|
||||||
|
"blank_lines_top_level_isort_compatibility-lines-after({lines_after_imports})-between({lines_between_types})"
|
||||||
|
);
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("pycodestyle").join("E30_isort.py"),
|
||||||
|
&settings::LinterSettings {
|
||||||
|
isort: isort::settings::Settings {
|
||||||
|
lines_after_imports,
|
||||||
|
lines_between_types,
|
||||||
|
..isort::settings::Settings::default()
|
||||||
|
},
|
||||||
|
..settings::LinterSettings::for_rules([
|
||||||
|
Rule::BlankLinesTopLevel,
|
||||||
|
Rule::UnsortedImports,
|
||||||
|
])
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
assert_messages!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tests the compatibility of the blank line too many lines and isort.
|
||||||
|
#[test_case(-1, 0)]
|
||||||
|
#[test_case(1, 1)]
|
||||||
|
#[test_case(0, 0)]
|
||||||
|
#[test_case(4, 4)]
|
||||||
|
fn too_many_blank_lines_isort_compatibility(
|
||||||
|
lines_after_imports: isize,
|
||||||
|
lines_between_types: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
let snapshot = format!("too_many_blank_lines_isort_compatibility-lines-after({lines_after_imports})-between({lines_between_types})");
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("pycodestyle").join("E30_isort.py"),
|
||||||
|
&settings::LinterSettings {
|
||||||
|
isort: isort::settings::Settings {
|
||||||
|
lines_after_imports,
|
||||||
|
lines_between_types,
|
||||||
|
..isort::settings::Settings::default()
|
||||||
|
},
|
||||||
|
..settings::LinterSettings::for_rules([
|
||||||
|
Rule::TooManyBlankLines,
|
||||||
|
Rule::UnsortedImports,
|
||||||
|
])
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
assert_messages!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn constant_literals() -> Result<()> {
|
fn constant_literals() -> Result<()> {
|
||||||
let diagnostics = test_path(
|
let diagnostics = test_path(
|
||||||
|
|
|
@ -24,7 +24,7 @@ use ruff_python_trivia::PythonWhitespace;
|
||||||
/// Number of blank lines around top level classes and functions.
|
/// Number of blank lines around top level classes and functions.
|
||||||
const BLANK_LINES_TOP_LEVEL: u32 = 2;
|
const BLANK_LINES_TOP_LEVEL: u32 = 2;
|
||||||
/// Number of blank lines around methods and nested classes and functions.
|
/// Number of blank lines around methods and nested classes and functions.
|
||||||
const BLANK_LINES_METHOD_LEVEL: u32 = 1;
|
const BLANK_LINES_NESTED_LEVEL: u32 = 1;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for missing blank lines between methods of a class.
|
/// Checks for missing blank lines between methods of a class.
|
||||||
|
@ -60,7 +60,7 @@ pub struct BlankLineBetweenMethods;
|
||||||
impl AlwaysFixableViolation for BlankLineBetweenMethods {
|
impl AlwaysFixableViolation for BlankLineBetweenMethods {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!("Expected {BLANK_LINES_METHOD_LEVEL:?} blank line, found 0")
|
format!("Expected {BLANK_LINES_NESTED_LEVEL:?} blank line, found 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_title(&self) -> String {
|
fn fix_title(&self) -> String {
|
||||||
|
@ -74,6 +74,10 @@ impl AlwaysFixableViolation for BlankLineBetweenMethods {
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// PEP 8 recommends exactly two blank lines between top level functions and classes.
|
/// PEP 8 recommends exactly two blank lines between top level functions and classes.
|
||||||
///
|
///
|
||||||
|
/// Note: The rule respects the [`lint.isort.lines-after-imports`] setting when determining
|
||||||
|
/// the required number of blank lines between top-level `import` statements and function or class definitions
|
||||||
|
/// for compatibility with isort.
|
||||||
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// def func1():
|
/// def func1():
|
||||||
|
@ -98,16 +102,18 @@ impl AlwaysFixableViolation for BlankLineBetweenMethods {
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct BlankLinesTopLevel {
|
pub struct BlankLinesTopLevel {
|
||||||
actual_blank_lines: u32,
|
actual_blank_lines: u32,
|
||||||
|
expected_blank_lines: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlwaysFixableViolation for BlankLinesTopLevel {
|
impl AlwaysFixableViolation for BlankLinesTopLevel {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let BlankLinesTopLevel {
|
let BlankLinesTopLevel {
|
||||||
actual_blank_lines: nb_blank_lines,
|
actual_blank_lines,
|
||||||
|
expected_blank_lines,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
format!("Expected {BLANK_LINES_TOP_LEVEL:?} blank lines, found {nb_blank_lines}")
|
format!("Expected {expected_blank_lines:?} blank lines, found {actual_blank_lines}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_title(&self) -> String {
|
fn fix_title(&self) -> String {
|
||||||
|
@ -144,6 +150,10 @@ impl AlwaysFixableViolation for BlankLinesTopLevel {
|
||||||
/// pass
|
/// pass
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Note: The rule respects the following `isort` settings when determining the maximum number of blank lines allowed between two statements:
|
||||||
|
/// * [`lint.isort.lines-after-imports`]: For top-level statements directly following an import statement.
|
||||||
|
/// * [`lint.isort.lines-between-types`]: For `import` statements directly following a `from ... import ...` statement or vice versa.
|
||||||
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines)
|
/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines)
|
||||||
/// - [Flake 8 rule](https://www.flake8rules.com/rules/E303.html)
|
/// - [Flake 8 rule](https://www.flake8rules.com/rules/E303.html)
|
||||||
|
@ -155,10 +165,9 @@ pub struct TooManyBlankLines {
|
||||||
impl AlwaysFixableViolation for TooManyBlankLines {
|
impl AlwaysFixableViolation for TooManyBlankLines {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let TooManyBlankLines {
|
let TooManyBlankLines { actual_blank_lines } = self;
|
||||||
actual_blank_lines: nb_blank_lines,
|
|
||||||
} = self;
|
format!("Too many blank lines ({actual_blank_lines})")
|
||||||
format!("Too many blank lines ({nb_blank_lines})")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_title(&self) -> String {
|
fn fix_title(&self) -> String {
|
||||||
|
@ -415,6 +424,8 @@ impl<'a> Iterator for LinePreprocessor<'a> {
|
||||||
{
|
{
|
||||||
LogicalLineKind::Function
|
LogicalLineKind::Function
|
||||||
}
|
}
|
||||||
|
TokenKind::Import => LogicalLineKind::Import,
|
||||||
|
TokenKind::From => LogicalLineKind::FromImport,
|
||||||
_ => LogicalLineKind::Other,
|
_ => LogicalLineKind::Other,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -560,9 +571,17 @@ enum Follows {
|
||||||
Other,
|
Other,
|
||||||
Decorator,
|
Decorator,
|
||||||
Def,
|
Def,
|
||||||
|
Import,
|
||||||
|
FromImport,
|
||||||
Docstring,
|
Docstring,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Follows {
|
||||||
|
const fn is_any_import(self) -> bool {
|
||||||
|
matches!(self, Follows::Import | Follows::FromImport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
enum Status {
|
enum Status {
|
||||||
/// Stores the indent level where the nesting started.
|
/// Stores the indent level where the nesting started.
|
||||||
|
@ -602,8 +621,335 @@ impl Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains variables used for the linting of blank lines.
|
/// Contains variables used for the linting of blank lines.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct BlankLinesChecker {
|
pub(crate) struct BlankLinesChecker<'a> {
|
||||||
|
stylist: &'a Stylist<'a>,
|
||||||
|
locator: &'a Locator<'a>,
|
||||||
|
indent_width: IndentWidth,
|
||||||
|
lines_after_imports: isize,
|
||||||
|
lines_between_types: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BlankLinesChecker<'a> {
|
||||||
|
pub(crate) fn new(
|
||||||
|
locator: &'a Locator<'a>,
|
||||||
|
stylist: &'a Stylist<'a>,
|
||||||
|
settings: &crate::settings::LinterSettings,
|
||||||
|
) -> BlankLinesChecker<'a> {
|
||||||
|
BlankLinesChecker {
|
||||||
|
stylist,
|
||||||
|
locator,
|
||||||
|
indent_width: settings.tab_size,
|
||||||
|
lines_after_imports: settings.isort.lines_after_imports,
|
||||||
|
lines_between_types: settings.isort.lines_between_types,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// E301, E302, E303, E304, E305, E306
|
||||||
|
pub(crate) fn check_lines(&self, tokens: &[LexResult], diagnostics: &mut Vec<Diagnostic>) {
|
||||||
|
let mut prev_indent_length: Option<usize> = None;
|
||||||
|
let mut state = BlankLinesState::default();
|
||||||
|
let line_preprocessor = LinePreprocessor::new(tokens, self.locator, self.indent_width);
|
||||||
|
|
||||||
|
for logical_line in line_preprocessor {
|
||||||
|
// Reset `follows` after a dedent:
|
||||||
|
// ```python
|
||||||
|
// if True:
|
||||||
|
// import test
|
||||||
|
// a = 10
|
||||||
|
// ```
|
||||||
|
// The `a` statement doesn't follow the `import` statement but the `if` statement.
|
||||||
|
if let Some(prev_indent_length) = prev_indent_length {
|
||||||
|
if prev_indent_length > logical_line.indent_length {
|
||||||
|
state.follows = Follows::Other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.class_status.update(&logical_line);
|
||||||
|
state.fn_status.update(&logical_line);
|
||||||
|
|
||||||
|
if state.is_not_first_logical_line {
|
||||||
|
self.check_line(&logical_line, &state, prev_indent_length, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
match logical_line.kind {
|
||||||
|
LogicalLineKind::Class => {
|
||||||
|
if matches!(state.class_status, Status::Outside) {
|
||||||
|
state.class_status = Status::Inside(logical_line.indent_length);
|
||||||
|
}
|
||||||
|
state.follows = Follows::Other;
|
||||||
|
}
|
||||||
|
LogicalLineKind::Decorator => {
|
||||||
|
state.follows = Follows::Decorator;
|
||||||
|
}
|
||||||
|
LogicalLineKind::Function => {
|
||||||
|
if matches!(state.fn_status, Status::Outside) {
|
||||||
|
state.fn_status = Status::Inside(logical_line.indent_length);
|
||||||
|
}
|
||||||
|
state.follows = Follows::Def;
|
||||||
|
}
|
||||||
|
LogicalLineKind::Comment => {}
|
||||||
|
LogicalLineKind::Import => {
|
||||||
|
state.follows = Follows::Import;
|
||||||
|
}
|
||||||
|
LogicalLineKind::FromImport => {
|
||||||
|
state.follows = Follows::FromImport;
|
||||||
|
}
|
||||||
|
LogicalLineKind::Other => {
|
||||||
|
state.follows = Follows::Other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if logical_line.is_docstring {
|
||||||
|
state.follows = Follows::Docstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !logical_line.is_comment_only {
|
||||||
|
state.is_not_first_logical_line = true;
|
||||||
|
|
||||||
|
state.last_non_comment_line_end = logical_line.logical_line_end;
|
||||||
|
|
||||||
|
if logical_line.indent_length == 0 {
|
||||||
|
state.previous_unindented_line_kind = Some(logical_line.kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !logical_line.is_comment_only {
|
||||||
|
prev_indent_length = Some(logical_line.indent_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::nonminimal_bool)]
|
||||||
|
fn check_line(
|
||||||
|
&self,
|
||||||
|
line: &LogicalLineInfo,
|
||||||
|
state: &BlankLinesState,
|
||||||
|
prev_indent_length: Option<usize>,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
if line.preceding_blank_lines == 0
|
||||||
|
// Only applies to methods.
|
||||||
|
&& matches!(line.kind, LogicalLineKind::Function | LogicalLineKind::Decorator)
|
||||||
|
// Allow groups of one-liners.
|
||||||
|
&& !(matches!(state.follows, Follows::Def) && !matches!(line.last_token, TokenKind::Colon))
|
||||||
|
&& matches!(state.class_status, Status::Inside(_))
|
||||||
|
// The class/parent method's docstring can directly precede the def.
|
||||||
|
// Allow following a decorator (if there is an error it will be triggered on the first decorator).
|
||||||
|
&& !matches!(state.follows, Follows::Docstring | Follows::Decorator)
|
||||||
|
// Do not trigger when the def follows an if/while/etc...
|
||||||
|
&& prev_indent_length.is_some_and(|prev_indent_length| prev_indent_length >= line.indent_length)
|
||||||
|
{
|
||||||
|
// E301
|
||||||
|
let mut diagnostic = Diagnostic::new(BlankLineBetweenMethods, line.first_token_range);
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
||||||
|
self.stylist.line_ending().to_string(),
|
||||||
|
self.locator.line_start(state.last_non_comment_line_end),
|
||||||
|
)));
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected_blank_lines_before_definition = if line.indent_length == 0 {
|
||||||
|
// Mimic the isort rules for the number of blank lines before classes and functions
|
||||||
|
if state.follows.is_any_import() {
|
||||||
|
// Fallback to the default if the value is too large for an u32 or if it is negative.
|
||||||
|
// A negative value means that isort should determine the blank lines automatically.
|
||||||
|
// `isort` defaults to 2 if before a class or function definition and 1 otherwise.
|
||||||
|
// Defaulting to 2 here is correct because the variable is only used when testing the
|
||||||
|
// blank lines before a class or function definition.
|
||||||
|
u32::try_from(self.lines_after_imports).unwrap_or(BLANK_LINES_TOP_LEVEL)
|
||||||
|
} else {
|
||||||
|
BLANK_LINES_TOP_LEVEL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BLANK_LINES_NESTED_LEVEL
|
||||||
|
};
|
||||||
|
|
||||||
|
if line.preceding_blank_lines < expected_blank_lines_before_definition
|
||||||
|
// Allow following a decorator (if there is an error it will be triggered on the first decorator).
|
||||||
|
&& !matches!(state.follows, Follows::Decorator)
|
||||||
|
// Allow groups of one-liners.
|
||||||
|
&& !(matches!(state.follows, Follows::Def) && !matches!(line.last_token, TokenKind::Colon))
|
||||||
|
// Only trigger on non-indented classes and functions (for example functions within an if are ignored)
|
||||||
|
&& line.indent_length == 0
|
||||||
|
// Only apply to functions or classes.
|
||||||
|
&& line.kind.is_class_function_or_decorator()
|
||||||
|
{
|
||||||
|
// E302
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
BlankLinesTopLevel {
|
||||||
|
actual_blank_lines: line.preceding_blank_lines.count(),
|
||||||
|
expected_blank_lines: expected_blank_lines_before_definition,
|
||||||
|
},
|
||||||
|
line.first_token_range,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(blank_lines_range) = line.blank_lines.range() {
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
|
self.stylist
|
||||||
|
.line_ending()
|
||||||
|
.repeat(expected_blank_lines_before_definition as usize),
|
||||||
|
blank_lines_range,
|
||||||
|
)));
|
||||||
|
} else {
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
||||||
|
self.stylist
|
||||||
|
.line_ending()
|
||||||
|
.repeat(expected_blank_lines_before_definition as usize),
|
||||||
|
self.locator.line_start(state.last_non_comment_line_end),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
let max_lines_level = if line.indent_length == 0 {
|
||||||
|
BLANK_LINES_TOP_LEVEL
|
||||||
|
} else {
|
||||||
|
BLANK_LINES_NESTED_LEVEL
|
||||||
|
};
|
||||||
|
|
||||||
|
// If between `import` and `from .. import ..` or the other way round,
|
||||||
|
// allow up to `lines_between_types` newlines for isort compatibility.
|
||||||
|
// We let `isort` remove extra blank lines when the imports belong
|
||||||
|
// to different sections.
|
||||||
|
let max_blank_lines = if matches!(
|
||||||
|
(line.kind, state.follows),
|
||||||
|
(LogicalLineKind::Import, Follows::FromImport)
|
||||||
|
| (LogicalLineKind::FromImport, Follows::Import)
|
||||||
|
) {
|
||||||
|
max_lines_level.max(u32::try_from(self.lines_between_types).unwrap_or(u32::MAX))
|
||||||
|
} else {
|
||||||
|
expected_blank_lines_before_definition
|
||||||
|
};
|
||||||
|
|
||||||
|
if line.blank_lines > max_blank_lines {
|
||||||
|
// E303
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
TooManyBlankLines {
|
||||||
|
actual_blank_lines: line.blank_lines.count(),
|
||||||
|
},
|
||||||
|
line.first_token_range,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(blank_lines_range) = line.blank_lines.range() {
|
||||||
|
if max_blank_lines == 0 {
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(blank_lines_range)));
|
||||||
|
} else {
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
|
self.stylist.line_ending().repeat(max_blank_lines as usize),
|
||||||
|
blank_lines_range,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(state.follows, Follows::Decorator)
|
||||||
|
&& !line.is_comment_only
|
||||||
|
&& line.preceding_blank_lines > 0
|
||||||
|
{
|
||||||
|
// E304
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
BlankLineAfterDecorator {
|
||||||
|
actual_blank_lines: line.preceding_blank_lines.count(),
|
||||||
|
},
|
||||||
|
line.first_token_range,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get all the lines between the last decorator line (included) and the current line (included).
|
||||||
|
// Then remove all blank lines.
|
||||||
|
let trivia_range = TextRange::new(
|
||||||
|
state.last_non_comment_line_end,
|
||||||
|
self.locator.line_start(line.first_token_range.start()),
|
||||||
|
);
|
||||||
|
let trivia_text = self.locator.slice(trivia_range);
|
||||||
|
let mut trivia_without_blank_lines = trivia_text
|
||||||
|
.universal_newlines()
|
||||||
|
.filter_map(|line| (!line.trim_whitespace().is_empty()).then_some(line.as_str()))
|
||||||
|
.join(&self.stylist.line_ending());
|
||||||
|
|
||||||
|
let fix = if trivia_without_blank_lines.is_empty() {
|
||||||
|
Fix::safe_edit(Edit::range_deletion(trivia_range))
|
||||||
|
} else {
|
||||||
|
trivia_without_blank_lines.push_str(&self.stylist.line_ending());
|
||||||
|
Fix::safe_edit(Edit::range_replacement(
|
||||||
|
trivia_without_blank_lines,
|
||||||
|
trivia_range,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
diagnostic.set_fix(fix);
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.preceding_blank_lines < BLANK_LINES_TOP_LEVEL
|
||||||
|
&& state
|
||||||
|
.previous_unindented_line_kind
|
||||||
|
.is_some_and(LogicalLineKind::is_class_function_or_decorator)
|
||||||
|
&& line.indent_length == 0
|
||||||
|
&& !line.is_comment_only
|
||||||
|
&& !line.kind.is_class_function_or_decorator()
|
||||||
|
{
|
||||||
|
// E305
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
BlankLinesAfterFunctionOrClass {
|
||||||
|
actual_blank_lines: line.preceding_blank_lines.count(),
|
||||||
|
},
|
||||||
|
line.first_token_range,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(blank_lines_range) = line.blank_lines.range() {
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
|
self.stylist
|
||||||
|
.line_ending()
|
||||||
|
.repeat(BLANK_LINES_TOP_LEVEL as usize),
|
||||||
|
blank_lines_range,
|
||||||
|
)));
|
||||||
|
} else {
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
||||||
|
self.stylist
|
||||||
|
.line_ending()
|
||||||
|
.repeat(BLANK_LINES_TOP_LEVEL as usize),
|
||||||
|
self.locator.line_start(line.first_token_range.start()),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.preceding_blank_lines == 0
|
||||||
|
// Only apply to nested functions.
|
||||||
|
&& matches!(state.fn_status, Status::Inside(_))
|
||||||
|
&& line.kind.is_class_function_or_decorator()
|
||||||
|
// Allow following a decorator (if there is an error it will be triggered on the first decorator).
|
||||||
|
&& !matches!(state.follows, Follows::Decorator)
|
||||||
|
// The class's docstring can directly precede the first function.
|
||||||
|
&& !matches!(state.follows, Follows::Docstring)
|
||||||
|
// Do not trigger when the def/class follows an "indenting token" (if/while/etc...).
|
||||||
|
&& prev_indent_length.is_some_and(|prev_indent_length| prev_indent_length >= line.indent_length)
|
||||||
|
// Allow groups of one-liners.
|
||||||
|
&& !(matches!(state.follows, Follows::Def) && line.last_token != TokenKind::Colon)
|
||||||
|
{
|
||||||
|
// E306
|
||||||
|
let mut diagnostic =
|
||||||
|
Diagnostic::new(BlankLinesBeforeNestedDefinition, line.first_token_range);
|
||||||
|
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
||||||
|
self.stylist.line_ending().to_string(),
|
||||||
|
self.locator.line_start(line.first_token_range.start()),
|
||||||
|
)));
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
struct BlankLinesState {
|
||||||
follows: Follows,
|
follows: Follows,
|
||||||
fn_status: Status,
|
fn_status: Status,
|
||||||
class_status: Status,
|
class_status: Status,
|
||||||
|
@ -615,264 +961,6 @@ pub(crate) struct BlankLinesChecker {
|
||||||
previous_unindented_line_kind: Option<LogicalLineKind>,
|
previous_unindented_line_kind: Option<LogicalLineKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlankLinesChecker {
|
|
||||||
/// E301, E302, E303, E304, E305, E306
|
|
||||||
pub(crate) fn check_lines(
|
|
||||||
&mut self,
|
|
||||||
tokens: &[LexResult],
|
|
||||||
locator: &Locator,
|
|
||||||
stylist: &Stylist,
|
|
||||||
indent_width: IndentWidth,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
let mut prev_indent_length: Option<usize> = None;
|
|
||||||
let line_preprocessor = LinePreprocessor::new(tokens, locator, indent_width);
|
|
||||||
|
|
||||||
for logical_line in line_preprocessor {
|
|
||||||
self.check_line(
|
|
||||||
&logical_line,
|
|
||||||
prev_indent_length,
|
|
||||||
locator,
|
|
||||||
stylist,
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
if !logical_line.is_comment_only {
|
|
||||||
prev_indent_length = Some(logical_line.indent_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::nonminimal_bool)]
|
|
||||||
fn check_line(
|
|
||||||
&mut self,
|
|
||||||
line: &LogicalLineInfo,
|
|
||||||
prev_indent_length: Option<usize>,
|
|
||||||
locator: &Locator,
|
|
||||||
stylist: &Stylist,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
self.class_status.update(line);
|
|
||||||
self.fn_status.update(line);
|
|
||||||
|
|
||||||
// Don't expect blank lines before the first non comment line.
|
|
||||||
if self.is_not_first_logical_line {
|
|
||||||
if line.preceding_blank_lines == 0
|
|
||||||
// Only applies to methods.
|
|
||||||
&& matches!(line.kind, LogicalLineKind::Function | LogicalLineKind::Decorator)
|
|
||||||
// Allow groups of one-liners.
|
|
||||||
&& !(matches!(self.follows, Follows::Def) && !matches!(line.last_token, TokenKind::Colon))
|
|
||||||
&& matches!(self.class_status, Status::Inside(_))
|
|
||||||
// The class/parent method's docstring can directly precede the def.
|
|
||||||
// Allow following a decorator (if there is an error it will be triggered on the first decorator).
|
|
||||||
&& !matches!(self.follows, Follows::Docstring | Follows::Decorator)
|
|
||||||
// Do not trigger when the def follows an if/while/etc...
|
|
||||||
&& prev_indent_length.is_some_and(|prev_indent_length| prev_indent_length >= line.indent_length)
|
|
||||||
{
|
|
||||||
// E301
|
|
||||||
let mut diagnostic =
|
|
||||||
Diagnostic::new(BlankLineBetweenMethods, line.first_token_range);
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
|
||||||
stylist.line_ending().to_string(),
|
|
||||||
locator.line_start(self.last_non_comment_line_end),
|
|
||||||
)));
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if line.preceding_blank_lines < BLANK_LINES_TOP_LEVEL
|
|
||||||
// Allow following a decorator (if there is an error it will be triggered on the first decorator).
|
|
||||||
&& !matches!(self.follows, Follows::Decorator)
|
|
||||||
// Allow groups of one-liners.
|
|
||||||
&& !(matches!(self.follows, Follows::Def) && !matches!(line.last_token, TokenKind::Colon))
|
|
||||||
// Only trigger on non-indented classes and functions (for example functions within an if are ignored)
|
|
||||||
&& line.indent_length == 0
|
|
||||||
// Only apply to functions or classes.
|
|
||||||
&& line.kind.is_top_level()
|
|
||||||
{
|
|
||||||
// E302
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
|
||||||
BlankLinesTopLevel {
|
|
||||||
actual_blank_lines: line.preceding_blank_lines.count(),
|
|
||||||
},
|
|
||||||
line.first_token_range,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(blank_lines_range) = line.blank_lines.range() {
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
|
||||||
stylist.line_ending().repeat(BLANK_LINES_TOP_LEVEL as usize),
|
|
||||||
blank_lines_range,
|
|
||||||
)));
|
|
||||||
} else {
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
|
||||||
stylist.line_ending().repeat(BLANK_LINES_TOP_LEVEL as usize),
|
|
||||||
locator.line_start(self.last_non_comment_line_end),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
let expected_blank_lines = if line.indent_length > 0 {
|
|
||||||
BLANK_LINES_METHOD_LEVEL
|
|
||||||
} else {
|
|
||||||
BLANK_LINES_TOP_LEVEL
|
|
||||||
};
|
|
||||||
|
|
||||||
if line.blank_lines > expected_blank_lines {
|
|
||||||
// E303
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
|
||||||
TooManyBlankLines {
|
|
||||||
actual_blank_lines: line.blank_lines.count(),
|
|
||||||
},
|
|
||||||
line.first_token_range,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(blank_lines_range) = line.blank_lines.range() {
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
|
||||||
stylist.line_ending().repeat(expected_blank_lines as usize),
|
|
||||||
blank_lines_range,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches!(self.follows, Follows::Decorator)
|
|
||||||
&& !line.is_comment_only
|
|
||||||
&& line.preceding_blank_lines > 0
|
|
||||||
{
|
|
||||||
// E304
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
|
||||||
BlankLineAfterDecorator {
|
|
||||||
actual_blank_lines: line.preceding_blank_lines.count(),
|
|
||||||
},
|
|
||||||
line.first_token_range,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get all the lines between the last decorator line (included) and the current line (included).
|
|
||||||
// Then remove all blank lines.
|
|
||||||
let trivia_range = TextRange::new(
|
|
||||||
self.last_non_comment_line_end,
|
|
||||||
locator.line_start(line.first_token_range.start()),
|
|
||||||
);
|
|
||||||
let trivia_text = locator.slice(trivia_range);
|
|
||||||
let mut trivia_without_blank_lines = trivia_text
|
|
||||||
.universal_newlines()
|
|
||||||
.filter_map(|line| {
|
|
||||||
(!line.trim_whitespace().is_empty()).then_some(line.as_str())
|
|
||||||
})
|
|
||||||
.join(&stylist.line_ending());
|
|
||||||
|
|
||||||
let fix = if trivia_without_blank_lines.is_empty() {
|
|
||||||
Fix::safe_edit(Edit::range_deletion(trivia_range))
|
|
||||||
} else {
|
|
||||||
trivia_without_blank_lines.push_str(&stylist.line_ending());
|
|
||||||
Fix::safe_edit(Edit::range_replacement(
|
|
||||||
trivia_without_blank_lines,
|
|
||||||
trivia_range,
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if line.preceding_blank_lines < BLANK_LINES_TOP_LEVEL
|
|
||||||
&& self
|
|
||||||
.previous_unindented_line_kind
|
|
||||||
.is_some_and(LogicalLineKind::is_top_level)
|
|
||||||
&& line.indent_length == 0
|
|
||||||
&& !line.is_comment_only
|
|
||||||
&& !line.kind.is_top_level()
|
|
||||||
{
|
|
||||||
// E305
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
|
||||||
BlankLinesAfterFunctionOrClass {
|
|
||||||
actual_blank_lines: line.preceding_blank_lines.count(),
|
|
||||||
},
|
|
||||||
line.first_token_range,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(blank_lines_range) = line.blank_lines.range() {
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
|
||||||
stylist.line_ending().repeat(BLANK_LINES_TOP_LEVEL as usize),
|
|
||||||
blank_lines_range,
|
|
||||||
)));
|
|
||||||
} else {
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
|
||||||
stylist.line_ending().repeat(BLANK_LINES_TOP_LEVEL as usize),
|
|
||||||
locator.line_start(line.first_token_range.start()),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if line.preceding_blank_lines == 0
|
|
||||||
// Only apply to nested functions.
|
|
||||||
&& matches!(self.fn_status, Status::Inside(_))
|
|
||||||
&& line.kind.is_top_level()
|
|
||||||
// Allow following a decorator (if there is an error it will be triggered on the first decorator).
|
|
||||||
&& !matches!(self.follows, Follows::Decorator)
|
|
||||||
// The class's docstring can directly precede the first function.
|
|
||||||
&& !matches!(self.follows, Follows::Docstring)
|
|
||||||
// Do not trigger when the def/class follows an "indenting token" (if/while/etc...).
|
|
||||||
&& prev_indent_length.is_some_and(|prev_indent_length| prev_indent_length >= line.indent_length)
|
|
||||||
// Allow groups of one-liners.
|
|
||||||
&& !(matches!(self.follows, Follows::Def) && line.last_token != TokenKind::Colon)
|
|
||||||
{
|
|
||||||
// E306
|
|
||||||
let mut diagnostic =
|
|
||||||
Diagnostic::new(BlankLinesBeforeNestedDefinition, line.first_token_range);
|
|
||||||
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
|
||||||
stylist.line_ending().to_string(),
|
|
||||||
locator.line_start(line.first_token_range.start()),
|
|
||||||
)));
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match line.kind {
|
|
||||||
LogicalLineKind::Class => {
|
|
||||||
if matches!(self.class_status, Status::Outside) {
|
|
||||||
self.class_status = Status::Inside(line.indent_length);
|
|
||||||
}
|
|
||||||
self.follows = Follows::Other;
|
|
||||||
}
|
|
||||||
LogicalLineKind::Decorator => {
|
|
||||||
self.follows = Follows::Decorator;
|
|
||||||
}
|
|
||||||
LogicalLineKind::Function => {
|
|
||||||
if matches!(self.fn_status, Status::Outside) {
|
|
||||||
self.fn_status = Status::Inside(line.indent_length);
|
|
||||||
}
|
|
||||||
self.follows = Follows::Def;
|
|
||||||
}
|
|
||||||
LogicalLineKind::Comment => {}
|
|
||||||
LogicalLineKind::Other => {
|
|
||||||
self.follows = Follows::Other;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if line.is_docstring {
|
|
||||||
self.follows = Follows::Docstring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !line.is_comment_only {
|
|
||||||
self.is_not_first_logical_line = true;
|
|
||||||
|
|
||||||
self.last_non_comment_line_end = line.logical_line_end;
|
|
||||||
|
|
||||||
if line.indent_length == 0 {
|
|
||||||
self.previous_unindented_line_kind = Some(line.kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum LogicalLineKind {
|
enum LogicalLineKind {
|
||||||
/// The clause header of a class definition
|
/// The clause header of a class definition
|
||||||
|
@ -883,12 +971,16 @@ enum LogicalLineKind {
|
||||||
Function,
|
Function,
|
||||||
/// A comment only line
|
/// A comment only line
|
||||||
Comment,
|
Comment,
|
||||||
|
/// An import statement
|
||||||
|
Import,
|
||||||
|
/// A from.. import statement
|
||||||
|
FromImport,
|
||||||
/// Any other statement or clause header
|
/// Any other statement or clause header
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogicalLineKind {
|
impl LogicalLineKind {
|
||||||
fn is_top_level(self) -> bool {
|
fn is_class_function_or_decorator(self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
LogicalLineKind::Class | LogicalLineKind::Function | LogicalLineKind::Decorator
|
LogicalLineKind::Class | LogicalLineKind::Function | LogicalLineKind::Decorator
|
||||||
|
|
|
@ -245,6 +245,4 @@ E30.py:702:5: E303 [*] Too many blank lines (2)
|
||||||
701 |-
|
701 |-
|
||||||
702 701 | pass
|
702 701 | pass
|
||||||
703 702 | # end
|
703 702 | # end
|
||||||
704 703 |
|
704 703 |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 |-
|
||||||
|
3 |-
|
||||||
|
4 |-
|
||||||
|
5 2 | from typing import Any, Sequence
|
||||||
|
6 3 |
|
||||||
|
7 4 |
|
||||||
|
|
||||||
|
E30_isort.py:23:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
| ^^^ E302
|
||||||
|
24 |
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
20 20 |
|
||||||
|
21 21 | abcd.foo()
|
||||||
|
22 22 |
|
||||||
|
23 |+
|
||||||
|
23 24 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
24 25 |
|
||||||
|
25 26 | if TYPE_CHECKING:
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:35:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
36 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
32 32 |
|
||||||
|
33 33 | abcd.foo()
|
||||||
|
34 34 |
|
||||||
|
35 |+
|
||||||
|
35 36 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
36 37 | ...
|
||||||
|
37 38 |
|
||||||
|
|
||||||
|
E30_isort.py:41:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
39 | from typing_extensions import TypeAlias
|
||||||
|
40 |
|
||||||
|
41 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
42 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
38 38 | if TYPE_CHECKING:
|
||||||
|
39 39 | from typing_extensions import TypeAlias
|
||||||
|
40 40 |
|
||||||
|
41 |+
|
||||||
|
41 42 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
42 43 | ...
|
||||||
|
43 44 |
|
||||||
|
|
||||||
|
E30_isort.py:60:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
60 | / from typing import Any, Sequence
|
||||||
|
61 | |
|
||||||
|
62 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 61 |
|
||||||
|
62 |+
|
||||||
|
62 63 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
|
||||||
|
E30_isort.py:62:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
60 | from typing import Any, Sequence
|
||||||
|
61 |
|
||||||
|
62 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| ^^^^^ E302
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 61 |
|
||||||
|
62 |+
|
||||||
|
62 63 | class MissingCommand(TypeError): ... # noqa: N818
|
|
@ -0,0 +1,127 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 |-
|
||||||
|
3 |-
|
||||||
|
4 |-
|
||||||
|
5 2 | from typing import Any, Sequence
|
||||||
|
6 |-
|
||||||
|
7 |-
|
||||||
|
8 3 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 4 |
|
||||||
|
10 5 |
|
||||||
|
|
||||||
|
E30_isort.py:23:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
| ^^^ E302
|
||||||
|
24 |
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
20 20 |
|
||||||
|
21 21 | abcd.foo()
|
||||||
|
22 22 |
|
||||||
|
23 |+
|
||||||
|
23 24 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
24 25 |
|
||||||
|
25 26 | if TYPE_CHECKING:
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:35:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
36 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
32 32 |
|
||||||
|
33 33 | abcd.foo()
|
||||||
|
34 34 |
|
||||||
|
35 |+
|
||||||
|
35 36 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
36 37 | ...
|
||||||
|
37 38 |
|
||||||
|
|
||||||
|
E30_isort.py:41:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
39 | from typing_extensions import TypeAlias
|
||||||
|
40 |
|
||||||
|
41 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
42 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
38 38 | if TYPE_CHECKING:
|
||||||
|
39 39 | from typing_extensions import TypeAlias
|
||||||
|
40 40 |
|
||||||
|
41 |+
|
||||||
|
41 42 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
42 43 | ...
|
||||||
|
43 44 |
|
||||||
|
|
||||||
|
E30_isort.py:60:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
60 | / from typing import Any, Sequence
|
||||||
|
61 | |
|
||||||
|
62 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
58 58 |
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 |-
|
||||||
|
62 61 | class MissingCommand(TypeError): ... # noqa: N818
|
|
@ -0,0 +1,110 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 2 |
|
||||||
|
3 |-
|
||||||
|
4 |-
|
||||||
|
5 3 | from typing import Any, Sequence
|
||||||
|
6 |-
|
||||||
|
7 4 |
|
||||||
|
8 5 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 6 |
|
||||||
|
|
||||||
|
E30_isort.py:23:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
| ^^^ E302
|
||||||
|
24 |
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
20 20 |
|
||||||
|
21 21 | abcd.foo()
|
||||||
|
22 22 |
|
||||||
|
23 |+
|
||||||
|
23 24 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
24 25 |
|
||||||
|
25 26 | if TYPE_CHECKING:
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:35:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
36 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
32 32 |
|
||||||
|
33 33 | abcd.foo()
|
||||||
|
34 34 |
|
||||||
|
35 |+
|
||||||
|
35 36 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
36 37 | ...
|
||||||
|
37 38 |
|
||||||
|
|
||||||
|
E30_isort.py:41:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
39 | from typing_extensions import TypeAlias
|
||||||
|
40 |
|
||||||
|
41 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
42 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
38 38 | if TYPE_CHECKING:
|
||||||
|
39 39 | from typing_extensions import TypeAlias
|
||||||
|
40 40 |
|
||||||
|
41 |+
|
||||||
|
41 42 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
42 43 | ...
|
||||||
|
43 44 |
|
|
@ -0,0 +1,166 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
2 2 |
|
||||||
|
3 3 |
|
||||||
|
4 4 |
|
||||||
|
5 |+
|
||||||
|
5 6 | from typing import Any, Sequence
|
||||||
|
6 7 |
|
||||||
|
7 8 |
|
||||||
|
9 |+
|
||||||
|
10 |+
|
||||||
|
8 11 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 12 |
|
||||||
|
10 13 |
|
||||||
|
|
||||||
|
E30_isort.py:8:1: E302 [*] Expected 4 blank lines, found 2
|
||||||
|
|
|
||||||
|
8 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| ^^^^^ E302
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
5 5 | from typing import Any, Sequence
|
||||||
|
6 6 |
|
||||||
|
7 7 |
|
||||||
|
8 |+
|
||||||
|
9 |+
|
||||||
|
8 10 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 11 |
|
||||||
|
10 12 |
|
||||||
|
|
||||||
|
E30_isort.py:23:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
| ^^^ E302
|
||||||
|
24 |
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
20 20 |
|
||||||
|
21 21 | abcd.foo()
|
||||||
|
22 22 |
|
||||||
|
23 |+
|
||||||
|
23 24 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
24 25 |
|
||||||
|
25 26 | if TYPE_CHECKING:
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:35:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
36 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
32 32 |
|
||||||
|
33 33 | abcd.foo()
|
||||||
|
34 34 |
|
||||||
|
35 |+
|
||||||
|
35 36 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
36 37 | ...
|
||||||
|
37 38 |
|
||||||
|
|
||||||
|
E30_isort.py:41:1: E302 [*] Expected 2 blank lines, found 1
|
||||||
|
|
|
||||||
|
39 | from typing_extensions import TypeAlias
|
||||||
|
40 |
|
||||||
|
41 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^ E302
|
||||||
|
42 | ...
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
38 38 | if TYPE_CHECKING:
|
||||||
|
39 39 | from typing_extensions import TypeAlias
|
||||||
|
40 40 |
|
||||||
|
41 |+
|
||||||
|
41 42 | def __call__2(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
42 43 | ...
|
||||||
|
43 44 |
|
||||||
|
|
||||||
|
E30_isort.py:60:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
60 | / from typing import Any, Sequence
|
||||||
|
61 | |
|
||||||
|
62 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 61 |
|
||||||
|
62 |+
|
||||||
|
63 |+
|
||||||
|
64 |+
|
||||||
|
62 65 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
|
||||||
|
E30_isort.py:62:1: E302 [*] Expected 4 blank lines, found 1
|
||||||
|
|
|
||||||
|
60 | from typing import Any, Sequence
|
||||||
|
61 |
|
||||||
|
62 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| ^^^^^ E302
|
||||||
|
|
|
||||||
|
= help: Add missing blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 61 |
|
||||||
|
62 |+
|
||||||
|
63 |+
|
||||||
|
64 |+
|
||||||
|
62 65 | class MissingCommand(TypeError): ... # noqa: N818
|
|
@ -0,0 +1,135 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 |-
|
||||||
|
3 |-
|
||||||
|
4 |-
|
||||||
|
5 2 | from typing import Any, Sequence
|
||||||
|
6 3 |
|
||||||
|
7 4 |
|
||||||
|
|
||||||
|
E30_isort.py:5:1: E303 [*] Too many blank lines (3)
|
||||||
|
|
|
||||||
|
5 | from typing import Any, Sequence
|
||||||
|
| ^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 2 |
|
||||||
|
3 3 |
|
||||||
|
4 |-
|
||||||
|
5 4 | from typing import Any, Sequence
|
||||||
|
6 5 |
|
||||||
|
7 6 |
|
||||||
|
|
||||||
|
E30_isort.py:21:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
17 17 | if __name__ == "__main__":
|
||||||
|
18 18 | import abcd
|
||||||
|
19 19 |
|
||||||
|
20 |-
|
||||||
|
21 20 | abcd.foo()
|
||||||
|
22 21 |
|
||||||
|
23 22 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:30:5: E303 [*] Too many blank lines (3)
|
||||||
|
|
|
||||||
|
30 | from typing_extensions import TypeAlias
|
||||||
|
| ^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:33:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
29 29 |
|
||||||
|
30 30 | from typing_extensions import TypeAlias
|
||||||
|
31 31 |
|
||||||
|
32 |-
|
||||||
|
33 32 | abcd.foo()
|
||||||
|
34 33 |
|
||||||
|
35 34 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
||||||
|
E30_isort.py:60:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
60 | / from typing import Any, Sequence
|
||||||
|
61 | |
|
||||||
|
62 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 61 |
|
||||||
|
62 |+
|
||||||
|
62 63 | class MissingCommand(TypeError): ... # noqa: N818
|
|
@ -0,0 +1,171 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 |-
|
||||||
|
3 |-
|
||||||
|
4 |-
|
||||||
|
5 2 | from typing import Any, Sequence
|
||||||
|
6 |-
|
||||||
|
7 |-
|
||||||
|
8 3 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 4 |
|
||||||
|
10 5 |
|
||||||
|
|
||||||
|
E30_isort.py:5:1: E303 [*] Too many blank lines (3)
|
||||||
|
|
|
||||||
|
5 | from typing import Any, Sequence
|
||||||
|
| ^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 2 |
|
||||||
|
3 3 |
|
||||||
|
4 |-
|
||||||
|
5 4 | from typing import Any, Sequence
|
||||||
|
6 5 |
|
||||||
|
7 6 |
|
||||||
|
|
||||||
|
E30_isort.py:8:1: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
8 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| ^^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
3 3 |
|
||||||
|
4 4 |
|
||||||
|
5 5 | from typing import Any, Sequence
|
||||||
|
6 |-
|
||||||
|
7 |-
|
||||||
|
8 6 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 7 |
|
||||||
|
10 8 |
|
||||||
|
|
||||||
|
E30_isort.py:21:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
17 17 | if __name__ == "__main__":
|
||||||
|
18 18 | import abcd
|
||||||
|
19 19 |
|
||||||
|
20 |-
|
||||||
|
21 20 | abcd.foo()
|
||||||
|
22 21 |
|
||||||
|
23 22 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:30:5: E303 [*] Too many blank lines (3)
|
||||||
|
|
|
||||||
|
30 | from typing_extensions import TypeAlias
|
||||||
|
| ^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:33:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
29 29 |
|
||||||
|
30 30 | from typing_extensions import TypeAlias
|
||||||
|
31 31 |
|
||||||
|
32 |-
|
||||||
|
33 32 | abcd.foo()
|
||||||
|
34 33 |
|
||||||
|
35 34 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
||||||
|
E30_isort.py:60:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
60 | / from typing import Any, Sequence
|
||||||
|
61 | |
|
||||||
|
62 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
58 58 |
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 |-
|
||||||
|
62 61 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
|
||||||
|
E30_isort.py:62:1: E303 [*] Too many blank lines (1)
|
||||||
|
|
|
||||||
|
60 | from typing import Any, Sequence
|
||||||
|
61 |
|
||||||
|
62 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| ^^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
58 58 |
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 |-
|
||||||
|
62 61 | class MissingCommand(TypeError): ... # noqa: N818
|
|
@ -0,0 +1,137 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 2 |
|
||||||
|
3 |-
|
||||||
|
4 |-
|
||||||
|
5 3 | from typing import Any, Sequence
|
||||||
|
6 |-
|
||||||
|
7 4 |
|
||||||
|
8 5 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 6 |
|
||||||
|
|
||||||
|
E30_isort.py:5:1: E303 [*] Too many blank lines (3)
|
||||||
|
|
|
||||||
|
5 | from typing import Any, Sequence
|
||||||
|
| ^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
1 1 | import json
|
||||||
|
2 2 |
|
||||||
|
3 3 |
|
||||||
|
4 |-
|
||||||
|
5 4 | from typing import Any, Sequence
|
||||||
|
6 5 |
|
||||||
|
7 6 |
|
||||||
|
|
||||||
|
E30_isort.py:8:1: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
8 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| ^^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
4 4 |
|
||||||
|
5 5 | from typing import Any, Sequence
|
||||||
|
6 6 |
|
||||||
|
7 |-
|
||||||
|
8 7 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 8 |
|
||||||
|
10 9 |
|
||||||
|
|
||||||
|
E30_isort.py:21:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
17 17 | if __name__ == "__main__":
|
||||||
|
18 18 | import abcd
|
||||||
|
19 19 |
|
||||||
|
20 |-
|
||||||
|
21 20 | abcd.foo()
|
||||||
|
22 21 |
|
||||||
|
23 22 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:30:5: E303 [*] Too many blank lines (3)
|
||||||
|
|
|
||||||
|
30 | from typing_extensions import TypeAlias
|
||||||
|
| ^^^^ E303
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:33:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
29 29 |
|
||||||
|
30 30 | from typing_extensions import TypeAlias
|
||||||
|
31 31 |
|
||||||
|
32 |-
|
||||||
|
33 32 | abcd.foo()
|
||||||
|
34 33 |
|
||||||
|
35 34 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
|
@ -0,0 +1,109 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
|
---
|
||||||
|
E30_isort.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
1 | / import json
|
||||||
|
2 | |
|
||||||
|
3 | |
|
||||||
|
4 | |
|
||||||
|
5 | | from typing import Any, Sequence
|
||||||
|
6 | |
|
||||||
|
7 | |
|
||||||
|
8 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
2 2 |
|
||||||
|
3 3 |
|
||||||
|
4 4 |
|
||||||
|
5 |+
|
||||||
|
5 6 | from typing import Any, Sequence
|
||||||
|
6 7 |
|
||||||
|
7 8 |
|
||||||
|
9 |+
|
||||||
|
10 |+
|
||||||
|
8 11 | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
9 12 |
|
||||||
|
10 13 |
|
||||||
|
|
||||||
|
E30_isort.py:21:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
21 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
22 |
|
||||||
|
23 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
17 17 | if __name__ == "__main__":
|
||||||
|
18 18 | import abcd
|
||||||
|
19 19 |
|
||||||
|
20 |-
|
||||||
|
21 20 | abcd.foo()
|
||||||
|
22 21 |
|
||||||
|
23 22 | def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
|
||||||
|
|
||||||
|
E30_isort.py:26:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
25 | if TYPE_CHECKING:
|
||||||
|
26 | / import os
|
||||||
|
27 | |
|
||||||
|
28 | |
|
||||||
|
29 | |
|
||||||
|
30 | | from typing_extensions import TypeAlias
|
||||||
|
31 | |
|
||||||
|
| |_^ I001
|
||||||
|
32 |
|
||||||
|
33 | abcd.foo()
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
25 25 | if TYPE_CHECKING:
|
||||||
|
26 26 | import os
|
||||||
|
27 27 |
|
||||||
|
28 |-
|
||||||
|
29 |-
|
||||||
|
30 28 | from typing_extensions import TypeAlias
|
||||||
|
31 29 |
|
||||||
|
32 30 |
|
||||||
|
|
||||||
|
E30_isort.py:33:5: E303 [*] Too many blank lines (2)
|
||||||
|
|
|
||||||
|
33 | abcd.foo()
|
||||||
|
| ^^^^ E303
|
||||||
|
34 |
|
||||||
|
35 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
|
||||||
|
= help: Remove extraneous blank line(s)
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
29 29 |
|
||||||
|
30 30 | from typing_extensions import TypeAlias
|
||||||
|
31 31 |
|
||||||
|
32 |-
|
||||||
|
33 32 | abcd.foo()
|
||||||
|
34 33 |
|
||||||
|
35 34 | def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
|
||||||
|
E30_isort.py:60:1: I001 [*] Import block is un-sorted or un-formatted
|
||||||
|
|
|
||||||
|
60 | / from typing import Any, Sequence
|
||||||
|
61 | |
|
||||||
|
62 | | class MissingCommand(TypeError): ... # noqa: N818
|
||||||
|
| |_^ I001
|
||||||
|
|
|
||||||
|
= help: Organize imports
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
59 59 |
|
||||||
|
60 60 | from typing import Any, Sequence
|
||||||
|
61 61 |
|
||||||
|
62 |+
|
||||||
|
63 |+
|
||||||
|
64 |+
|
||||||
|
62 65 | class MissingCommand(TypeError): ... # noqa: N818
|
|
@ -12,6 +12,7 @@ use ruff_source_file::{find_newline, LineEnding};
|
||||||
use ruff_python_ast::str::leading_quote;
|
use ruff_python_ast::str::leading_quote;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Stylist<'a> {
|
pub struct Stylist<'a> {
|
||||||
locator: &'a Locator<'a>,
|
locator: &'a Locator<'a>,
|
||||||
indentation: Indentation,
|
indentation: Indentation,
|
||||||
|
@ -145,7 +146,7 @@ impl fmt::Display for Quote {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The indentation style used in Python source code.
|
/// The indentation style used in Python source code.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Indentation(String);
|
pub struct Indentation(String);
|
||||||
|
|
||||||
impl Indentation {
|
impl Indentation {
|
||||||
|
|
|
@ -9,6 +9,7 @@ use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||||
use crate::newlines::find_newline;
|
use crate::newlines::find_newline;
|
||||||
use crate::{LineIndex, OneIndexed, SourceCode, SourceLocation};
|
use crate::{LineIndex, OneIndexed, SourceCode, SourceLocation};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Locator<'a> {
|
pub struct Locator<'a> {
|
||||||
contents: &'a str,
|
contents: &'a str,
|
||||||
index: OnceCell<LineIndex>,
|
index: OnceCell<LineIndex>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue