[pylint] Omit stubs from invalid-bool and invalid-str-return-type (#11008)

## Summary

Reflecting some improvements that were made in
https://github.com/astral-sh/ruff/pull/10959.
This commit is contained in:
Charlie Marsh 2024-04-17 21:57:20 -04:00 committed by GitHub
parent 9f01ac3f87
commit 4d8890eef5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 65 additions and 34 deletions

View file

@ -1,36 +1,49 @@
# These testcases should raise errors # These testcases should raise errors
class Float: class Float:
def __str__(self): def __str__(self):
return 3.05 return 3.05
class Int: class Int:
def __str__(self): def __str__(self):
return 1 return 1
class Int2: class Int2:
def __str__(self): def __str__(self):
return 0 return 0
class Bool: class Bool:
def __str__(self): def __str__(self):
return False return False
# TODO: Once Ruff has better type checking # TODO: Once Ruff has better type checking
def return_int(): def return_int():
return 3 return 3
class ComplexReturn: class ComplexReturn:
def __str__(self): def __str__(self):
return return_int() return return_int()
# These testcases should NOT raise errors # These testcases should NOT raise errors
class Str: class Str:
def __str__(self): def __str__(self):
return "ruff" return "ruff"
class Str2: class Str2:
def __str__(self): def __str__(self):
x = "ruff" x = "ruff"
return x return x
class Str3:
def __str__(self): ...

View file

@ -95,7 +95,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
} }
if checker.enabled(Rule::InvalidBoolReturnType) { if checker.enabled(Rule::InvalidBoolReturnType) {
pylint::rules::invalid_bool_return(checker, name, body); pylint::rules::invalid_bool_return(checker, function_def);
} }
if checker.enabled(Rule::InvalidLengthReturnType) { if checker.enabled(Rule::InvalidLengthReturnType) {
pylint::rules::invalid_length_return(checker, function_def); pylint::rules::invalid_length_return(checker, function_def);
@ -104,7 +104,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pylint::rules::invalid_bytes_return(checker, function_def); pylint::rules::invalid_bytes_return(checker, function_def);
} }
if checker.enabled(Rule::InvalidStrReturnType) { if checker.enabled(Rule::InvalidStrReturnType) {
pylint::rules::invalid_str_return(checker, name, body); pylint::rules::invalid_str_return(checker, function_def);
} }
if checker.enabled(Rule::InvalidFunctionName) { if checker.enabled(Rule::InvalidFunctionName) {
if let Some(diagnostic) = pep8_naming::rules::invalid_function_name( if let Some(diagnostic) = pep8_naming::rules::invalid_function_name(

View file

@ -1,8 +1,10 @@
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::ReturnStatementVisitor; use ruff_python_ast::helpers::ReturnStatementVisitor;
use ruff_python_ast::identifier::Identifier;
use ruff_python_ast::visitor::Visitor; use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::Stmt; use ruff_python_ast::{self as ast};
use ruff_python_semantic::analyze::function_type::is_stub;
use ruff_python_semantic::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType}; use ruff_python_semantic::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
@ -42,8 +44,8 @@ impl Violation for InvalidBoolReturnType {
} }
/// E0307 /// E0307
pub(crate) fn invalid_bool_return(checker: &mut Checker, name: &str, body: &[Stmt]) { pub(crate) fn invalid_bool_return(checker: &mut Checker, function_def: &ast::StmtFunctionDef) {
if name != "__bool__" { if function_def.name.as_str() != "__bool__" {
return; return;
} }
@ -51,12 +53,23 @@ pub(crate) fn invalid_bool_return(checker: &mut Checker, name: &str, body: &[Stm
return; return;
} }
if is_stub(function_def, checker.semantic()) {
return;
}
let returns = { let returns = {
let mut visitor = ReturnStatementVisitor::default(); let mut visitor = ReturnStatementVisitor::default();
visitor.visit_body(body); visitor.visit_body(&function_def.body);
visitor.returns visitor.returns
}; };
if returns.is_empty() {
checker.diagnostics.push(Diagnostic::new(
InvalidBoolReturnType,
function_def.identifier(),
));
}
for stmt in returns { for stmt in returns {
if let Some(value) = stmt.value.as_deref() { if let Some(value) = stmt.value.as_deref() {
if !matches!( if !matches!(

View file

@ -1,8 +1,10 @@
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::ReturnStatementVisitor; use ruff_python_ast::helpers::ReturnStatementVisitor;
use ruff_python_ast::identifier::Identifier;
use ruff_python_ast::visitor::Visitor; use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::Stmt; use ruff_python_ast::{self as ast};
use ruff_python_semantic::analyze::function_type::is_stub;
use ruff_python_semantic::analyze::type_inference::{PythonType, ResolvedPythonType}; use ruff_python_semantic::analyze::type_inference::{PythonType, ResolvedPythonType};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
@ -42,8 +44,8 @@ impl Violation for InvalidStrReturnType {
} }
/// E0307 /// E0307
pub(crate) fn invalid_str_return(checker: &mut Checker, name: &str, body: &[Stmt]) { pub(crate) fn invalid_str_return(checker: &mut Checker, function_def: &ast::StmtFunctionDef) {
if name != "__str__" { if function_def.name.as_str() != "__str__" {
return; return;
} }
@ -51,12 +53,23 @@ pub(crate) fn invalid_str_return(checker: &mut Checker, name: &str, body: &[Stmt
return; return;
} }
if is_stub(function_def, checker.semantic()) {
return;
}
let returns = { let returns = {
let mut visitor = ReturnStatementVisitor::default(); let mut visitor = ReturnStatementVisitor::default();
visitor.visit_body(body); visitor.visit_body(&function_def.body);
visitor.returns visitor.returns
}; };
if returns.is_empty() {
checker.diagnostics.push(Diagnostic::new(
InvalidStrReturnType,
function_def.identifier(),
));
}
for stmt in returns { for stmt in returns {
if let Some(value) = stmt.value.as_deref() { if let Some(value) = stmt.value.as_deref() {
if !matches!( if !matches!(

View file

@ -1,42 +1,34 @@
--- ---
source: crates/ruff_linter/src/rules/pylint/mod.rs source: crates/ruff_linter/src/rules/pylint/mod.rs
--- ---
invalid_return_type_str.py:5:16: PLE0307 `__str__` does not return `str` invalid_return_type_str.py:6:16: PLE0307 `__str__` does not return `str`
| |
3 | class Float: 4 | class Float:
4 | def __str__(self): 5 | def __str__(self):
5 | return 3.05 6 | return 3.05
| ^^^^ PLE0307 | ^^^^ PLE0307
6 |
7 | class Int:
| |
invalid_return_type_str.py:9:16: PLE0307 `__str__` does not return `str` invalid_return_type_str.py:11:16: PLE0307 `__str__` does not return `str`
| |
7 | class Int: 9 | class Int:
8 | def __str__(self): 10 | def __str__(self):
9 | return 1 11 | return 1
| ^ PLE0307 | ^ PLE0307
10 |
11 | class Int2:
| |
invalid_return_type_str.py:13:16: PLE0307 `__str__` does not return `str` invalid_return_type_str.py:16:16: PLE0307 `__str__` does not return `str`
| |
11 | class Int2: 14 | class Int2:
12 | def __str__(self): 15 | def __str__(self):
13 | return 0 16 | return 0
| ^ PLE0307 | ^ PLE0307
14 |
15 | class Bool:
| |
invalid_return_type_str.py:17:16: PLE0307 `__str__` does not return `str` invalid_return_type_str.py:21:16: PLE0307 `__str__` does not return `str`
| |
15 | class Bool: 19 | class Bool:
16 | def __str__(self): 20 | def __str__(self):
17 | return False 21 | return False
| ^^^^^ PLE0307 | ^^^^^ PLE0307
18 |
19 | # TODO: Once Ruff has better type checking
| |