Skip to content

Commit

Permalink
Improve RUF006 detection
Browse files Browse the repository at this point in the history
  • Loading branch information
tyilo committed Feb 13, 2024
1 parent 46db3f9 commit 10b5a83
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 7 deletions.
23 changes: 23 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF006.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,26 @@ async def f(x: bool):
T = asyncio.create_task(asyncio.sleep(1))
else:
T = None


# Error
def f():
loop = asyncio.new_event_loop()
loop.create_task(main()) # Error

# Error
def f():
loop = asyncio.get_event_loop()
loop.create_task(main()) # Error

# OK
def f():
global task
loop = asyncio.new_event_loop()
task = loop.create_task(main()) # Error

# OK
def f():
global task
loop = asyncio.get_event_loop()
task = loop.create_task(main()) # Error
21 changes: 16 additions & 5 deletions crates/ruff_linter/src/rules/ruff/rules/asyncio_dangling_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ use ruff_text_size::Ranged;
/// - [The Python Standard Library](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task)
#[violation]
pub struct AsyncioDanglingTask {
expr: &'static str,
method: Method,
}

impl Violation for AsyncioDanglingTask {
#[derive_message_formats]
fn message(&self) -> String {
let AsyncioDanglingTask { method } = self;
format!("Store a reference to the return value of `asyncio.{method}`")
let AsyncioDanglingTask { expr, method } = self;
format!("Store a reference to the return value of `{expr}.{method}`")
}
}

Expand All @@ -80,19 +81,29 @@ pub(crate) fn asyncio_dangling_task(expr: &Expr, semantic: &SemanticModel) -> Op
})
{
return Some(Diagnostic::new(
AsyncioDanglingTask { method },
AsyncioDanglingTask {
expr: "asyncio",
method,
},
expr.range(),
));
}

// Ex) `loop = asyncio.get_running_loop(); loop.create_task(...)`
// Ex) `loop = ...; loop.create_task(...)`
if let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() {
if attr == "create_task" {
if typing::resolve_assignment(value, semantic).is_some_and(|call_path| {
matches!(call_path.as_slice(), ["asyncio", "get_running_loop"])
matches!(
call_path.as_slice(),
[
"asyncio",
"get_event_loop" | "get_running_loop" | "new_event_loop"
]
)
}) {
return Some(Diagnostic::new(
AsyncioDanglingTask {
expr: "loop", // TODO: How can you turn `value` into a string?
method: Method::CreateTask,
},
expr.range(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,40 @@ RUF006.py:68:12: RUF006 Store a reference to the return value of `asyncio.create
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF006
|

RUF006.py:74:26: RUF006 Store a reference to the return value of `asyncio.create_task`
RUF006.py:74:26: RUF006 Store a reference to the return value of `loop.create_task`
|
72 | def f():
73 | loop = asyncio.get_running_loop()
74 | task: asyncio.Task = loop.create_task(coordinator.ws_connect())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF006
|

RUF006.py:97:5: RUF006 Store a reference to the return value of `asyncio.create_task`
RUF006.py:97:5: RUF006 Store a reference to the return value of `loop.create_task`
|
95 | def f():
96 | loop = asyncio.get_running_loop()
97 | loop.create_task(coordinator.ws_connect()) # Error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF006
|

RUF006.py:170:5: RUF006 Store a reference to the return value of `loop.create_task`
|
168 | def f():
169 | loop = asyncio.new_event_loop()
170 | loop.create_task(main()) # Error
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF006
171 |
172 | # Error
|

RUF006.py:175:5: RUF006 Store a reference to the return value of `loop.create_task`
|
173 | def f():
174 | loop = asyncio.get_event_loop()
175 | loop.create_task(main()) # Error
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF006
176 |
177 | # OK
|


0 comments on commit 10b5a83

Please sign in to comment.