mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 04:19:43 +00:00
Implement D400 (DocstringEndsInNonPeriod) (#396)
This commit is contained in:
parent
8b66bbdc9b
commit
30877127bc
8 changed files with 115 additions and 4 deletions
|
@ -217,7 +217,7 @@ ruff also implements some of the most popular Flake8 plugins natively, including
|
||||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||||
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/) (11/16)
|
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/) (11/16)
|
||||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (3/32)
|
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (3/32)
|
||||||
- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) (1/47)
|
- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) (2/47)
|
||||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (partial)
|
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (partial)
|
||||||
|
|
||||||
Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8:
|
Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8:
|
||||||
|
@ -304,6 +304,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||||
| U006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | | 🛠 |
|
| U006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | | 🛠 |
|
||||||
| U007 | UsePEP604Annotation | Use `X \| Y` for type annotations | | 🛠 |
|
| U007 | UsePEP604Annotation | Use `X \| Y` for type annotations | | 🛠 |
|
||||||
| U008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | | 🛠 |
|
| U008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | | 🛠 |
|
||||||
|
| D400 | DocstringEndsInNonPeriod | First line should end with a period | | |
|
||||||
| D419 | EmptyDocstring | Docstring is empty | | |
|
| D419 | EmptyDocstring | Docstring is empty | | |
|
||||||
| M001 | UnusedNOQA | Unused `noqa` directive | | 🛠 |
|
| M001 | UnusedNOQA | Unused `noqa` directive | | 🛠 |
|
||||||
|
|
||||||
|
|
27
resources/test/fixtures/D400.py
vendored
Normal file
27
resources/test/fixtures/D400.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
def f1() -> None:
|
||||||
|
"""Hello, world.
|
||||||
|
|
||||||
|
More content here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def f2() -> None:
|
||||||
|
"""Hello, world!
|
||||||
|
|
||||||
|
More content here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def f3() -> None:
|
||||||
|
"""Hello, world
|
||||||
|
|
||||||
|
More content here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def f4() -> None:
|
||||||
|
"""."""
|
||||||
|
|
||||||
|
|
||||||
|
def f5() -> None:
|
||||||
|
""""""
|
|
@ -1890,7 +1890,12 @@ impl<'a> Checker<'a> {
|
||||||
|
|
||||||
fn check_docstrings(&mut self) {
|
fn check_docstrings(&mut self) {
|
||||||
while let Some(docstring) = self.docstrings.pop() {
|
while let Some(docstring) = self.docstrings.pop() {
|
||||||
docstrings::docstring_empty(self, &docstring);
|
if self.settings.enabled.contains(&CheckCode::D400) {
|
||||||
|
docstrings::ends_with_period(self, &docstring);
|
||||||
|
}
|
||||||
|
if self.settings.enabled.contains(&CheckCode::D419) {
|
||||||
|
docstrings::not_empty(self, &docstring);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,7 @@ pub enum CheckCode {
|
||||||
U007,
|
U007,
|
||||||
U008,
|
U008,
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
|
D400,
|
||||||
D419,
|
D419,
|
||||||
// Meta
|
// Meta
|
||||||
M001,
|
M001,
|
||||||
|
@ -250,6 +251,7 @@ pub enum CheckKind {
|
||||||
SuperCallWithParameters,
|
SuperCallWithParameters,
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
EmptyDocstring,
|
EmptyDocstring,
|
||||||
|
DocstringEndsInNonPeriod,
|
||||||
// Meta
|
// Meta
|
||||||
UnusedNOQA(Option<Vec<String>>),
|
UnusedNOQA(Option<Vec<String>>),
|
||||||
}
|
}
|
||||||
|
@ -359,6 +361,7 @@ impl CheckCode {
|
||||||
CheckCode::U007 => CheckKind::UsePEP604Annotation,
|
CheckCode::U007 => CheckKind::UsePEP604Annotation,
|
||||||
CheckCode::U008 => CheckKind::SuperCallWithParameters,
|
CheckCode::U008 => CheckKind::SuperCallWithParameters,
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
|
CheckCode::D400 => CheckKind::DocstringEndsInNonPeriod,
|
||||||
CheckCode::D419 => CheckKind::EmptyDocstring,
|
CheckCode::D419 => CheckKind::EmptyDocstring,
|
||||||
// Meta
|
// Meta
|
||||||
CheckCode::M001 => CheckKind::UnusedNOQA(None),
|
CheckCode::M001 => CheckKind::UnusedNOQA(None),
|
||||||
|
@ -448,6 +451,7 @@ impl CheckKind {
|
||||||
CheckKind::UselessObjectInheritance(_) => &CheckCode::U004,
|
CheckKind::UselessObjectInheritance(_) => &CheckCode::U004,
|
||||||
CheckKind::SuperCallWithParameters => &CheckCode::U008,
|
CheckKind::SuperCallWithParameters => &CheckCode::U008,
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
|
CheckKind::DocstringEndsInNonPeriod => &CheckCode::D400,
|
||||||
CheckKind::EmptyDocstring => &CheckCode::D419,
|
CheckKind::EmptyDocstring => &CheckCode::D419,
|
||||||
// Meta
|
// Meta
|
||||||
CheckKind::UnusedNOQA(_) => &CheckCode::M001,
|
CheckKind::UnusedNOQA(_) => &CheckCode::M001,
|
||||||
|
@ -693,6 +697,9 @@ impl CheckKind {
|
||||||
"Use `super()` instead of `super(__class__, self)`".to_string()
|
"Use `super()` instead of `super(__class__, self)`".to_string()
|
||||||
}
|
}
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
|
CheckKind::DocstringEndsInNonPeriod => {
|
||||||
|
"First line should end with a period".to_string()
|
||||||
|
}
|
||||||
CheckKind::EmptyDocstring => "Docstring is empty".to_string(),
|
CheckKind::EmptyDocstring => "Docstring is empty".to_string(),
|
||||||
// Meta
|
// Meta
|
||||||
CheckKind::UnusedNOQA(codes) => match codes {
|
CheckKind::UnusedNOQA(codes) => match codes {
|
||||||
|
|
|
@ -61,8 +61,7 @@ pub fn extract<'a, 'b>(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn docstring_empty(checker: &mut Checker, docstring: &Docstring) {
|
pub fn not_empty(checker: &mut Checker, docstring: &Docstring) {
|
||||||
// Extract the source.
|
|
||||||
if let ExprKind::Constant {
|
if let ExprKind::Constant {
|
||||||
value: Constant::Str(string),
|
value: Constant::Str(string),
|
||||||
..
|
..
|
||||||
|
@ -76,3 +75,20 @@ pub fn docstring_empty(checker: &mut Checker, docstring: &Docstring) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ends_with_period(checker: &mut Checker, docstring: &Docstring) {
|
||||||
|
if let ExprKind::Constant {
|
||||||
|
value: Constant::Str(string),
|
||||||
|
..
|
||||||
|
} = &docstring.expr.node
|
||||||
|
{
|
||||||
|
if let Some(string) = string.lines().next() {
|
||||||
|
if !string.ends_with('.') {
|
||||||
|
checker.add_check(Check::new(
|
||||||
|
CheckKind::DocstringEndsInNonPeriod,
|
||||||
|
Range::from_located(docstring.expr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -978,6 +978,18 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn d400() -> Result<()> {
|
||||||
|
let mut checks = check_path(
|
||||||
|
Path::new("./resources/test/fixtures/D400.py"),
|
||||||
|
&settings::Settings::for_rule(CheckCode::D400),
|
||||||
|
&fixer::Mode::Generate,
|
||||||
|
)?;
|
||||||
|
checks.sort_by_key(|check| check.location);
|
||||||
|
insta::assert_yaml_snapshot!(checks);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn d419() -> Result<()> {
|
fn d419() -> Result<()> {
|
||||||
let mut checks = check_path(
|
let mut checks = check_path(
|
||||||
|
|
21
src/snapshots/ruff__linter__tests__d400.snap
Normal file
21
src/snapshots/ruff__linter__tests__d400.snap
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
source: src/linter.rs
|
||||||
|
expression: checks
|
||||||
|
---
|
||||||
|
- kind: DocstringEndsInPeriod
|
||||||
|
location:
|
||||||
|
row: 9
|
||||||
|
column: 6
|
||||||
|
end_location:
|
||||||
|
row: 12
|
||||||
|
column: 8
|
||||||
|
fix: ~
|
||||||
|
- kind: DocstringEndsInPeriod
|
||||||
|
location:
|
||||||
|
row: 16
|
||||||
|
column: 6
|
||||||
|
end_location:
|
||||||
|
row: 19
|
||||||
|
column: 8
|
||||||
|
fix: ~
|
||||||
|
|
22
src/snapshots/ruff__linter__tests__d400.snap.new
Normal file
22
src/snapshots/ruff__linter__tests__d400.snap.new
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
source: src/linter.rs
|
||||||
|
assertion_line: 989
|
||||||
|
expression: checks
|
||||||
|
---
|
||||||
|
- kind: DocstringEndsInNonPeriod
|
||||||
|
location:
|
||||||
|
row: 9
|
||||||
|
column: 6
|
||||||
|
end_location:
|
||||||
|
row: 12
|
||||||
|
column: 8
|
||||||
|
fix: ~
|
||||||
|
- kind: DocstringEndsInNonPeriod
|
||||||
|
location:
|
||||||
|
row: 16
|
||||||
|
column: 6
|
||||||
|
end_location:
|
||||||
|
row: 19
|
||||||
|
column: 8
|
||||||
|
fix: ~
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue