Avoid some false positives for ends-in-period checks (#1521)

This commit is contained in:
Charlie Marsh 2022-12-31 18:38:22 -05:00 committed by GitHub
parent 605c6069e2
commit f2c9f94f73
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 32 deletions

View file

@ -35,7 +35,6 @@ def f():
...
def f():
r"Here's a line without a period"
...
@ -71,3 +70,24 @@ def f():
Here's a line without a period,
but here's the next line with trailing space """
...
def f(rounds: list[int], number: int) -> bool:
"""
:param rounds: list - rounds played.
:param number: int - round number.
:return: bool - was the round played?
"""
return number in rounds
def f(rounds: list[int], number: int) -> bool:
"""
Args:
rounds (list): rounds played.
number (int): round number.
Returns:
bool: was the round played?
"""
return number in rounds

View file

@ -5,21 +5,21 @@ use crate::docstrings::google::{GOOGLE_SECTION_NAMES, LOWERCASE_GOOGLE_SECTION_N
use crate::docstrings::numpy::{LOWERCASE_NUMPY_SECTION_NAMES, NUMPY_SECTION_NAMES};
pub(crate) enum SectionStyle {
NumPy,
Numpy,
Google,
}
impl SectionStyle {
pub(crate) fn section_names(&self) -> &Lazy<FxHashSet<&'static str>> {
match self {
SectionStyle::NumPy => &NUMPY_SECTION_NAMES,
SectionStyle::Numpy => &NUMPY_SECTION_NAMES,
SectionStyle::Google => &GOOGLE_SECTION_NAMES,
}
}
pub(crate) fn lowercase_section_names(&self) -> &Lazy<FxHashSet<&'static str>> {
match self {
SectionStyle::NumPy => &LOWERCASE_NUMPY_SECTION_NAMES,
SectionStyle::Numpy => &LOWERCASE_NUMPY_SECTION_NAMES,
SectionStyle::Google => &LOWERCASE_GOOGLE_SECTION_NAMES,
}
}

View file

@ -665,9 +665,35 @@ pub fn ends_with_period(checker: &mut Checker, docstring: &Docstring) {
let contents = docstring.contents;
let body = docstring.body;
if let Some(first_line) = body.trim().lines().next() {
let trimmed = first_line.trim();
// Avoid false-positives: `:param`, etc.
for prefix in [":param", ":type", ":raises", ":return", ":rtype"] {
if trimmed.starts_with(prefix) {
return;
}
}
// Avoid false-positives: `Args:`, etc.
for style in [SectionStyle::Google, SectionStyle::Numpy] {
for section_name in style.section_names().iter() {
if let Some(suffix) = trimmed.strip_suffix(section_name) {
if suffix.is_empty() {
return;
}
if suffix == ":" {
return;
}
}
}
}
}
if let Some(index) = logical_line(body) {
let line = body.lines().nth(index).unwrap();
let trimmed = line.trim_end();
if !trimmed.ends_with('.') {
let mut check =
Check::new(CheckKind::EndsInPeriod, Range::from_located(docstring.expr));
@ -712,7 +738,7 @@ pub fn no_signature(checker: &mut Checker, docstring: &Docstring) {
let body = docstring.body;
let Some(first_line) = body.lines().next() else {
let Some(first_line) = body.trim().lines().next() else {
return;
};
if !first_line.contains(&format!("{name}(")) {
@ -785,6 +811,31 @@ pub fn ends_with_punctuation(checker: &mut Checker, docstring: &Docstring) {
let contents = docstring.contents;
let body = docstring.body;
if let Some(first_line) = body.trim().lines().next() {
let trimmed = first_line.trim();
// Avoid false-positives: `:param`, etc.
for prefix in [":param", ":type", ":raises", ":return", ":rtype"] {
if trimmed.starts_with(prefix) {
return;
}
}
// Avoid false-positives: `Args:`, etc.
for style in [SectionStyle::Google, SectionStyle::Numpy] {
for section_name in style.section_names().iter() {
if let Some(suffix) = trimmed.strip_suffix(section_name) {
if suffix.is_empty() {
return;
}
if suffix == ":" {
return;
}
}
}
}
}
if let Some(index) = logical_line(body) {
let line = body.lines().nth(index).unwrap();
let trimmed = line.trim_end();
@ -869,14 +920,14 @@ pub fn sections(checker: &mut Checker, docstring: &Docstring, convention: Option
}
}
Some(Convention::Numpy) => {
for context in &section_contexts(&lines, &SectionStyle::NumPy) {
for context in &section_contexts(&lines, &SectionStyle::Numpy) {
numpy_section(checker, docstring, context);
}
}
None => {
// First, interpret as NumPy-style sections.
let mut found_numpy_section = false;
for context in &section_contexts(&lines, &SectionStyle::NumPy) {
for context in &section_contexts(&lines, &SectionStyle::Numpy) {
found_numpy_section = true;
numpy_section(checker, docstring, context);
}
@ -1418,7 +1469,7 @@ fn parameters_section(checker: &mut Checker, docstring: &Docstring, context: &Se
}
fn numpy_section(checker: &mut Checker, docstring: &Docstring, context: &SectionContext) {
common_section(checker, docstring, context, &SectionStyle::NumPy);
common_section(checker, docstring, context, &SectionStyle::Numpy);
if checker.settings.enabled.contains(&CheckCode::D406) {
let suffix = context

View file

@ -100,98 +100,98 @@ expression: checks
parent: ~
- kind: EndsInPeriod
location:
row: 40
row: 39
column: 4
end_location:
row: 40
row: 39
column: 37
fix:
content: "."
location:
row: 40
row: 39
column: 36
end_location:
row: 40
row: 39
column: 36
parent: ~
- kind: EndsInPeriod
location:
row: 45
row: 44
column: 4
end_location:
row: 45
row: 44
column: 41
fix:
content: "."
location:
row: 45
row: 44
column: 38
end_location:
row: 45
row: 44
column: 38
parent: ~
- kind: EndsInPeriod
location:
row: 50
row: 49
column: 4
end_location:
row: 53
row: 52
column: 7
fix:
content: "."
location:
row: 52
row: 51
column: 28
end_location:
row: 52
row: 51
column: 28
parent: ~
- kind: EndsInPeriod
location:
row: 58
row: 57
column: 4
end_location:
row: 58
row: 57
column: 41
fix:
content: "."
location:
row: 58
row: 57
column: 38
end_location:
row: 58
row: 57
column: 38
parent: ~
- kind: EndsInPeriod
location:
row: 63
row: 62
column: 4
end_location:
row: 65
row: 64
column: 31
fix:
content: "."
location:
row: 65
row: 64
column: 28
end_location:
row: 65
row: 64
column: 28
parent: ~
- kind: EndsInPeriod
location:
row: 70
row: 69
column: 4
end_location:
row: 72
row: 71
column: 52
fix:
content: "."
location:
row: 72
row: 71
column: 48
end_location:
row: 72
row: 71
column: 48
parent: ~