Skip to content

Commit 06c248a

Browse files
[ruff] Ignore stub functions in unused-async (RUF029) (#11026)
## Summary We should ignore methods that appear to be stubs, e.g.: ```python async def foo() -> int: ... ``` Closes #11018.
1 parent 27902b7 commit 06c248a

File tree

3 files changed

+34
-32
lines changed

3 files changed

+34
-32
lines changed

crates/ruff_linter/resources/test/fixtures/ruff/RUF029.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ async def pass_3(): # OK: uses an async loop
2222

2323

2424
class Foo:
25-
async def pass_4(): # OK: method of a class
25+
async def pass_4(self): # OK: method of a class
2626
pass
2727

2828

@@ -31,6 +31,10 @@ async def pass_5(): # OK: uses an await
3131
await bla
3232

3333

34+
async def pass_6(): # OK: just a stub
35+
...
36+
37+
3438
async def fail_1a(): # RUF029
3539
time.sleep(1)
3640

@@ -58,7 +62,7 @@ async def foo():
5862

5963
async def fail_4b(): # RUF029: the /outer/ function does not await
6064
class Foo:
61-
async def foo():
65+
async def foo(self):
6266
await bla
6367

6468

crates/ruff_linter/src/rules/ruff/rules/unused_async.rs

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
33
use ruff_python_ast::identifier::Identifier;
44
use ruff_python_ast::visitor::preorder;
55
use ruff_python_ast::{self as ast, AnyNodeRef, Expr, Stmt};
6+
use ruff_python_semantic::analyze::function_type::is_stub;
67

78
use crate::checkers::ast::Checker;
89

@@ -160,6 +161,11 @@ pub(crate) fn unused_async(
160161
return;
161162
}
162163

164+
// Ignore stubs (e.g., `...`).
165+
if is_stub(function_def, checker.semantic()) {
166+
return;
167+
}
168+
163169
let found_await_or_async = {
164170
let mut visitor = AsyncExprVisitor::default();
165171
preorder::walk_body(&mut visitor, body);
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,48 @@
11
---
22
source: crates/ruff_linter/src/rules/ruff/mod.rs
33
---
4-
RUF029.py:34:11: RUF029 Function `fail_1a` is declared `async`, but doesn't `await` or use `async` features.
4+
RUF029.py:38:11: RUF029 Function `fail_1a` is declared `async`, but doesn't `await` or use `async` features.
55
|
6-
34 | async def fail_1a(): # RUF029
6+
38 | async def fail_1a(): # RUF029
77
| ^^^^^^^ RUF029
8-
35 | time.sleep(1)
8+
39 | time.sleep(1)
99
|
1010

11-
RUF029.py:38:11: RUF029 Function `fail_1b` is declared `async`, but doesn't `await` or use `async` features.
11+
RUF029.py:42:11: RUF029 Function `fail_1b` is declared `async`, but doesn't `await` or use `async` features.
1212
|
13-
38 | async def fail_1b(): # RUF029: yield does not require async
13+
42 | async def fail_1b(): # RUF029: yield does not require async
1414
| ^^^^^^^ RUF029
15-
39 | yield "hello"
15+
43 | yield "hello"
1616
|
1717

18-
RUF029.py:42:11: RUF029 Function `fail_2` is declared `async`, but doesn't `await` or use `async` features.
18+
RUF029.py:46:11: RUF029 Function `fail_2` is declared `async`, but doesn't `await` or use `async` features.
1919
|
20-
42 | async def fail_2(): # RUF029
20+
46 | async def fail_2(): # RUF029
2121
| ^^^^^^ RUF029
22-
43 | with None as i:
23-
44 | pass
22+
47 | with None as i:
23+
48 | pass
2424
|
2525

26-
RUF029.py:47:11: RUF029 Function `fail_3` is declared `async`, but doesn't `await` or use `async` features.
26+
RUF029.py:51:11: RUF029 Function `fail_3` is declared `async`, but doesn't `await` or use `async` features.
2727
|
28-
47 | async def fail_3(): # RUF029
28+
51 | async def fail_3(): # RUF029
2929
| ^^^^^^ RUF029
30-
48 | for i in []:
31-
49 | pass
30+
52 | for i in []:
31+
53 | pass
3232
|
3333

34-
RUF029.py:54:11: RUF029 Function `fail_4a` is declared `async`, but doesn't `await` or use `async` features.
34+
RUF029.py:58:11: RUF029 Function `fail_4a` is declared `async`, but doesn't `await` or use `async` features.
3535
|
36-
54 | async def fail_4a(): # RUF029: the /outer/ function does not await
36+
58 | async def fail_4a(): # RUF029: the /outer/ function does not await
3737
| ^^^^^^^ RUF029
38-
55 | async def foo():
39-
56 | await bla
38+
59 | async def foo():
39+
60 | await bla
4040
|
4141

42-
RUF029.py:59:11: RUF029 Function `fail_4b` is declared `async`, but doesn't `await` or use `async` features.
42+
RUF029.py:63:11: RUF029 Function `fail_4b` is declared `async`, but doesn't `await` or use `async` features.
4343
|
44-
59 | async def fail_4b(): # RUF029: the /outer/ function does not await
44+
63 | async def fail_4b(): # RUF029: the /outer/ function does not await
4545
| ^^^^^^^ RUF029
46-
60 | class Foo:
47-
61 | async def foo():
48-
|
49-
50-
RUF029.py:66:15: RUF029 Function `fail_4c` is declared `async`, but doesn't `await` or use `async` features.
51-
|
52-
65 | def foo():
53-
66 | async def fail_4c(): # RUF029: the /inner/ function does not await
54-
| ^^^^^^^ RUF029
55-
67 | pass
46+
64 | class Foo:
47+
65 | async def foo(self):
5648
|

0 commit comments

Comments
 (0)