mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00
Ignore same-line docstrings for lines-before and lines-after rules (#6344)
These rules assume that the docstring is on its own line. pydocstyle treats them inconsistently, so I'm just going to disable them in this case. Closes https://github.com/astral-sh/ruff/issues/6329.
This commit is contained in:
parent
08dd87e04d
commit
fa5c9cced9
5 changed files with 115 additions and 36 deletions
|
@ -634,3 +634,8 @@ def starts_with_this():
|
|||
@expect('D404: First word of the docstring should not be "This"')
|
||||
def starts_with_space_then_this():
|
||||
""" This is a docstring that starts with a space.""" # noqa: D210
|
||||
|
||||
|
||||
class SameLine: """This is a docstring on the same line"""
|
||||
|
||||
def same_line(): """This is a docstring on the same line"""
|
||||
|
|
|
@ -43,9 +43,7 @@ use crate::registry::{AsRule, Rule};
|
|||
///
|
||||
/// [D211]: https://beta.ruff.rs/docs/rules/blank-line-before-class
|
||||
#[violation]
|
||||
pub struct OneBlankLineBeforeClass {
|
||||
lines: usize,
|
||||
}
|
||||
pub struct OneBlankLineBeforeClass;
|
||||
|
||||
impl AlwaysAutofixableViolation for OneBlankLineBeforeClass {
|
||||
#[derive_message_formats]
|
||||
|
@ -97,9 +95,7 @@ impl AlwaysAutofixableViolation for OneBlankLineBeforeClass {
|
|||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct OneBlankLineAfterClass {
|
||||
lines: usize,
|
||||
}
|
||||
pub struct OneBlankLineAfterClass;
|
||||
|
||||
impl AlwaysAutofixableViolation for OneBlankLineAfterClass {
|
||||
#[derive_message_formats]
|
||||
|
@ -144,9 +140,7 @@ impl AlwaysAutofixableViolation for OneBlankLineAfterClass {
|
|||
///
|
||||
/// [D203]: https://beta.ruff.rs/docs/rules/one-blank-line-before-class
|
||||
#[violation]
|
||||
pub struct BlankLineBeforeClass {
|
||||
lines: usize,
|
||||
}
|
||||
pub struct BlankLineBeforeClass;
|
||||
|
||||
impl AlwaysAutofixableViolation for BlankLineBeforeClass {
|
||||
#[derive_message_formats]
|
||||
|
@ -170,14 +164,24 @@ pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstr
|
|||
return;
|
||||
};
|
||||
|
||||
// Special-case: the docstring is on the same line as the class. For example:
|
||||
// ```python
|
||||
// class PhotoMetadata: """Metadata about a photo."""
|
||||
// ```
|
||||
let between_range = TextRange::new(stmt.start(), docstring.start());
|
||||
if !checker.locator().contains_line_break(between_range) {
|
||||
return;
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::OneBlankLineBeforeClass) || checker.enabled(Rule::BlankLineBeforeClass)
|
||||
{
|
||||
let before = checker
|
||||
.locator()
|
||||
.slice(TextRange::new(stmt.start(), docstring.start()));
|
||||
let mut lines = UniversalNewlineIterator::with_offset(
|
||||
checker.locator().slice(between_range),
|
||||
between_range.start(),
|
||||
)
|
||||
.rev();
|
||||
|
||||
let mut blank_lines_before = 0usize;
|
||||
let mut lines = UniversalNewlineIterator::with_offset(before, stmt.start()).rev();
|
||||
let mut blank_lines_start = lines.next().map(|line| line.start()).unwrap_or_default();
|
||||
|
||||
for line in lines {
|
||||
|
@ -191,12 +195,7 @@ pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstr
|
|||
|
||||
if checker.enabled(Rule::BlankLineBeforeClass) {
|
||||
if blank_lines_before != 0 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
BlankLineBeforeClass {
|
||||
lines: blank_lines_before,
|
||||
},
|
||||
docstring.range(),
|
||||
);
|
||||
let mut diagnostic = Diagnostic::new(BlankLineBeforeClass, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Delete the blank line before the class.
|
||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||
|
@ -209,12 +208,7 @@ pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstr
|
|||
}
|
||||
if checker.enabled(Rule::OneBlankLineBeforeClass) {
|
||||
if blank_lines_before != 1 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
OneBlankLineBeforeClass {
|
||||
lines: blank_lines_before,
|
||||
},
|
||||
docstring.range(),
|
||||
);
|
||||
let mut diagnostic = Diagnostic::new(OneBlankLineBeforeClass, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Insert one blank line before the class.
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
|
@ -229,9 +223,9 @@ pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstr
|
|||
}
|
||||
|
||||
if checker.enabled(Rule::OneBlankLineAfterClass) {
|
||||
let after = checker
|
||||
.locator()
|
||||
.slice(TextRange::new(docstring.end(), stmt.end()));
|
||||
let after_range = TextRange::new(docstring.end(), stmt.end());
|
||||
|
||||
let after = checker.locator().slice(after_range);
|
||||
|
||||
let all_blank_after = after.universal_newlines().skip(1).all(|line| {
|
||||
line.trim_whitespace().is_empty() || line.trim_whitespace_start().starts_with('#')
|
||||
|
@ -240,9 +234,10 @@ pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstr
|
|||
return;
|
||||
}
|
||||
|
||||
let mut blank_lines_after = 0usize;
|
||||
let mut lines = UniversalNewlineIterator::with_offset(after, docstring.end());
|
||||
let mut lines = UniversalNewlineIterator::with_offset(after, after_range.start());
|
||||
|
||||
let first_line_start = lines.next().map(|l| l.start()).unwrap_or_default();
|
||||
let mut blank_lines_after = 0usize;
|
||||
let mut blank_lines_end = docstring.end();
|
||||
|
||||
for line in lines {
|
||||
|
@ -255,12 +250,7 @@ pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstr
|
|||
}
|
||||
|
||||
if blank_lines_after != 1 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
OneBlankLineAfterClass {
|
||||
lines: blank_lines_after,
|
||||
},
|
||||
docstring.range(),
|
||||
);
|
||||
let mut diagnostic = Diagnostic::new(OneBlankLineAfterClass, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Insert a blank line before the class (replacing any existing lines).
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
|
|
|
@ -272,4 +272,38 @@ D.py:615:5: D400 [*] First line should end with a period
|
|||
617 617 | """
|
||||
618 618 |
|
||||
|
||||
D.py:639:17: D400 [*] First line should end with a period
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
636 636 | """ This is a docstring that starts with a space.""" # noqa: D210
|
||||
637 637 |
|
||||
638 638 |
|
||||
639 |-class SameLine: """This is a docstring on the same line"""
|
||||
639 |+class SameLine: """This is a docstring on the same line."""
|
||||
640 640 |
|
||||
641 641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
||||
D.py:641:18: D400 [*] First line should end with a period
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
638 638 |
|
||||
639 639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 640 |
|
||||
641 |-def same_line(): """This is a docstring on the same line"""
|
||||
641 |+def same_line(): """This is a docstring on the same line."""
|
||||
|
||||
|
||||
|
|
|
@ -17,4 +17,20 @@ D.py:636:5: D404 First word of the docstring should not be "This"
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D404
|
||||
|
|
||||
|
||||
D.py:639:17: D404 First word of the docstring should not be "This"
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D404
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
|
||||
|
||||
D.py:641:18: D404 First word of the docstring should not be "This"
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D404
|
||||
|
|
||||
|
||||
|
||||
|
|
|
@ -254,4 +254,38 @@ D.py:615:5: D415 [*] First line should end with a period, question mark, or excl
|
|||
617 617 | """
|
||||
618 618 |
|
||||
|
||||
D.py:639:17: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D415
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
636 636 | """ This is a docstring that starts with a space.""" # noqa: D210
|
||||
637 637 |
|
||||
638 638 |
|
||||
639 |-class SameLine: """This is a docstring on the same line"""
|
||||
639 |+class SameLine: """This is a docstring on the same line."""
|
||||
640 640 |
|
||||
641 641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
||||
D.py:641:18: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
638 638 |
|
||||
639 639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 640 |
|
||||
641 |-def same_line(): """This is a docstring on the same line"""
|
||||
641 |+def same_line(): """This is a docstring on the same line."""
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue