Skip to content

Commit 4d8890e

Browse files
[pylint] Omit stubs from invalid-bool and invalid-str-return-type (#11008)
## Summary Reflecting some improvements that were made in #10959.
1 parent 9f01ac3 commit 4d8890e

File tree

5 files changed

+65
-34
lines changed

5 files changed

+65
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,49 @@
11
# These testcases should raise errors
22

3+
34
class Float:
45
def __str__(self):
56
return 3.05
67

8+
79
class Int:
810
def __str__(self):
911
return 1
1012

13+
1114
class Int2:
1215
def __str__(self):
1316
return 0
1417

18+
1519
class Bool:
1620
def __str__(self):
1721
return False
1822

23+
1924
# TODO: Once Ruff has better type checking
2025
def return_int():
2126
return 3
2227

28+
2329
class ComplexReturn:
2430
def __str__(self):
2531
return return_int()
2632

33+
2734
# These testcases should NOT raise errors
2835

36+
2937
class Str:
3038
def __str__(self):
3139
return "ruff"
3240

41+
3342
class Str2:
3443
def __str__(self):
3544
x = "ruff"
3645
return x
46+
47+
48+
class Str3:
49+
def __str__(self): ...

crates/ruff_linter/src/checkers/ast/analyze/statement.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
9595
}
9696
}
9797
if checker.enabled(Rule::InvalidBoolReturnType) {
98-
pylint::rules::invalid_bool_return(checker, name, body);
98+
pylint::rules::invalid_bool_return(checker, function_def);
9999
}
100100
if checker.enabled(Rule::InvalidLengthReturnType) {
101101
pylint::rules::invalid_length_return(checker, function_def);
@@ -104,7 +104,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
104104
pylint::rules::invalid_bytes_return(checker, function_def);
105105
}
106106
if checker.enabled(Rule::InvalidStrReturnType) {
107-
pylint::rules::invalid_str_return(checker, name, body);
107+
pylint::rules::invalid_str_return(checker, function_def);
108108
}
109109
if checker.enabled(Rule::InvalidFunctionName) {
110110
if let Some(diagnostic) = pep8_naming::rules::invalid_function_name(

crates/ruff_linter/src/rules/pylint/rules/invalid_bool_return.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use ruff_diagnostics::{Diagnostic, Violation};
22
use ruff_macros::{derive_message_formats, violation};
33
use ruff_python_ast::helpers::ReturnStatementVisitor;
4+
use ruff_python_ast::identifier::Identifier;
45
use ruff_python_ast::visitor::Visitor;
5-
use ruff_python_ast::Stmt;
6+
use ruff_python_ast::{self as ast};
7+
use ruff_python_semantic::analyze::function_type::is_stub;
68
use ruff_python_semantic::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType};
79
use ruff_text_size::Ranged;
810

@@ -42,21 +44,32 @@ impl Violation for InvalidBoolReturnType {
4244
}
4345

4446
/// E0307
45-
pub(crate) fn invalid_bool_return(checker: &mut Checker, name: &str, body: &[Stmt]) {
46-
if name != "__bool__" {
47+
pub(crate) fn invalid_bool_return(checker: &mut Checker, function_def: &ast::StmtFunctionDef) {
48+
if function_def.name.as_str() != "__bool__" {
4749
return;
4850
}
4951

5052
if !checker.semantic().current_scope().kind.is_class() {
5153
return;
5254
}
5355

56+
if is_stub(function_def, checker.semantic()) {
57+
return;
58+
}
59+
5460
let returns = {
5561
let mut visitor = ReturnStatementVisitor::default();
56-
visitor.visit_body(body);
62+
visitor.visit_body(&function_def.body);
5763
visitor.returns
5864
};
5965

66+
if returns.is_empty() {
67+
checker.diagnostics.push(Diagnostic::new(
68+
InvalidBoolReturnType,
69+
function_def.identifier(),
70+
));
71+
}
72+
6073
for stmt in returns {
6174
if let Some(value) = stmt.value.as_deref() {
6275
if !matches!(

crates/ruff_linter/src/rules/pylint/rules/invalid_str_return.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use ruff_diagnostics::{Diagnostic, Violation};
22
use ruff_macros::{derive_message_formats, violation};
33
use ruff_python_ast::helpers::ReturnStatementVisitor;
4+
use ruff_python_ast::identifier::Identifier;
45
use ruff_python_ast::visitor::Visitor;
5-
use ruff_python_ast::Stmt;
6+
use ruff_python_ast::{self as ast};
7+
use ruff_python_semantic::analyze::function_type::is_stub;
68
use ruff_python_semantic::analyze::type_inference::{PythonType, ResolvedPythonType};
79
use ruff_text_size::Ranged;
810

@@ -42,21 +44,32 @@ impl Violation for InvalidStrReturnType {
4244
}
4345

4446
/// E0307
45-
pub(crate) fn invalid_str_return(checker: &mut Checker, name: &str, body: &[Stmt]) {
46-
if name != "__str__" {
47+
pub(crate) fn invalid_str_return(checker: &mut Checker, function_def: &ast::StmtFunctionDef) {
48+
if function_def.name.as_str() != "__str__" {
4749
return;
4850
}
4951

5052
if !checker.semantic().current_scope().kind.is_class() {
5153
return;
5254
}
5355

56+
if is_stub(function_def, checker.semantic()) {
57+
return;
58+
}
59+
5460
let returns = {
5561
let mut visitor = ReturnStatementVisitor::default();
56-
visitor.visit_body(body);
62+
visitor.visit_body(&function_def.body);
5763
visitor.returns
5864
};
5965

66+
if returns.is_empty() {
67+
checker.diagnostics.push(Diagnostic::new(
68+
InvalidStrReturnType,
69+
function_def.identifier(),
70+
));
71+
}
72+
6073
for stmt in returns {
6174
if let Some(value) = stmt.value.as_deref() {
6275
if !matches!(
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,34 @@
11
---
22
source: crates/ruff_linter/src/rules/pylint/mod.rs
33
---
4-
invalid_return_type_str.py:5:16: PLE0307 `__str__` does not return `str`
4+
invalid_return_type_str.py:6:16: PLE0307 `__str__` does not return `str`
55
|
6-
3 | class Float:
7-
4 | def __str__(self):
8-
5 | return 3.05
6+
4 | class Float:
7+
5 | def __str__(self):
8+
6 | return 3.05
99
| ^^^^ PLE0307
10-
6 |
11-
7 | class Int:
1210
|
1311

14-
invalid_return_type_str.py:9:16: PLE0307 `__str__` does not return `str`
12+
invalid_return_type_str.py:11:16: PLE0307 `__str__` does not return `str`
1513
|
16-
7 | class Int:
17-
8 | def __str__(self):
18-
9 | return 1
14+
9 | class Int:
15+
10 | def __str__(self):
16+
11 | return 1
1917
| ^ PLE0307
20-
10 |
21-
11 | class Int2:
2218
|
2319

24-
invalid_return_type_str.py:13:16: PLE0307 `__str__` does not return `str`
20+
invalid_return_type_str.py:16:16: PLE0307 `__str__` does not return `str`
2521
|
26-
11 | class Int2:
27-
12 | def __str__(self):
28-
13 | return 0
22+
14 | class Int2:
23+
15 | def __str__(self):
24+
16 | return 0
2925
| ^ PLE0307
30-
14 |
31-
15 | class Bool:
3226
|
3327

34-
invalid_return_type_str.py:17:16: PLE0307 `__str__` does not return `str`
28+
invalid_return_type_str.py:21:16: PLE0307 `__str__` does not return `str`
3529
|
36-
15 | class Bool:
37-
16 | def __str__(self):
38-
17 | return False
30+
19 | class Bool:
31+
20 | def __str__(self):
32+
21 | return False
3933
| ^^^^^ PLE0307
40-
18 |
41-
19 | # TODO: Once Ruff has better type checking
4234
|

0 commit comments

Comments
 (0)