mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
Implement autofix support for D214, D405, D406, and D416 (#450)
This commit is contained in:
parent
659a28de02
commit
f832f88c75
6 changed files with 175 additions and 29 deletions
|
@ -303,15 +303,15 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
|||
| D211 | NoBlankLineBeforeClass | No blank lines allowed before class docstring | 🛠 |
|
||||
| D212 | MultiLineSummaryFirstLine | Multi-line docstring summary should start at the first line | |
|
||||
| D213 | MultiLineSummarySecondLine | Multi-line docstring summary should start at the second line | |
|
||||
| D214 | SectionNotOverIndented | Section is over-indented ("Returns") | |
|
||||
| D214 | SectionNotOverIndented | Section is over-indented ("Returns") | 🛠 |
|
||||
| D215 | SectionUnderlineNotOverIndented | Section underline is over-indented ("Returns") | 🛠 |
|
||||
| D300 | UsesTripleQuotes | Use """triple double quotes""" | |
|
||||
| D400 | EndsInPeriod | First line should end with a period | |
|
||||
| D402 | NoSignature | First line should not be the function's 'signature' | |
|
||||
| D403 | FirstLineCapitalized | First word of the first line should be properly capitalized | |
|
||||
| D404 | NoThisPrefix | First word of the docstring should not be `This` | |
|
||||
| D405 | CapitalizeSectionName | Section name should be properly capitalized ("returns") | |
|
||||
| D406 | NewLineAfterSectionName | Section name should end with a newline ("Returns") | |
|
||||
| D405 | CapitalizeSectionName | Section name should be properly capitalized ("returns") | 🛠 |
|
||||
| D406 | NewLineAfterSectionName | Section name should end with a newline ("Returns") | 🛠 |
|
||||
| D407 | DashedUnderlineAfterSection | Missing dashed underline after section ("Returns") | 🛠 |
|
||||
| D408 | SectionUnderlineAfterName | Section underline should be in the line following the section's name ("Returns") | |
|
||||
| D409 | SectionUnderlineMatchesSectionLength | Section underline should match the length of its name ("Returns") | 🛠 |
|
||||
|
@ -321,7 +321,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
|||
| D413 | BlankLineAfterLastSection | Missing blank line after last section ("Returns") | 🛠 |
|
||||
| D414 | NonEmptySection | Section has no content ("Returns") | |
|
||||
| D415 | EndsInPunctuation | First line should end with a period, question mark, or exclamation point | |
|
||||
| D416 | SectionNameEndsInColon | Section name should end with a colon ("Returns") | |
|
||||
| D416 | SectionNameEndsInColon | Section name should end with a colon ("Returns") | 🛠 |
|
||||
| D417 | DocumentAllArguments | Missing argument descriptions in the docstring: `x`, `y` | |
|
||||
| D418 | SkipDocstring | Function decorated with @overload shouldn't contain a docstring | |
|
||||
| D419 | NonEmpty | Docstring is empty | |
|
||||
|
@ -399,6 +399,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
|||
| ---- | ---- | ------- | --- |
|
||||
| M001 | UnusedNOQA | Unused `noqa` directive | 🛠 |
|
||||
|
||||
|
||||
## Editor Integrations
|
||||
|
||||
### PyCharm
|
||||
|
|
|
@ -1208,11 +1208,13 @@ impl CheckKind {
|
|||
| CheckKind::BlankLineAfterSection(_)
|
||||
| CheckKind::BlankLineAfterSummary
|
||||
| CheckKind::BlankLineBeforeSection(_)
|
||||
| CheckKind::CapitalizeSectionName(_)
|
||||
| CheckKind::DashedUnderlineAfterSection(_)
|
||||
| CheckKind::DeprecatedUnittestAlias(_, _)
|
||||
| CheckKind::DoNotAssertFalse
|
||||
| CheckKind::DuplicateHandlerException(_)
|
||||
| CheckKind::NewLineAfterLastParagraph
|
||||
| CheckKind::NewLineAfterSectionName(_)
|
||||
| CheckKind::NoBlankLineAfterFunction(_)
|
||||
| CheckKind::NoBlankLineBeforeClass(_)
|
||||
| CheckKind::NoBlankLineBeforeFunction(_)
|
||||
|
@ -1222,6 +1224,8 @@ impl CheckKind {
|
|||
| CheckKind::OneBlankLineBeforeClass(_)
|
||||
| CheckKind::PPrintFound
|
||||
| CheckKind::PrintFound
|
||||
| CheckKind::SectionNameEndsInColon(_)
|
||||
| CheckKind::SectionNotOverIndented(_)
|
||||
| CheckKind::SectionUnderlineMatchesSectionLength(_)
|
||||
| CheckKind::SectionUnderlineNotOverIndented(_)
|
||||
| CheckKind::SuperCallWithParameters
|
||||
|
|
|
@ -4,7 +4,6 @@ use itertools::Itertools;
|
|||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind};
|
||||
use titlecase::titlecase;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::fixer;
|
||||
|
@ -1099,25 +1098,61 @@ fn common_section(
|
|||
if !style
|
||||
.section_names()
|
||||
.contains(&context.section_name.as_str())
|
||||
&& style
|
||||
.section_names()
|
||||
.contains(titlecase(&context.section_name).as_str())
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
let capitalized_section_name = titlecase::titlecase(&context.section_name);
|
||||
if style
|
||||
.section_names()
|
||||
.contains(capitalized_section_name.as_str())
|
||||
{
|
||||
let mut check = Check::new(
|
||||
CheckKind::CapitalizeSectionName(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
);
|
||||
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||
// Replace the section title with the capitalized variant. This requires
|
||||
// locating the start and end of the section name.
|
||||
if let Some(index) = context.line.find(&context.section_name) {
|
||||
// Map from bytes to characters.
|
||||
let section_name_start = &context.line[..index].chars().count();
|
||||
let section_name_length = &context.section_name.chars().count();
|
||||
check.amend(Fix::replacement(
|
||||
capitalized_section_name,
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
1 + section_name_start,
|
||||
),
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
1 + section_name_start + section_name_length,
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D214) {
|
||||
if helpers::leading_space(context.line).len()
|
||||
> helpers::indentation(checker, docstring).len()
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
let leading_space = helpers::leading_space(context.line);
|
||||
let indentation = helpers::indentation(checker, docstring).to_string();
|
||||
if leading_space.len() > indentation.len() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionNotOverIndented(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
))
|
||||
);
|
||||
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||
// Replace the existing indentation with whitespace of the appropriate length.
|
||||
check.amend(Fix::replacement(
|
||||
indentation,
|
||||
Location::new(docstring.location.row() + context.original_index, 1),
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
1 + leading_space.len(),
|
||||
),
|
||||
));
|
||||
};
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1144,7 +1179,7 @@ fn common_section(
|
|||
+ context.following_lines.len(),
|
||||
1,
|
||||
),
|
||||
))
|
||||
));
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
|
@ -1334,10 +1369,31 @@ fn numpy_section(checker: &mut Checker, definition: &Definition, context: &Secti
|
|||
let docstring = definition
|
||||
.docstring
|
||||
.expect("Sections are only available for docstrings.");
|
||||
checker.add_check(Check::new(
|
||||
let mut check = Check::new(
|
||||
CheckKind::NewLineAfterSectionName(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
))
|
||||
);
|
||||
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||
// Delete the suffix. This requires locating the end of the section name.
|
||||
if let Some(index) = context.line.find(&context.section_name) {
|
||||
// Map from bytes to characters.
|
||||
let suffix_start = &context.line[..index + context.section_name.len()]
|
||||
.chars()
|
||||
.count();
|
||||
let suffix_length = suffix.chars().count();
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
1 + suffix_start,
|
||||
),
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
1 + suffix_start + suffix_length,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
checker.add_check(check)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1362,10 +1418,32 @@ fn google_section(checker: &mut Checker, definition: &Definition, context: &Sect
|
|||
let docstring = definition
|
||||
.docstring
|
||||
.expect("Sections are only available for docstrings.");
|
||||
checker.add_check(Check::new(
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionNameEndsInColon(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
))
|
||||
);
|
||||
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||
// Replace the suffix. This requires locating the end of the section name.
|
||||
if let Some(index) = context.line.find(&context.section_name) {
|
||||
// Map from bytes to characters.
|
||||
let suffix_start = &context.line[..index + context.section_name.len()]
|
||||
.chars()
|
||||
.count();
|
||||
let suffix_length = suffix.chars().count();
|
||||
check.amend(Fix::replacement(
|
||||
":".to_string(),
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
1 + suffix_start,
|
||||
),
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
1 + suffix_start + suffix_length,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,5 +10,14 @@ expression: checks
|
|||
end_location:
|
||||
row: 141
|
||||
column: 8
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: " "
|
||||
location:
|
||||
row: 137
|
||||
column: 1
|
||||
end_location:
|
||||
row: 137
|
||||
column: 9
|
||||
applied: false
|
||||
|
||||
|
|
|
@ -10,7 +10,16 @@ expression: checks
|
|||
end_location:
|
||||
row: 23
|
||||
column: 8
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: Returns
|
||||
location:
|
||||
row: 19
|
||||
column: 5
|
||||
end_location:
|
||||
row: 19
|
||||
column: 12
|
||||
applied: false
|
||||
- kind:
|
||||
CapitalizeSectionName: Short summary
|
||||
location:
|
||||
|
@ -19,5 +28,14 @@ expression: checks
|
|||
end_location:
|
||||
row: 221
|
||||
column: 8
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: Short Summary
|
||||
location:
|
||||
row: 209
|
||||
column: 5
|
||||
end_location:
|
||||
row: 209
|
||||
column: 18
|
||||
applied: false
|
||||
|
||||
|
|
|
@ -10,7 +10,16 @@ expression: checks
|
|||
end_location:
|
||||
row: 36
|
||||
column: 8
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 32
|
||||
column: 12
|
||||
end_location:
|
||||
row: 32
|
||||
column: 13
|
||||
applied: false
|
||||
- kind:
|
||||
NewLineAfterSectionName: Raises
|
||||
location:
|
||||
|
@ -19,7 +28,16 @@ expression: checks
|
|||
end_location:
|
||||
row: 221
|
||||
column: 8
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 218
|
||||
column: 11
|
||||
end_location:
|
||||
row: 218
|
||||
column: 12
|
||||
applied: false
|
||||
- kind:
|
||||
NewLineAfterSectionName: Returns
|
||||
location:
|
||||
|
@ -28,7 +46,16 @@ expression: checks
|
|||
end_location:
|
||||
row: 262
|
||||
column: 8
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 257
|
||||
column: 12
|
||||
end_location:
|
||||
row: 257
|
||||
column: 13
|
||||
applied: false
|
||||
- kind:
|
||||
NewLineAfterSectionName: Raises
|
||||
location:
|
||||
|
@ -37,5 +64,14 @@ expression: checks
|
|||
end_location:
|
||||
row: 262
|
||||
column: 8
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 259
|
||||
column: 11
|
||||
end_location:
|
||||
row: 259
|
||||
column: 12
|
||||
applied: false
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue