[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 https://github.com/astral-sh/ruff/issues/11018.
This commit is contained in:
Charlie Marsh 2024-04-19 00:03:52 -04:00 committed by GitHub
parent 27902b7130
commit 06c248a126
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 32 deletions

View file

@ -22,7 +22,7 @@ async def pass_3(): # OK: uses an async loop
class Foo: class Foo:
async def pass_4(): # OK: method of a class async def pass_4(self): # OK: method of a class
pass pass
@ -31,6 +31,10 @@ def foo():
await bla await bla
async def pass_6(): # OK: just a stub
...
async def fail_1a(): # RUF029 async def fail_1a(): # RUF029
time.sleep(1) time.sleep(1)
@ -58,7 +62,7 @@ async def fail_4a(): # RUF029: the /outer/ function does not await
async def fail_4b(): # RUF029: the /outer/ function does not await async def fail_4b(): # RUF029: the /outer/ function does not await
class Foo: class Foo:
async def foo(): async def foo(self):
await bla await bla

View file

@ -3,6 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::identifier::Identifier; use ruff_python_ast::identifier::Identifier;
use ruff_python_ast::visitor::preorder; use ruff_python_ast::visitor::preorder;
use ruff_python_ast::{self as ast, AnyNodeRef, Expr, Stmt}; use ruff_python_ast::{self as ast, AnyNodeRef, Expr, Stmt};
use ruff_python_semantic::analyze::function_type::is_stub;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -160,6 +161,11 @@ pub(crate) fn unused_async(
return; return;
} }
// Ignore stubs (e.g., `...`).
if is_stub(function_def, checker.semantic()) {
return;
}
let found_await_or_async = { let found_await_or_async = {
let mut visitor = AsyncExprVisitor::default(); let mut visitor = AsyncExprVisitor::default();
preorder::walk_body(&mut visitor, body); preorder::walk_body(&mut visitor, body);

View file

@ -1,56 +1,48 @@
--- ---
source: crates/ruff_linter/src/rules/ruff/mod.rs source: crates/ruff_linter/src/rules/ruff/mod.rs
--- ---
RUF029.py:34:11: RUF029 Function `fail_1a` is declared `async`, but doesn't `await` or use `async` features. RUF029.py:38:11: RUF029 Function `fail_1a` is declared `async`, but doesn't `await` or use `async` features.
| |
34 | async def fail_1a(): # RUF029 38 | async def fail_1a(): # RUF029
| ^^^^^^^ RUF029 | ^^^^^^^ RUF029
35 | time.sleep(1) 39 | time.sleep(1)
| |
RUF029.py:38:11: RUF029 Function `fail_1b` is declared `async`, but doesn't `await` or use `async` features. RUF029.py:42:11: RUF029 Function `fail_1b` is declared `async`, but doesn't `await` or use `async` features.
| |
38 | async def fail_1b(): # RUF029: yield does not require async 42 | async def fail_1b(): # RUF029: yield does not require async
| ^^^^^^^ RUF029 | ^^^^^^^ RUF029
39 | yield "hello" 43 | yield "hello"
| |
RUF029.py:42:11: RUF029 Function `fail_2` is declared `async`, but doesn't `await` or use `async` features. RUF029.py:46:11: RUF029 Function `fail_2` is declared `async`, but doesn't `await` or use `async` features.
| |
42 | async def fail_2(): # RUF029 46 | async def fail_2(): # RUF029
| ^^^^^^ RUF029 | ^^^^^^ RUF029
43 | with None as i: 47 | with None as i:
44 | pass 48 | pass
| |
RUF029.py:47:11: RUF029 Function `fail_3` is declared `async`, but doesn't `await` or use `async` features. RUF029.py:51:11: RUF029 Function `fail_3` is declared `async`, but doesn't `await` or use `async` features.
| |
47 | async def fail_3(): # RUF029 51 | async def fail_3(): # RUF029
| ^^^^^^ RUF029 | ^^^^^^ RUF029
48 | for i in []: 52 | for i in []:
49 | pass 53 | pass
| |
RUF029.py:54:11: RUF029 Function `fail_4a` is declared `async`, but doesn't `await` or use `async` features. RUF029.py:58:11: RUF029 Function `fail_4a` is declared `async`, but doesn't `await` or use `async` features.
| |
54 | async def fail_4a(): # RUF029: the /outer/ function does not await 58 | async def fail_4a(): # RUF029: the /outer/ function does not await
| ^^^^^^^ RUF029 | ^^^^^^^ RUF029
55 | async def foo(): 59 | async def foo():
56 | await bla 60 | await bla
| |
RUF029.py:59:11: RUF029 Function `fail_4b` is declared `async`, but doesn't `await` or use `async` features. RUF029.py:63:11: RUF029 Function `fail_4b` is declared `async`, but doesn't `await` or use `async` features.
| |
59 | async def fail_4b(): # RUF029: the /outer/ function does not await 63 | async def fail_4b(): # RUF029: the /outer/ function does not await
| ^^^^^^^ RUF029 | ^^^^^^^ RUF029
60 | class Foo: 64 | class Foo:
61 | async def foo(): 65 | async def foo(self):
|
RUF029.py:66:15: RUF029 Function `fail_4c` is declared `async`, but doesn't `await` or use `async` features.
|
65 | def foo():
66 | async def fail_4c(): # RUF029: the /inner/ function does not await
| ^^^^^^^ RUF029
67 | pass
| |