Implement PYI048 for `flake8-pyi` plugin (#4645)

This commit is contained in:
qdegraaf 2023-05-25 22:04:14 +02:00 committed by GitHub
parent 0f610f2cf7
commit 52deeb36ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 112 additions and 0 deletions

View File

@ -0,0 +1,19 @@
def bar(): # OK
...
def oof(): # OK, docstrings are handled by another rule
"""oof"""
print("foo")
def foo(): # Ok not in Stub file
"""foo"""
print("foo")
print("foo")
def buzz(): # Ok not in Stub file
print("fizz")
print("buzz")
print("test")

View File

@ -0,0 +1,20 @@
def bar():
... # OK
def oof(): # OK, docstrings are handled by another rule
"""oof"""
print("foo")
def foo(): # ERROR PYI048
"""foo"""
print("foo")
print("foo")
def buzz(): # ERROR PYI048
print("fizz")
print("buzz")
print("test")

View File

@ -425,6 +425,9 @@ where
if self.enabled(Rule::NonEmptyStubBody) { if self.enabled(Rule::NonEmptyStubBody) {
flake8_pyi::rules::non_empty_stub_body(self, body); flake8_pyi::rules::non_empty_stub_body(self, body);
} }
if self.enabled(Rule::StubBodyMultipleStatements) {
flake8_pyi::rules::stub_body_multiple_statements(self, stmt, body);
}
} }
if self.enabled(Rule::DunderFunctionName) { if self.enabled(Rule::DunderFunctionName) {

View File

@ -592,6 +592,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Pyi, "033") => (RuleGroup::Unspecified, Rule::TypeCommentInStub), (Flake8Pyi, "033") => (RuleGroup::Unspecified, Rule::TypeCommentInStub),
(Flake8Pyi, "042") => (RuleGroup::Unspecified, Rule::SnakeCaseTypeAlias), (Flake8Pyi, "042") => (RuleGroup::Unspecified, Rule::SnakeCaseTypeAlias),
(Flake8Pyi, "043") => (RuleGroup::Unspecified, Rule::TSuffixedTypeAlias), (Flake8Pyi, "043") => (RuleGroup::Unspecified, Rule::TSuffixedTypeAlias),
(Flake8Pyi, "048") => (RuleGroup::Unspecified, Rule::StubBodyMultipleStatements),
(Flake8Pyi, "052") => (RuleGroup::Unspecified, Rule::UnannotatedAssignmentInStub), (Flake8Pyi, "052") => (RuleGroup::Unspecified, Rule::UnannotatedAssignmentInStub),
// flake8-pytest-style // flake8-pytest-style

View File

@ -519,6 +519,7 @@ ruff_macros::register_rules!(
rules::flake8_pyi::rules::PassStatementStubBody, rules::flake8_pyi::rules::PassStatementStubBody,
rules::flake8_pyi::rules::QuotedAnnotationInStub, rules::flake8_pyi::rules::QuotedAnnotationInStub,
rules::flake8_pyi::rules::SnakeCaseTypeAlias, rules::flake8_pyi::rules::SnakeCaseTypeAlias,
rules::flake8_pyi::rules::StubBodyMultipleStatements,
rules::flake8_pyi::rules::TSuffixedTypeAlias, rules::flake8_pyi::rules::TSuffixedTypeAlias,
rules::flake8_pyi::rules::TypeCommentInStub, rules::flake8_pyi::rules::TypeCommentInStub,
rules::flake8_pyi::rules::TypedArgumentDefaultInStub, rules::flake8_pyi::rules::TypedArgumentDefaultInStub,

View File

@ -34,6 +34,8 @@ mod tests {
#[test_case(Rule::QuotedAnnotationInStub, Path::new("PYI020.pyi"))] #[test_case(Rule::QuotedAnnotationInStub, Path::new("PYI020.pyi"))]
#[test_case(Rule::SnakeCaseTypeAlias, Path::new("PYI042.py"))] #[test_case(Rule::SnakeCaseTypeAlias, Path::new("PYI042.py"))]
#[test_case(Rule::SnakeCaseTypeAlias, Path::new("PYI042.pyi"))] #[test_case(Rule::SnakeCaseTypeAlias, Path::new("PYI042.pyi"))]
#[test_case(Rule::StubBodyMultipleStatements, Path::new("PYI048.py"))]
#[test_case(Rule::StubBodyMultipleStatements, Path::new("PYI048.pyi"))]
#[test_case(Rule::TSuffixedTypeAlias, Path::new("PYI043.py"))] #[test_case(Rule::TSuffixedTypeAlias, Path::new("PYI043.py"))]
#[test_case(Rule::TSuffixedTypeAlias, Path::new("PYI043.pyi"))] #[test_case(Rule::TSuffixedTypeAlias, Path::new("PYI043.pyi"))]
#[test_case(Rule::TypeCommentInStub, Path::new("PYI033.py"))] #[test_case(Rule::TypeCommentInStub, Path::new("PYI033.py"))]

View File

@ -16,6 +16,9 @@ pub(crate) use simple_defaults::{
typed_argument_simple_defaults, unannotated_assignment_in_stub, ArgumentDefaultInStub, typed_argument_simple_defaults, unannotated_assignment_in_stub, ArgumentDefaultInStub,
AssignmentDefaultInStub, TypedArgumentDefaultInStub, UnannotatedAssignmentInStub, AssignmentDefaultInStub, TypedArgumentDefaultInStub, UnannotatedAssignmentInStub,
}; };
pub(crate) use stub_body_multiple_statements::{
stub_body_multiple_statements, StubBodyMultipleStatements,
};
pub(crate) use type_alias_naming::{ pub(crate) use type_alias_naming::{
snake_case_type_alias, t_suffixed_type_alias, SnakeCaseTypeAlias, TSuffixedTypeAlias, snake_case_type_alias, t_suffixed_type_alias, SnakeCaseTypeAlias, TSuffixedTypeAlias,
}; };
@ -34,6 +37,7 @@ mod pass_statement_stub_body;
mod prefix_type_params; mod prefix_type_params;
mod quoted_annotation_in_stub; mod quoted_annotation_in_stub;
mod simple_defaults; mod simple_defaults;
mod stub_body_multiple_statements;
mod type_alias_naming; mod type_alias_naming;
mod type_comment_in_stub; mod type_comment_in_stub;
mod unrecognized_platform; mod unrecognized_platform;

View File

@ -0,0 +1,37 @@
use rustpython_parser::ast::Stmt;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers;
use ruff_python_ast::helpers::is_docstring_stmt;
use crate::checkers::ast::Checker;
#[violation]
pub struct StubBodyMultipleStatements;
impl Violation for StubBodyMultipleStatements {
#[derive_message_formats]
fn message(&self) -> String {
format!("Function body must contain exactly one statement")
}
}
/// PYI010
pub(crate) fn stub_body_multiple_statements(checker: &mut Checker, stmt: &Stmt, body: &[Stmt]) {
// If the function body consists of exactly one statement, abort.
if body.len() == 1 {
return;
}
// If the function body consists of exactly two statements, and the first is a
// docstring, abort (this is covered by PYI021).
if body.len() == 2 && is_docstring_stmt(&body[0]) {
return;
}
checker.diagnostics.push(Diagnostic::new(
StubBodyMultipleStatements,
helpers::identifier_range(stmt, checker.locator),
));
}

View File

@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/flake8_pyi/mod.rs
---

View File

@ -0,0 +1,20 @@
---
source: crates/ruff/src/rules/flake8_pyi/mod.rs
---
PYI048.pyi:11:5: PYI048 Function body must contain exactly one statement
|
11 | def foo(): # ERROR PYI048
| ^^^ PYI048
12 | """foo"""
13 | print("foo")
|
PYI048.pyi:17:5: PYI048 Function body must contain exactly one statement
|
17 | def buzz(): # ERROR PYI048
| ^^^^ PYI048
18 | print("fizz")
19 | print("buzz")
|

1
ruff.schema.json generated
View File

@ -2206,6 +2206,7 @@
"PYI04", "PYI04",
"PYI042", "PYI042",
"PYI043", "PYI043",
"PYI048",
"PYI05", "PYI05",
"PYI052", "PYI052",
"Q", "Q",