mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 22:31:23 +00:00
Enforce max-doc-length for multi-line docstrings (#4347)
This commit is contained in:
parent
ddbe5a1243
commit
5f64d2346f
5 changed files with 57 additions and 12 deletions
|
@ -2,7 +2,7 @@
|
||||||
"""Here's a top-level docstring that's over the limit."""
|
"""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."""
|
"""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.
|
x = 1 # Here's a comment that's over the limit, but it's not standalone.
|
||||||
|
@ -16,3 +16,16 @@ def f():
|
||||||
|
|
||||||
|
|
||||||
"This is also considered a docstring, and is over the limit."
|
"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."""
|
||||||
|
|
|
@ -118,7 +118,7 @@ pub fn check_physical_lines(
|
||||||
}
|
}
|
||||||
|
|
||||||
while doc_lines_iter
|
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()
|
.is_some()
|
||||||
{
|
{
|
||||||
if enforce_doc_line_too_long {
|
if enforce_doc_line_too_long {
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
//! Doc line extraction. In this context, a doc line is a line consisting of a
|
//! Doc line extraction. In this context, a doc line is a line consisting of a
|
||||||
//! standalone comment or a constant string statement.
|
//! standalone comment or a constant string statement.
|
||||||
|
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
|
||||||
use std::iter::FusedIterator;
|
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::ast::{Constant, ExprKind, Stmt, StmtKind, Suite};
|
||||||
use rustpython_parser::lexer::LexResult;
|
use rustpython_parser::lexer::LexResult;
|
||||||
use rustpython_parser::Tok;
|
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;
|
||||||
use ruff_python_ast::visitor::Visitor;
|
use ruff_python_ast::visitor::Visitor;
|
||||||
|
|
||||||
|
@ -69,12 +70,12 @@ impl Iterator for DocLines<'_> {
|
||||||
|
|
||||||
impl FusedIterator for DocLines<'_> {}
|
impl FusedIterator for DocLines<'_> {}
|
||||||
|
|
||||||
#[derive(Default)]
|
struct StringLinesVisitor<'a> {
|
||||||
struct StringLinesVisitor {
|
|
||||||
string_lines: Vec<TextSize>,
|
string_lines: Vec<TextSize>,
|
||||||
|
locator: &'a Locator<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visitor<'_> for StringLinesVisitor {
|
impl Visitor<'_> for StringLinesVisitor<'_> {
|
||||||
fn visit_stmt(&mut self, stmt: &Stmt) {
|
fn visit_stmt(&mut self, stmt: &Stmt) {
|
||||||
if let StmtKind::Expr { value } = &stmt.node {
|
if let StmtKind::Expr { value } = &stmt.node {
|
||||||
if let ExprKind::Constant {
|
if let ExprKind::Constant {
|
||||||
|
@ -82,16 +83,30 @@ impl Visitor<'_> for StringLinesVisitor {
|
||||||
..
|
..
|
||||||
} = &value.node
|
} = &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);
|
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.
|
/// Extract doc lines (standalone strings) start positions from an AST.
|
||||||
pub fn doc_lines_from_ast(python_ast: &Suite) -> Vec<TextSize> {
|
pub fn doc_lines_from_ast(python_ast: &Suite, locator: &Locator) -> Vec<TextSize> {
|
||||||
let mut visitor = StringLinesVisitor::default();
|
let mut visitor = StringLinesVisitor::new(locator);
|
||||||
visitor.visit_body(python_ast);
|
visitor.visit_body(python_ast);
|
||||||
visitor.string_lines
|
visitor.string_lines
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ pub fn check_path(
|
||||||
diagnostics.extend(import_diagnostics);
|
diagnostics.extend(import_diagnostics);
|
||||||
}
|
}
|
||||||
if use_doc_lines {
|
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) => {
|
Err(parse_error) => {
|
||||||
|
|
|
@ -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)
|
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."""
|
7 | """Here's a docstring that's also over the limit."""
|
||||||
| ^^^^^^ W505
|
| ^^^^^^ W505
|
||||||
8 |
|
8 |
|
||||||
|
@ -42,4 +42,21 @@ W505.py:18:51: W505 Doc line too long (61 > 50 characters)
|
||||||
| ^^^^^^^^^^^ W505
|
| ^^^^^^^^^^^ 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
|
||||||
|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue