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 | 🛠 |
|
| D211 | NoBlankLineBeforeClass | No blank lines allowed before class docstring | 🛠 |
|
||||||
| D212 | MultiLineSummaryFirstLine | Multi-line docstring summary should start at the first line | |
|
| D212 | MultiLineSummaryFirstLine | Multi-line docstring summary should start at the first line | |
|
||||||
| D213 | MultiLineSummarySecondLine | Multi-line docstring summary should start at the second 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") | 🛠 |
|
| D215 | SectionUnderlineNotOverIndented | Section underline is over-indented ("Returns") | 🛠 |
|
||||||
| D300 | UsesTripleQuotes | Use """triple double quotes""" | |
|
| D300 | UsesTripleQuotes | Use """triple double quotes""" | |
|
||||||
| D400 | EndsInPeriod | First line should end with a period | |
|
| D400 | EndsInPeriod | First line should end with a period | |
|
||||||
| D402 | NoSignature | First line should not be the function's 'signature' | |
|
| D402 | NoSignature | First line should not be the function's 'signature' | |
|
||||||
| D403 | FirstLineCapitalized | First word of the first line should be properly capitalized | |
|
| D403 | FirstLineCapitalized | First word of the first line should be properly capitalized | |
|
||||||
| D404 | NoThisPrefix | First word of the docstring should not be `This` | |
|
| D404 | NoThisPrefix | First word of the docstring should not be `This` | |
|
||||||
| D405 | CapitalizeSectionName | Section name should be properly capitalized ("returns") | |
|
| D405 | CapitalizeSectionName | Section name should be properly capitalized ("returns") | 🛠 |
|
||||||
| D406 | NewLineAfterSectionName | Section name should end with a newline ("Returns") | |
|
| D406 | NewLineAfterSectionName | Section name should end with a newline ("Returns") | 🛠 |
|
||||||
| D407 | DashedUnderlineAfterSection | Missing dashed underline after section ("Returns") | 🛠 |
|
| D407 | DashedUnderlineAfterSection | Missing dashed underline after section ("Returns") | 🛠 |
|
||||||
| D408 | SectionUnderlineAfterName | Section underline should be in the line following the section's name ("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") | 🛠 |
|
| 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") | 🛠 |
|
| D413 | BlankLineAfterLastSection | Missing blank line after last section ("Returns") | 🛠 |
|
||||||
| D414 | NonEmptySection | Section has no content ("Returns") | |
|
| D414 | NonEmptySection | Section has no content ("Returns") | |
|
||||||
| D415 | EndsInPunctuation | First line should end with a period, question mark, or exclamation point | |
|
| 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` | |
|
| D417 | DocumentAllArguments | Missing argument descriptions in the docstring: `x`, `y` | |
|
||||||
| D418 | SkipDocstring | Function decorated with @overload shouldn't contain a docstring | |
|
| D418 | SkipDocstring | Function decorated with @overload shouldn't contain a docstring | |
|
||||||
| D419 | NonEmpty | Docstring is empty | |
|
| 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 | 🛠 |
|
| M001 | UnusedNOQA | Unused `noqa` directive | 🛠 |
|
||||||
|
|
||||||
|
|
||||||
## Editor Integrations
|
## Editor Integrations
|
||||||
|
|
||||||
### PyCharm
|
### PyCharm
|
||||||
|
|
|
@ -1208,11 +1208,13 @@ impl CheckKind {
|
||||||
| CheckKind::BlankLineAfterSection(_)
|
| CheckKind::BlankLineAfterSection(_)
|
||||||
| CheckKind::BlankLineAfterSummary
|
| CheckKind::BlankLineAfterSummary
|
||||||
| CheckKind::BlankLineBeforeSection(_)
|
| CheckKind::BlankLineBeforeSection(_)
|
||||||
|
| CheckKind::CapitalizeSectionName(_)
|
||||||
| CheckKind::DashedUnderlineAfterSection(_)
|
| CheckKind::DashedUnderlineAfterSection(_)
|
||||||
| CheckKind::DeprecatedUnittestAlias(_, _)
|
| CheckKind::DeprecatedUnittestAlias(_, _)
|
||||||
| CheckKind::DoNotAssertFalse
|
| CheckKind::DoNotAssertFalse
|
||||||
| CheckKind::DuplicateHandlerException(_)
|
| CheckKind::DuplicateHandlerException(_)
|
||||||
| CheckKind::NewLineAfterLastParagraph
|
| CheckKind::NewLineAfterLastParagraph
|
||||||
|
| CheckKind::NewLineAfterSectionName(_)
|
||||||
| CheckKind::NoBlankLineAfterFunction(_)
|
| CheckKind::NoBlankLineAfterFunction(_)
|
||||||
| CheckKind::NoBlankLineBeforeClass(_)
|
| CheckKind::NoBlankLineBeforeClass(_)
|
||||||
| CheckKind::NoBlankLineBeforeFunction(_)
|
| CheckKind::NoBlankLineBeforeFunction(_)
|
||||||
|
@ -1222,6 +1224,8 @@ impl CheckKind {
|
||||||
| CheckKind::OneBlankLineBeforeClass(_)
|
| CheckKind::OneBlankLineBeforeClass(_)
|
||||||
| CheckKind::PPrintFound
|
| CheckKind::PPrintFound
|
||||||
| CheckKind::PrintFound
|
| CheckKind::PrintFound
|
||||||
|
| CheckKind::SectionNameEndsInColon(_)
|
||||||
|
| CheckKind::SectionNotOverIndented(_)
|
||||||
| CheckKind::SectionUnderlineMatchesSectionLength(_)
|
| CheckKind::SectionUnderlineMatchesSectionLength(_)
|
||||||
| CheckKind::SectionUnderlineNotOverIndented(_)
|
| CheckKind::SectionUnderlineNotOverIndented(_)
|
||||||
| CheckKind::SuperCallWithParameters
|
| CheckKind::SuperCallWithParameters
|
||||||
|
|
|
@ -4,7 +4,6 @@ use itertools::Itertools;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind};
|
use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind};
|
||||||
use titlecase::titlecase;
|
|
||||||
|
|
||||||
use crate::ast::types::Range;
|
use crate::ast::types::Range;
|
||||||
use crate::autofix::fixer;
|
use crate::autofix::fixer;
|
||||||
|
@ -1099,25 +1098,61 @@ fn common_section(
|
||||||
if !style
|
if !style
|
||||||
.section_names()
|
.section_names()
|
||||||
.contains(&context.section_name.as_str())
|
.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);
|
||||||
CheckKind::CapitalizeSectionName(context.section_name.to_string()),
|
if style
|
||||||
Range::from_located(docstring),
|
.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 checker.settings.enabled.contains(&CheckCode::D214) {
|
||||||
if helpers::leading_space(context.line).len()
|
let leading_space = helpers::leading_space(context.line);
|
||||||
> helpers::indentation(checker, docstring).len()
|
let indentation = helpers::indentation(checker, docstring).to_string();
|
||||||
{
|
if leading_space.len() > indentation.len() {
|
||||||
checker.add_check(Check::new(
|
let mut check = Check::new(
|
||||||
CheckKind::SectionNotOverIndented(context.section_name.to_string()),
|
CheckKind::SectionNotOverIndented(context.section_name.to_string()),
|
||||||
Range::from_located(docstring),
|
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(),
|
+ context.following_lines.len(),
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
checker.add_check(check);
|
checker.add_check(check);
|
||||||
}
|
}
|
||||||
|
@ -1334,10 +1369,31 @@ fn numpy_section(checker: &mut Checker, definition: &Definition, context: &Secti
|
||||||
let docstring = definition
|
let docstring = definition
|
||||||
.docstring
|
.docstring
|
||||||
.expect("Sections are only available for docstrings.");
|
.expect("Sections are only available for docstrings.");
|
||||||
checker.add_check(Check::new(
|
let mut check = Check::new(
|
||||||
CheckKind::NewLineAfterSectionName(context.section_name.to_string()),
|
CheckKind::NewLineAfterSectionName(context.section_name.to_string()),
|
||||||
Range::from_located(docstring),
|
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
|
let docstring = definition
|
||||||
.docstring
|
.docstring
|
||||||
.expect("Sections are only available for docstrings.");
|
.expect("Sections are only available for docstrings.");
|
||||||
checker.add_check(Check::new(
|
let mut check = Check::new(
|
||||||
CheckKind::SectionNameEndsInColon(context.section_name.to_string()),
|
CheckKind::SectionNameEndsInColon(context.section_name.to_string()),
|
||||||
Range::from_located(docstring),
|
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:
|
end_location:
|
||||||
row: 141
|
row: 141
|
||||||
column: 8
|
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:
|
end_location:
|
||||||
row: 23
|
row: 23
|
||||||
column: 8
|
column: 8
|
||||||
fix: ~
|
fix:
|
||||||
|
patch:
|
||||||
|
content: Returns
|
||||||
|
location:
|
||||||
|
row: 19
|
||||||
|
column: 5
|
||||||
|
end_location:
|
||||||
|
row: 19
|
||||||
|
column: 12
|
||||||
|
applied: false
|
||||||
- kind:
|
- kind:
|
||||||
CapitalizeSectionName: Short summary
|
CapitalizeSectionName: Short summary
|
||||||
location:
|
location:
|
||||||
|
@ -19,5 +28,14 @@ expression: checks
|
||||||
end_location:
|
end_location:
|
||||||
row: 221
|
row: 221
|
||||||
column: 8
|
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:
|
end_location:
|
||||||
row: 36
|
row: 36
|
||||||
column: 8
|
column: 8
|
||||||
fix: ~
|
fix:
|
||||||
|
patch:
|
||||||
|
content: ""
|
||||||
|
location:
|
||||||
|
row: 32
|
||||||
|
column: 12
|
||||||
|
end_location:
|
||||||
|
row: 32
|
||||||
|
column: 13
|
||||||
|
applied: false
|
||||||
- kind:
|
- kind:
|
||||||
NewLineAfterSectionName: Raises
|
NewLineAfterSectionName: Raises
|
||||||
location:
|
location:
|
||||||
|
@ -19,7 +28,16 @@ expression: checks
|
||||||
end_location:
|
end_location:
|
||||||
row: 221
|
row: 221
|
||||||
column: 8
|
column: 8
|
||||||
fix: ~
|
fix:
|
||||||
|
patch:
|
||||||
|
content: ""
|
||||||
|
location:
|
||||||
|
row: 218
|
||||||
|
column: 11
|
||||||
|
end_location:
|
||||||
|
row: 218
|
||||||
|
column: 12
|
||||||
|
applied: false
|
||||||
- kind:
|
- kind:
|
||||||
NewLineAfterSectionName: Returns
|
NewLineAfterSectionName: Returns
|
||||||
location:
|
location:
|
||||||
|
@ -28,7 +46,16 @@ expression: checks
|
||||||
end_location:
|
end_location:
|
||||||
row: 262
|
row: 262
|
||||||
column: 8
|
column: 8
|
||||||
fix: ~
|
fix:
|
||||||
|
patch:
|
||||||
|
content: ""
|
||||||
|
location:
|
||||||
|
row: 257
|
||||||
|
column: 12
|
||||||
|
end_location:
|
||||||
|
row: 257
|
||||||
|
column: 13
|
||||||
|
applied: false
|
||||||
- kind:
|
- kind:
|
||||||
NewLineAfterSectionName: Raises
|
NewLineAfterSectionName: Raises
|
||||||
location:
|
location:
|
||||||
|
@ -37,5 +64,14 @@ expression: checks
|
||||||
end_location:
|
end_location:
|
||||||
row: 262
|
row: 262
|
||||||
column: 8
|
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