diff --git a/README.md b/README.md index 25a9ddbf2f..78290f88b6 100644 --- a/README.md +++ b/README.md @@ -380,7 +380,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI | E714 | NotIsTest | Test for object identity should be `is not` | 🛠 | | E721 | TypeComparison | Do not compare types, use `isinstance()` | | | E722 | DoNotUseBareExcept | Do not use bare `except` | | -| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | | +| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | 🛠 | | E741 | AmbiguousVariableName | Ambiguous variable name: `...` | | | E742 | AmbiguousClassName | Ambiguous class name: `...` | | | E743 | AmbiguousFunctionName | Ambiguous function name: `...` | | diff --git a/src/ast/helpers.rs b/src/ast/helpers.rs index 46e1b040ac..150d722c1d 100644 --- a/src/ast/helpers.rs +++ b/src/ast/helpers.rs @@ -1,7 +1,10 @@ use fnv::{FnvHashMap, FnvHashSet}; use once_cell::sync::Lazy; use regex::Regex; -use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, StmtKind}; +use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind}; + +use crate::ast::types::Range; +use crate::SourceCodeLocator; #[inline(always)] fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut Vec<&'a str>) { @@ -261,6 +264,34 @@ pub fn to_absolute(relative: &Location, base: &Location) -> Location { } } +/// Return `true` if a `Stmt` has leading content. +pub fn match_leading_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool { + let range = Range { + location: Location::new(stmt.location.row(), 0), + end_location: stmt.location, + }; + let prefix = locator.slice_source_code_range(&range); + prefix.chars().any(|char| !char.is_whitespace()) +} + +/// Return `true` if a `Stmt` has trailing content. +pub fn match_trailing_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool { + let range = Range { + location: stmt.end_location.unwrap(), + end_location: Location::new(stmt.end_location.unwrap().row() + 1, 0), + }; + let suffix = locator.slice_source_code_range(&range); + for char in suffix.chars() { + if char == '#' { + return false; + } + if !char.is_whitespace() { + return true; + } + } + false +} + #[cfg(test)] mod tests { use anyhow::Result; diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 3b9a2fcd32..9bdb26a1c7 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -3,3 +3,4 @@ pub mod operations; pub mod relocate; pub mod types; pub mod visitor; +pub mod whitespace; diff --git a/src/docstrings/helpers.rs b/src/ast/whitespace.rs similarity index 83% rename from src/docstrings/helpers.rs rename to src/ast/whitespace.rs index 8249ede685..7f11861241 100644 --- a/src/docstrings/helpers.rs +++ b/src/ast/whitespace.rs @@ -3,12 +3,6 @@ use rustpython_ast::{Located, Location}; use crate::ast::types::Range; use crate::check_ast::Checker; -pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[ - "ur\"\"\"", "ur'''", "u\"\"\"", "u'''", "r\"\"\"", "r'''", "\"\"\"", "'''", -]; - -pub const SINGLE_QUOTE_PREFIXES: &[&str] = &["ur\"", "ur'", "u\"", "u'", "r\"", "r'", "\"", "'"]; - /// Extract the leading words from a line of text. pub fn leading_words(line: &str) -> String { line.trim() diff --git a/src/check_ast.rs b/src/check_ast.rs index 84fff9acb6..93d6c0add3 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -981,11 +981,7 @@ where StmtKind::Assign { targets, value, .. } => { if self.settings.enabled.contains(&CheckCode::E731) { if let [target] = &targets[..] { - if let Some(check) = - pycodestyle::checks::do_not_assign_lambda(target, value, stmt) - { - self.add_check(check); - } + pycodestyle::plugins::do_not_assign_lambda(self, target, value, stmt) } } if self.settings.enabled.contains(&CheckCode::U001) { @@ -1010,11 +1006,7 @@ where StmtKind::AnnAssign { target, value, .. } => { if self.settings.enabled.contains(&CheckCode::E731) { if let Some(value) = value { - if let Some(check) = - pycodestyle::checks::do_not_assign_lambda(target, value, stmt) - { - self.add_check(check); - } + pycodestyle::plugins::do_not_assign_lambda(self, target, value, stmt); } } } diff --git a/src/checks.rs b/src/checks.rs index 3b238465fc..993ebb3770 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -2038,46 +2038,51 @@ impl CheckKind { pub fn fixable(&self) -> bool { matches!( self, - CheckKind::AmbiguousUnicodeCharacterString(_, _) - | CheckKind::AmbiguousUnicodeCharacterDocstring(_, _) - | CheckKind::BlankLineAfterLastSection(_) - | CheckKind::BlankLineAfterSection(_) + CheckKind::AmbiguousUnicodeCharacterString(..) + | CheckKind::AmbiguousUnicodeCharacterDocstring(..) + | CheckKind::BlankLineAfterLastSection(..) + | CheckKind::BlankLineAfterSection(..) | CheckKind::BlankLineAfterSummary - | CheckKind::BlankLineBeforeSection(_) - | CheckKind::CapitalizeSectionName(_) - | CheckKind::DashedUnderlineAfterSection(_) - | CheckKind::DeprecatedUnittestAlias(_, _) + | CheckKind::BlankLineBeforeSection(..) + | CheckKind::CapitalizeSectionName(..) + | CheckKind::ConvertTypedDictFunctionalToClass + | CheckKind::DashedUnderlineAfterSection(..) + | CheckKind::DeprecatedUnittestAlias(..) | CheckKind::DoNotAssertFalse - | CheckKind::DuplicateHandlerException(_) + | CheckKind::DoNotAssignLambda + | CheckKind::DuplicateHandlerException(..) | CheckKind::GetAttrWithConstant | CheckKind::IsLiteral | CheckKind::NewLineAfterLastParagraph - | CheckKind::NewLineAfterSectionName(_) - | CheckKind::NoBlankLineAfterFunction(_) - | CheckKind::NoBlankLineBeforeClass(_) - | CheckKind::NoBlankLineBeforeFunction(_) - | CheckKind::NoBlankLinesBetweenHeaderAndContent(_) + | CheckKind::NewLineAfterSectionName(..) + | CheckKind::NoBlankLineAfterFunction(..) + | CheckKind::NoBlankLineBeforeClass(..) + | CheckKind::NoBlankLineBeforeFunction(..) + | CheckKind::NoBlankLinesBetweenHeaderAndContent(..) | CheckKind::NoOverIndentation | CheckKind::NoSurroundingWhitespace | CheckKind::NoUnderIndentation - | CheckKind::OneBlankLineAfterClass(_) - | CheckKind::OneBlankLineBeforeClass(_) + | CheckKind::NoneComparison(..) + | CheckKind::NotInTest + | CheckKind::NotIsTest + | CheckKind::OneBlankLineAfterClass(..) + | CheckKind::OneBlankLineBeforeClass(..) | CheckKind::PEP3120UnnecessaryCodingComment | CheckKind::PPrintFound | CheckKind::PrintFound | CheckKind::RaiseNotImplemented - | CheckKind::SectionNameEndsInColon(_) - | CheckKind::SectionNotOverIndented(_) - | CheckKind::SectionUnderlineAfterName(_) - | CheckKind::SectionUnderlineMatchesSectionLength(_) - | CheckKind::SectionUnderlineNotOverIndented(_) + | CheckKind::SectionNameEndsInColon(..) + | CheckKind::SectionNotOverIndented(..) + | CheckKind::SectionUnderlineAfterName(..) + | CheckKind::SectionUnderlineMatchesSectionLength(..) + | CheckKind::SectionUnderlineNotOverIndented(..) | CheckKind::SuperCallWithParameters - | CheckKind::TypeOfPrimitive(_) - | CheckKind::UnnecessaryCollectionCall(_) - | CheckKind::UnnecessaryComprehension(_) + | CheckKind::TrueFalseComparison(..) + | CheckKind::TypeOfPrimitive(..) + | CheckKind::UnnecessaryCollectionCall(..) + | CheckKind::UnnecessaryComprehension(..) | CheckKind::UnnecessaryEncodeUTF8 - | CheckKind::ConvertTypedDictFunctionalToClass - | CheckKind::UnnecessaryFutureImport(_) + | CheckKind::UnnecessaryFutureImport(..) | CheckKind::UnnecessaryGeneratorDict | CheckKind::UnnecessaryGeneratorList | CheckKind::UnnecessaryGeneratorSet @@ -2085,18 +2090,18 @@ impl CheckKind { | CheckKind::UnnecessaryListCall | CheckKind::UnnecessaryListComprehensionDict | CheckKind::UnnecessaryListComprehensionSet - | CheckKind::UnnecessaryLiteralDict(_) - | CheckKind::UnnecessaryLiteralSet(_) - | CheckKind::UnnecessaryLiteralWithinListCall(_) - | CheckKind::UnnecessaryLiteralWithinTupleCall(_) + | CheckKind::UnnecessaryLiteralDict(..) + | CheckKind::UnnecessaryLiteralSet(..) + | CheckKind::UnnecessaryLiteralWithinListCall(..) + | CheckKind::UnnecessaryLiteralWithinTupleCall(..) | CheckKind::UnsortedImports | CheckKind::UnusedImport(_, false) - | CheckKind::UnusedLoopControlVariable(_) - | CheckKind::UnusedNOQA(_) - | CheckKind::UsePEP585Annotation(_) + | CheckKind::UnusedLoopControlVariable(..) + | CheckKind::UnusedNOQA(..) + | CheckKind::UsePEP585Annotation(..) | CheckKind::UsePEP604Annotation | CheckKind::UselessMetaclassType - | CheckKind::UselessObjectInheritance(_) + | CheckKind::UselessObjectInheritance(..) ) } } diff --git a/src/docstrings/constants.rs b/src/docstrings/constants.rs new file mode 100644 index 0000000000..6ebcaec66e --- /dev/null +++ b/src/docstrings/constants.rs @@ -0,0 +1,5 @@ +pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[ + "ur\"\"\"", "ur'''", "u\"\"\"", "u'''", "r\"\"\"", "r'''", "\"\"\"", "'''", +]; + +pub const SINGLE_QUOTE_PREFIXES: &[&str] = &["ur\"", "ur'", "u\"", "u'", "r\"", "r'", "\"", "'"]; diff --git a/src/docstrings/mod.rs b/src/docstrings/mod.rs index 1c19b1f217..6c0f85022a 100644 --- a/src/docstrings/mod.rs +++ b/src/docstrings/mod.rs @@ -1,7 +1,7 @@ +pub mod constants; pub mod definition; pub mod extraction; pub mod google; -pub mod helpers; pub mod numpy; pub mod sections; pub mod styles; diff --git a/src/docstrings/sections.rs b/src/docstrings/sections.rs index d87fa8162c..cab413569f 100644 --- a/src/docstrings/sections.rs +++ b/src/docstrings/sections.rs @@ -1,4 +1,4 @@ -use crate::docstrings::helpers; +use crate::ast::whitespace; use crate::docstrings::styles::SectionStyle; #[derive(Debug)] @@ -14,7 +14,7 @@ pub(crate) struct SectionContext<'a> { fn suspected_as_section(line: &str, style: &SectionStyle) -> bool { style .lowercase_section_names() - .contains(&helpers::leading_words(line).to_lowercase().as_str()) + .contains(&whitespace::leading_words(line).to_lowercase().as_str()) } /// Check if the suspected context is really a section header. @@ -64,7 +64,7 @@ pub(crate) fn section_contexts<'a>( let mut contexts = vec![]; for lineno in suspected_section_indices { let context = SectionContext { - section_name: helpers::leading_words(lines[lineno]), + section_name: whitespace::leading_words(lines[lineno]), previous_line: lines[lineno - 1], line: lines[lineno], following_lines: &lines[lineno + 1..], diff --git a/src/isort/plugins.rs b/src/isort/plugins.rs index e6f0867ac8..9b862d9f72 100644 --- a/src/isort/plugins.rs +++ b/src/isort/plugins.rs @@ -1,10 +1,11 @@ use rustpython_ast::{Location, Stmt}; use textwrap::{dedent, indent}; +use crate::ast::helpers::{match_leading_content, match_trailing_content}; use crate::ast::types::Range; +use crate::ast::whitespace::leading_space; use crate::autofix::{fixer, Fix}; use crate::checks::CheckKind; -use crate::docstrings::helpers::leading_space; use crate::isort::{comments, format_imports}; use crate::{Check, Settings, SourceCodeLocator}; @@ -27,34 +28,6 @@ fn extract_indentation(body: &[&Stmt], locator: &SourceCodeLocator) -> String { leading_space(&existing) } -fn match_leading_content(body: &[&Stmt], locator: &SourceCodeLocator) -> bool { - let location = body.first().unwrap().location; - let range = Range { - location: Location::new(location.row(), 0), - end_location: location, - }; - let prefix = locator.slice_source_code_range(&range); - prefix.chars().any(|char| !char.is_whitespace()) -} - -fn match_trailing_content(body: &[&Stmt], locator: &SourceCodeLocator) -> bool { - let end_location = body.last().unwrap().end_location.unwrap(); - let range = Range { - location: end_location, - end_location: Location::new(end_location.row() + 1, 0), - }; - let suffix = locator.slice_source_code_range(&range); - for char in suffix.chars() { - if char == '#' { - return false; - } - if !char.is_whitespace() { - return true; - } - } - false -} - /// I001 pub fn check_imports( body: Vec<&Stmt>, @@ -75,8 +48,8 @@ pub fn check_imports( ); // Special-cases: there's leading or trailing content in the import block. - let has_leading_content = match_leading_content(&body, locator); - let has_trailing_content = match_trailing_content(&body, locator); + let has_leading_content = match_leading_content(body.first().unwrap(), locator); + let has_trailing_content = match_trailing_content(body.last().unwrap(), locator); // Generate the sorted import block. let expected = format_imports( diff --git a/src/pycodestyle/checks.rs b/src/pycodestyle/checks.rs index 6b76617194..13730f6107 100644 --- a/src/pycodestyle/checks.rs +++ b/src/pycodestyle/checks.rs @@ -1,6 +1,6 @@ use itertools::izip; use rustpython_ast::Location; -use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Stmt}; +use rustpython_parser::ast::{Cmpop, Expr, ExprKind}; use crate::ast::types::Range; use crate::checks::{Check, CheckKind}; @@ -46,19 +46,6 @@ pub fn ambiguous_function_name(name: &str, location: Range) -> Option { } } -/// E731 -pub fn do_not_assign_lambda(target: &Expr, value: &Expr, stmt: &Stmt) -> Option { - if let ExprKind::Name { .. } = &target.node { - if let ExprKind::Lambda { .. } = &value.node { - return Some(Check::new( - CheckKind::DoNotAssignLambda, - Range::from_located(stmt), - )); - } - } - None -} - /// E721 pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) -> Vec { let mut checks: Vec = vec![]; diff --git a/src/pycodestyle/plugins.rs b/src/pycodestyle/plugins.rs index fd6b96109e..eeb40ae389 100644 --- a/src/pycodestyle/plugins.rs +++ b/src/pycodestyle/plugins.rs @@ -1,8 +1,13 @@ +use anyhow::Result; use fnv::FnvHashMap; use itertools::izip; -use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Unaryop}; +use log::error; +use rustpython_ast::{Arguments, Location, StmtKind}; +use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Stmt, Unaryop}; +use crate::ast::helpers::{match_leading_content, match_trailing_content}; use crate::ast::types::Range; +use crate::ast::whitespace::leading_space; use crate::autofix::Fix; use crate::check_ast::Checker; use crate::checks::{Check, CheckKind, RejectedCmpop}; @@ -260,3 +265,69 @@ pub fn not_tests( } } } + +fn function(name: &str, args: &Arguments, body: &Expr) -> Result { + let body = Stmt::new( + Default::default(), + Default::default(), + StmtKind::Return { + value: Some(Box::new(body.clone())), + }, + ); + let func = Stmt::new( + Default::default(), + Default::default(), + StmtKind::FunctionDef { + name: name.to_string(), + args: Box::new(args.clone()), + body: vec![body], + decorator_list: vec![], + returns: None, + type_comment: None, + }, + ); + let mut generator = SourceGenerator::new(); + generator.unparse_stmt(&func)?; + generator.generate().map_err(|e| e.into()) +} + +/// E731 +pub fn do_not_assign_lambda(checker: &mut Checker, target: &Expr, value: &Expr, stmt: &Stmt) { + if let ExprKind::Name { id, .. } = &target.node { + if let ExprKind::Lambda { args, body } = &value.node { + let mut check = Check::new(CheckKind::DoNotAssignLambda, Range::from_located(stmt)); + if checker.patch(check.kind.code()) { + if !match_leading_content(stmt, checker.locator) + && !match_trailing_content(stmt, checker.locator) + { + match function(id, args, body) { + Ok(content) => { + let indentation = + &leading_space(&checker.locator.slice_source_code_range(&Range { + location: Location::new(stmt.location.row(), 0), + end_location: Location::new(stmt.location.row() + 1, 0), + })); + let mut indented = String::new(); + for (idx, line) in content.lines().enumerate() { + if idx == 0 { + indented.push_str(line); + } else { + indented.push('\n'); + indented.push_str(indentation); + indented.push_str(line); + } + } + check.amend(Fix::replacement( + indented, + stmt.location, + stmt.end_location.unwrap(), + )); + } + Err(e) => error!("Failed to generate fix: {}", e), + } + } + } + checker.add_check(check); + } + } +} diff --git a/src/pydocstyle/plugins.rs b/src/pydocstyle/plugins.rs index 78db55e391..42a3bade93 100644 --- a/src/pydocstyle/plugins.rs +++ b/src/pydocstyle/plugins.rs @@ -7,11 +7,12 @@ use regex::Regex; use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind}; use crate::ast::types::Range; +use crate::ast::whitespace; use crate::autofix::Fix; use crate::check_ast::Checker; use crate::checks::{Check, CheckCode, CheckKind}; +use crate::docstrings::constants; use crate::docstrings::definition::{Definition, DefinitionKind}; -use crate::docstrings::helpers; use crate::docstrings::sections::{section_contexts, SectionContext}; use crate::docstrings::styles::SectionStyle; use crate::visibility::{is_init, is_magic, is_overload, is_staticmethod, Visibility}; @@ -391,7 +392,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) { return; } - let docstring_indent = helpers::indentation(checker, docstring); + let docstring_indent = whitespace::indentation(checker, docstring); let mut has_seen_tab = docstring_indent.contains('\t'); let mut is_over_indented = true; let mut over_indented_lines = vec![]; @@ -408,7 +409,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) { continue; } - let line_indent = helpers::leading_space(lines[i]); + let line_indent = whitespace::leading_space(lines[i]); // We only report tab indentation once, so only check if we haven't seen a tab // yet. @@ -427,7 +428,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) { ); if checker.patch(check.kind.code()) { check.amend(Fix::replacement( - helpers::clean(&docstring_indent), + whitespace::clean(&docstring_indent), Location::new(docstring.location.row() + i, 0), Location::new(docstring.location.row() + i, line_indent.len()), )); @@ -464,7 +465,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) { // If every line (except the last) is over-indented... if is_over_indented { for i in over_indented_lines { - let line_indent = helpers::leading_space(lines[i]); + let line_indent = whitespace::leading_space(lines[i]); if line_indent.len() > docstring_indent.len() { // We report over-indentation on every line. This isn't great, but // enables autofix. @@ -477,7 +478,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) { ); if checker.patch(check.kind.code()) { check.amend(Fix::replacement( - helpers::clean(&docstring_indent), + whitespace::clean(&docstring_indent), Location::new(docstring.location.row() + i, 0), Location::new(docstring.location.row() + i, line_indent.len()), )); @@ -490,7 +491,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) { // If the last line is over-indented... if !lines.is_empty() { let i = lines.len() - 1; - let line_indent = helpers::leading_space(lines[i]); + let line_indent = whitespace::leading_space(lines[i]); if line_indent.len() > docstring_indent.len() { let mut check = Check::new( CheckKind::NoOverIndentation, @@ -501,7 +502,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) { ); if checker.patch(check.kind.code()) { check.amend(Fix::replacement( - helpers::clean(&docstring_indent), + whitespace::clean(&docstring_indent), Location::new(docstring.location.row() + i, 0), Location::new(docstring.location.row() + i, line_indent.len()), )); @@ -541,7 +542,7 @@ pub fn newline_after_last_paragraph(checker: &mut Checker, definition: &Definiti // Insert a newline just before the end-quote(s). let content = format!( "\n{}", - helpers::clean(&helpers::indentation(checker, docstring)) + whitespace::clean(&whitespace::indentation(checker, docstring)) ); check.amend(Fix::insertion( content, @@ -588,9 +589,9 @@ pub fn no_surrounding_whitespace(checker: &mut Checker, definition: &Definition) .next() .map(|line| line.to_lowercase()) { - for pattern in helpers::TRIPLE_QUOTE_PREFIXES + for pattern in constants::TRIPLE_QUOTE_PREFIXES .iter() - .chain(helpers::SINGLE_QUOTE_PREFIXES) + .chain(constants::SINGLE_QUOTE_PREFIXES) { if first_line.starts_with(pattern) { check.amend(Fix::replacement( @@ -634,7 +635,7 @@ pub fn multi_line_summary_start(checker: &mut Checker, definition: &Definition) .next() .map(|line| line.to_lowercase()) { - if helpers::TRIPLE_QUOTE_PREFIXES.contains(&first_line.as_str()) { + if constants::TRIPLE_QUOTE_PREFIXES.contains(&first_line.as_str()) { if checker.settings.enabled.contains(&CheckCode::D212) { checker.add_check(Check::new( CheckKind::MultiLineSummaryFirstLine, @@ -920,7 +921,7 @@ fn blanks_and_section_underline( // Add a dashed line (of the appropriate length) under the section header. let content = format!( "{}{}\n", - helpers::clean(&helpers::indentation(checker, docstring)), + whitespace::clean(&whitespace::indentation(checker, docstring)), "-".repeat(context.section_name.len()) ); check.amend(Fix::insertion( @@ -954,7 +955,7 @@ fn blanks_and_section_underline( // Add a dashed line (of the appropriate length) under the section header. let content = format!( "{}{}\n", - helpers::clean(&helpers::indentation(checker, docstring)), + whitespace::clean(&whitespace::indentation(checker, docstring)), "-".repeat(context.section_name.len()) ); check.amend(Fix::insertion( @@ -1030,7 +1031,7 @@ fn blanks_and_section_underline( // Replace the existing underline with a line of the appropriate length. let content = format!( "{}{}\n", - helpers::clean(&helpers::indentation(checker, docstring)), + whitespace::clean(&whitespace::indentation(checker, docstring)), "-".repeat(context.section_name.len()) ); check.amend(Fix::replacement( @@ -1057,8 +1058,8 @@ fn blanks_and_section_underline( } if checker.settings.enabled.contains(&CheckCode::D215) { - let leading_space = helpers::leading_space(non_empty_line); - let indentation = helpers::indentation(checker, docstring); + let leading_space = whitespace::leading_space(non_empty_line); + let indentation = whitespace::indentation(checker, docstring); if leading_space.len() > indentation.len() { let mut check = Check::new( CheckKind::SectionUnderlineNotOverIndented(context.section_name.to_string()), @@ -1067,7 +1068,7 @@ fn blanks_and_section_underline( if checker.patch(check.kind.code()) { // Replace the existing indentation with whitespace of the appropriate length. check.amend(Fix::replacement( - helpers::clean(&indentation), + whitespace::clean(&indentation), Location::new( docstring.location.row() + context.original_index @@ -1198,8 +1199,8 @@ fn common_section( } if checker.settings.enabled.contains(&CheckCode::D214) { - let leading_space = helpers::leading_space(context.line); - let indentation = helpers::indentation(checker, docstring); + let leading_space = whitespace::leading_space(context.line); + let indentation = whitespace::indentation(checker, docstring); if leading_space.len() > indentation.len() { let mut check = Check::new( CheckKind::SectionNotOverIndented(context.section_name.to_string()), @@ -1208,7 +1209,7 @@ fn common_section( if checker.patch(check.kind.code()) { // Replace the existing indentation with whitespace of the appropriate length. check.amend(Fix::replacement( - helpers::clean(&indentation), + whitespace::clean(&indentation), Location::new(docstring.location.row() + context.original_index, 0), Location::new( docstring.location.row() + context.original_index, @@ -1400,13 +1401,13 @@ fn args_section(checker: &mut Checker, definition: &Definition, context: &Sectio fn parameters_section(checker: &mut Checker, definition: &Definition, context: &SectionContext) { // Collect the list of arguments documented in the docstring. let mut docstring_args: FnvHashSet<&str> = FnvHashSet::default(); - let section_level_indent = helpers::leading_space(context.line); + let section_level_indent = whitespace::leading_space(context.line); for i in 1..context.following_lines.len() { let current_line = context.following_lines[i - 1]; - let current_leading_space = helpers::leading_space(current_line); + let current_leading_space = whitespace::leading_space(current_line); let next_line = context.following_lines[i]; if current_leading_space == section_level_indent - && (helpers::leading_space(next_line).len() > current_leading_space.len()) + && (whitespace::leading_space(next_line).len() > current_leading_space.len()) && !next_line.trim().is_empty() { let parameters = if let Some(semi_index) = current_line.find(':') { diff --git a/src/snapshots/ruff__linter__tests__E731_E731.py.snap b/src/snapshots/ruff__linter__tests__E731_E731.py.snap index 476613bc9e..daf8c8f058 100644 --- a/src/snapshots/ruff__linter__tests__E731_E731.py.snap +++ b/src/snapshots/ruff__linter__tests__E731_E731.py.snap @@ -9,7 +9,16 @@ expression: checks end_location: row: 2 column: 19 - fix: ~ + fix: + patch: + content: "def f(x):\n return (2 * x)" + location: + row: 2 + column: 0 + end_location: + row: 2 + column: 19 + applied: false - kind: DoNotAssignLambda location: row: 4 @@ -17,7 +26,16 @@ expression: checks end_location: row: 4 column: 19 - fix: ~ + fix: + patch: + content: "def f(x):\n return (2 * x)" + location: + row: 4 + column: 0 + end_location: + row: 4 + column: 19 + applied: false - kind: DoNotAssignLambda location: row: 7 @@ -25,5 +43,14 @@ expression: checks end_location: row: 7 column: 29 - fix: ~ + fix: + patch: + content: "def this(y, z):\n return (2 * x)" + location: + row: 7 + column: 4 + end_location: + row: 7 + column: 29 + applied: false