Skip to content

Commit

Permalink
Enforce max-doc-length for multi-line docstrings (#4347)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh authored May 10, 2023
1 parent ddbe5a1 commit 5f64d23
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 12 deletions.
15 changes: 14 additions & 1 deletion crates/ruff/resources/test/fixtures/pycodestyle/W505.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""Here's a top-level docstring that's over the limit."""


def f():
def f1():
"""Here's a docstring that's also over the limit."""

x = 1 # Here's a comment that's over the limit, but it's not standalone.
Expand All @@ -16,3 +16,16 @@ def f():


"This is also considered a docstring, and is over the limit."


def f2():
"""Here's a multi-line docstring.
It's over the limit on this line, which isn't the first line in the docstring.
"""


def f3():
"""Here's a multi-line docstring.
It's over the limit on this line, which isn't the first line in the docstring."""
2 changes: 1 addition & 1 deletion crates/ruff/src/checkers/physical_lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ pub fn check_physical_lines(
}

while doc_lines_iter
.next_if(|doc_line_start| line.range().contains(**doc_line_start))
.next_if(|doc_line_start| line.range().contains_inclusive(**doc_line_start))
.is_some()
{
if enforce_doc_line_too_long {
Expand Down
31 changes: 23 additions & 8 deletions crates/ruff/src/doc_lines.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! Doc line extraction. In this context, a doc line is a line consisting of a
//! standalone comment or a constant string statement.

use ruff_text_size::{TextRange, TextSize};
use std::iter::FusedIterator;

use ruff_python_ast::source_code::Locator;
use ruff_text_size::{TextRange, TextSize};
use rustpython_parser::ast::{Constant, ExprKind, Stmt, StmtKind, Suite};
use rustpython_parser::lexer::LexResult;
use rustpython_parser::Tok;

use ruff_python_ast::newlines::UniversalNewlineIterator;
use ruff_python_ast::source_code::Locator;
use ruff_python_ast::visitor;
use ruff_python_ast::visitor::Visitor;

Expand Down Expand Up @@ -69,29 +70,43 @@ impl Iterator for DocLines<'_> {

impl FusedIterator for DocLines<'_> {}

#[derive(Default)]
struct StringLinesVisitor {
struct StringLinesVisitor<'a> {
string_lines: Vec<TextSize>,
locator: &'a Locator<'a>,
}

impl Visitor<'_> for StringLinesVisitor {
impl Visitor<'_> for StringLinesVisitor<'_> {
fn visit_stmt(&mut self, stmt: &Stmt) {
if let StmtKind::Expr { value } = &stmt.node {
if let ExprKind::Constant {
value: Constant::Str(..),
..
} = &value.node
{
self.string_lines.push(value.start());
for line in UniversalNewlineIterator::with_offset(
self.locator.slice(value.range()),
value.start(),
) {
self.string_lines.push(line.start());
}
}
}
visitor::walk_stmt(self, stmt);
}
}

impl<'a> StringLinesVisitor<'a> {
fn new(locator: &'a Locator<'a>) -> Self {
Self {
string_lines: Vec::new(),
locator,
}
}
}

/// Extract doc lines (standalone strings) start positions from an AST.
pub fn doc_lines_from_ast(python_ast: &Suite) -> Vec<TextSize> {
let mut visitor = StringLinesVisitor::default();
pub fn doc_lines_from_ast(python_ast: &Suite, locator: &Locator) -> Vec<TextSize> {
let mut visitor = StringLinesVisitor::new(locator);
visitor.visit_body(python_ast);
visitor.string_lines
}
2 changes: 1 addition & 1 deletion crates/ruff/src/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub fn check_path(
diagnostics.extend(import_diagnostics);
}
if use_doc_lines {
doc_lines.extend(doc_lines_from_ast(&python_ast));
doc_lines.extend(doc_lines_from_ast(&python_ast, locator));
}
}
Err(parse_error) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ W505.py:2:51: W505 Doc line too long (57 > 50 characters)

W505.py:6:51: W505 Doc line too long (56 > 50 characters)
|
6 | def f():
6 | def f1():
7 | """Here's a docstring that's also over the limit."""
| ^^^^^^ W505
8 |
Expand Down Expand Up @@ -42,4 +42,21 @@ W505.py:18:51: W505 Doc line too long (61 > 50 characters)
| ^^^^^^^^^^^ W505
|

W505.py:24:51: W505 Doc line too long (82 > 50 characters)
|
24 | """Here's a multi-line docstring.
25 |
26 | It's over the limit on this line, which isn't the first line in the docstring.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ W505
27 | """
|

W505.py:31:51: W505 Doc line too long (85 > 50 characters)
|
31 | """Here's a multi-line docstring.
32 |
33 | It's over the limit on this line, which isn't the first line in the docstring."""
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ W505
|


0 comments on commit 5f64d23

Please sign in to comment.