Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement PYI048 for flake8-pyi plugin #4645

Merged
merged 5 commits into from May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions crates/ruff/resources/test/fixtures/flake8_pyi/PYI048.py
@@ -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")
20 changes: 20 additions & 0 deletions crates/ruff/resources/test/fixtures/flake8_pyi/PYI048.pyi
@@ -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")
3 changes: 3 additions & 0 deletions crates/ruff/src/checkers/ast/mod.rs
Expand Up @@ -425,6 +425,9 @@ where
if self.enabled(Rule::NonEmptyStubBody) {
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) {
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/codes.rs
Expand Up @@ -592,6 +592,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Pyi, "033") => (RuleGroup::Unspecified, Rule::TypeCommentInStub),
(Flake8Pyi, "042") => (RuleGroup::Unspecified, Rule::SnakeCaseTypeAlias),
(Flake8Pyi, "043") => (RuleGroup::Unspecified, Rule::TSuffixedTypeAlias),
(Flake8Pyi, "048") => (RuleGroup::Unspecified, Rule::StubBodyMultipleStatements),
(Flake8Pyi, "052") => (RuleGroup::Unspecified, Rule::UnannotatedAssignmentInStub),

// flake8-pytest-style
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/registry.rs
Expand Up @@ -519,6 +519,7 @@ ruff_macros::register_rules!(
rules::flake8_pyi::rules::PassStatementStubBody,
rules::flake8_pyi::rules::QuotedAnnotationInStub,
rules::flake8_pyi::rules::SnakeCaseTypeAlias,
rules::flake8_pyi::rules::StubBodyMultipleStatements,
rules::flake8_pyi::rules::TSuffixedTypeAlias,
rules::flake8_pyi::rules::TypeCommentInStub,
rules::flake8_pyi::rules::TypedArgumentDefaultInStub,
Expand Down
2 changes: 2 additions & 0 deletions crates/ruff/src/rules/flake8_pyi/mod.rs
Expand Up @@ -34,6 +34,8 @@ mod tests {
#[test_case(Rule::QuotedAnnotationInStub, Path::new("PYI020.pyi"))]
#[test_case(Rule::SnakeCaseTypeAlias, Path::new("PYI042.py"))]
#[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.pyi"))]
#[test_case(Rule::TypeCommentInStub, Path::new("PYI033.py"))]
Expand Down
4 changes: 4 additions & 0 deletions crates/ruff/src/rules/flake8_pyi/rules/mod.rs
Expand Up @@ -16,6 +16,9 @@ pub(crate) use simple_defaults::{
typed_argument_simple_defaults, unannotated_assignment_in_stub, ArgumentDefaultInStub,
AssignmentDefaultInStub, TypedArgumentDefaultInStub, UnannotatedAssignmentInStub,
};
pub(crate) use stub_body_multiple_statements::{
stub_body_multiple_statements, StubBodyMultipleStatements,
};
pub(crate) use type_alias_naming::{
snake_case_type_alias, t_suffixed_type_alias, SnakeCaseTypeAlias, TSuffixedTypeAlias,
};
Expand All @@ -34,6 +37,7 @@ mod pass_statement_stub_body;
mod prefix_type_params;
mod quoted_annotation_in_stub;
mod simple_defaults;
mod stub_body_multiple_statements;
mod type_alias_naming;
mod type_comment_in_stub;
mod unrecognized_platform;
@@ -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),
));
}
@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/flake8_pyi/mod.rs
---

@@ -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 change: 1 addition & 0 deletions ruff.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.