Implement D200 (OneLinerDocstring) (#397)

This commit is contained in:
Charlie Marsh 2022-10-10 16:07:51 -04:00 committed by GitHub
parent 30877127bc
commit b8dce8922d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 24 deletions

25
resources/test/fixtures/D200.py vendored Normal file
View file

@ -0,0 +1,25 @@
def f():
"""
Fail.
"""
def f():
"""Fail.
"""
def f():
"""
Fail."""
def f():
"""Pass."""
def f():
"""Pass.
More content here.
"""

View file

@ -1890,6 +1890,9 @@ 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() {
if self.settings.enabled.contains(&CheckCode::D200) {
docstrings::one_liner(self, &docstring);
}
if self.settings.enabled.contains(&CheckCode::D400) { if self.settings.enabled.contains(&CheckCode::D400) {
docstrings::ends_with_period(self, &docstring); docstrings::ends_with_period(self, &docstring);
} }

View file

@ -151,6 +151,7 @@ pub enum CheckCode {
U007, U007,
U008, U008,
// pydocstyle // pydocstyle
D200,
D400, D400,
D419, D419,
// Meta // Meta
@ -250,6 +251,7 @@ pub enum CheckKind {
UsePEP604Annotation, UsePEP604Annotation,
SuperCallWithParameters, SuperCallWithParameters,
// pydocstyle // pydocstyle
OneLinerDocstring,
EmptyDocstring, EmptyDocstring,
DocstringEndsInNonPeriod, DocstringEndsInNonPeriod,
// Meta // Meta
@ -361,6 +363,7 @@ impl CheckCode {
CheckCode::U007 => CheckKind::UsePEP604Annotation, CheckCode::U007 => CheckKind::UsePEP604Annotation,
CheckCode::U008 => CheckKind::SuperCallWithParameters, CheckCode::U008 => CheckKind::SuperCallWithParameters,
// pydocstyle // pydocstyle
CheckCode::D200 => CheckKind::OneLinerDocstring,
CheckCode::D400 => CheckKind::DocstringEndsInNonPeriod, CheckCode::D400 => CheckKind::DocstringEndsInNonPeriod,
CheckCode::D419 => CheckKind::EmptyDocstring, CheckCode::D419 => CheckKind::EmptyDocstring,
// Meta // Meta
@ -451,6 +454,7 @@ impl CheckKind {
CheckKind::UselessObjectInheritance(_) => &CheckCode::U004, CheckKind::UselessObjectInheritance(_) => &CheckCode::U004,
CheckKind::SuperCallWithParameters => &CheckCode::U008, CheckKind::SuperCallWithParameters => &CheckCode::U008,
// pydocstyle // pydocstyle
CheckKind::OneLinerDocstring => &CheckCode::D200,
CheckKind::DocstringEndsInNonPeriod => &CheckCode::D400, CheckKind::DocstringEndsInNonPeriod => &CheckCode::D400,
CheckKind::EmptyDocstring => &CheckCode::D419, CheckKind::EmptyDocstring => &CheckCode::D419,
// Meta // Meta
@ -697,6 +701,7 @@ impl CheckKind {
"Use `super()` instead of `super(__class__, self)`".to_string() "Use `super()` instead of `super(__class__, self)`".to_string()
} }
// pydocstyle // pydocstyle
CheckKind::OneLinerDocstring => "One-line docstring should fit on one line".to_string(),
CheckKind::DocstringEndsInNonPeriod => { CheckKind::DocstringEndsInNonPeriod => {
"First line should end with a period".to_string() "First line should end with a period".to_string()
} }

View file

@ -61,6 +61,33 @@ pub fn extract<'a, 'b>(
None None
} }
pub fn one_liner(checker: &mut Checker, docstring: &Docstring) {
if let ExprKind::Constant {
value: Constant::Str(string),
..
} = &docstring.expr.node
{
let mut line_count = 0;
let mut non_empty_line_count = 0;
for line in string.lines() {
line_count += 1;
if !line.trim().is_empty() {
non_empty_line_count += 1;
}
if non_empty_line_count > 1 {
return;
}
}
if non_empty_line_count == 1 && line_count > 1 {
checker.add_check(Check::new(
CheckKind::OneLinerDocstring,
Range::from_located(docstring.expr),
));
}
}
}
pub fn not_empty(checker: &mut Checker, docstring: &Docstring) { pub fn not_empty(checker: &mut Checker, docstring: &Docstring) {
if let ExprKind::Constant { if let ExprKind::Constant {
value: Constant::Str(string), value: Constant::Str(string),

View file

@ -978,6 +978,18 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn d200() -> Result<()> {
let mut checks = check_path(
Path::new("./resources/test/fixtures/D200.py"),
&settings::Settings::for_rule(CheckCode::D200),
&fixer::Mode::Generate,
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
#[test] #[test]
fn d400() -> Result<()> { fn d400() -> Result<()> {
let mut checks = check_path( let mut checks = check_path(

View file

@ -0,0 +1,29 @@
---
source: src/linter.rs
expression: checks
---
- kind: OneLinerDocstring
location:
row: 2
column: 6
end_location:
row: 4
column: 8
fix: ~
- kind: OneLinerDocstring
location:
row: 8
column: 6
end_location:
row: 9
column: 8
fix: ~
- kind: OneLinerDocstring
location:
row: 13
column: 6
end_location:
row: 14
column: 13
fix: ~

View file

@ -2,7 +2,7 @@
source: src/linter.rs source: src/linter.rs
expression: checks expression: checks
--- ---
- kind: DocstringEndsInPeriod - kind: DocstringEndsInNonPeriod
location: location:
row: 9 row: 9
column: 6 column: 6
@ -10,7 +10,7 @@ expression: checks
row: 12 row: 12
column: 8 column: 8
fix: ~ fix: ~
- kind: DocstringEndsInPeriod - kind: DocstringEndsInNonPeriod
location: location:
row: 16 row: 16
column: 6 column: 6

View file

@ -1,22 +0,0 @@
---
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: ~