mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:28 +00:00
Add TRIO110 rule (#8537)
## Summary Adds TRIO110 from the [flake8-trio plugin](https://github.com/Zac-HD/flake8-trio). Relates to: https://github.com/astral-sh/ruff/issues/8451
This commit is contained in:
parent
fce9f63418
commit
0126f74c29
8 changed files with 115 additions and 1 deletions
16
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO110.py
vendored
Normal file
16
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO110.py
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
import trio
|
||||
|
||||
|
||||
async def func():
|
||||
while True:
|
||||
await trio.sleep(10)
|
||||
|
||||
|
||||
async def func():
|
||||
while True:
|
||||
await trio.sleep_until(10)
|
||||
|
||||
|
||||
async def func():
|
||||
while True:
|
||||
trio.sleep(10)
|
|
@ -1206,7 +1206,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
flake8_trio::rules::timeout_without_await(checker, with_stmt, items);
|
||||
}
|
||||
}
|
||||
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
|
||||
Stmt::While(while_stmt @ ast::StmtWhile { body, orelse, .. }) => {
|
||||
if checker.enabled(Rule::FunctionUsesLoopVariable) {
|
||||
flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Stmt(stmt));
|
||||
}
|
||||
|
@ -1216,6 +1216,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::TryExceptInLoop) {
|
||||
perflint::rules::try_except_in_loop(checker, body);
|
||||
}
|
||||
if checker.enabled(Rule::TrioUnneededSleep) {
|
||||
flake8_trio::rules::unneeded_sleep(checker, while_stmt);
|
||||
}
|
||||
}
|
||||
Stmt::For(
|
||||
for_stmt @ ast::StmtFor {
|
||||
|
|
|
@ -293,6 +293,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
// flake8-trio
|
||||
(Flake8Trio, "100") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioTimeoutWithoutAwait),
|
||||
(Flake8Trio, "105") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioSyncCall),
|
||||
(Flake8Trio, "110") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioUnneededSleep),
|
||||
(Flake8Trio, "115") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioZeroSleepCall),
|
||||
|
||||
// flake8-builtins
|
||||
|
|
|
@ -16,6 +16,7 @@ mod tests {
|
|||
|
||||
#[test_case(Rule::TrioTimeoutWithoutAwait, Path::new("TRIO100.py"))]
|
||||
#[test_case(Rule::TrioSyncCall, Path::new("TRIO105.py"))]
|
||||
#[test_case(Rule::TrioUnneededSleep, Path::new("TRIO110.py"))]
|
||||
#[test_case(Rule::TrioZeroSleepCall, Path::new("TRIO115.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub(crate) use sync_call::*;
|
||||
pub(crate) use timeout_without_await::*;
|
||||
pub(crate) use unneeded_sleep::*;
|
||||
pub(crate) use zero_sleep_call::*;
|
||||
|
||||
mod sync_call;
|
||||
mod timeout_without_await;
|
||||
mod unneeded_sleep;
|
||||
mod zero_sleep_call;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for the use of `trio.sleep` in a `while` loop.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Instead of sleeping in a `while` loop, and waiting for a condition
|
||||
/// to become true, it's preferable to `wait()` on a `trio.Event`.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// DONE = False
|
||||
///
|
||||
///
|
||||
/// async def func():
|
||||
/// while not DONE:
|
||||
/// await trio.sleep(1)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// DONE = trio.Event()
|
||||
///
|
||||
///
|
||||
/// async def func():
|
||||
/// await DONE.wait()
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct TrioUnneededSleep;
|
||||
|
||||
impl Violation for TrioUnneededSleep {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use `trio.Event` instead of awaiting `trio.sleep` in a `while` loop")
|
||||
}
|
||||
}
|
||||
|
||||
/// TRIO110
|
||||
pub(crate) fn unneeded_sleep(checker: &mut Checker, while_stmt: &ast::StmtWhile) {
|
||||
// The body should be a single `await` call.
|
||||
let [stmt] = while_stmt.body.as_slice() else {
|
||||
return;
|
||||
};
|
||||
let Stmt::Expr(ast::StmtExpr { value, .. }) = stmt else {
|
||||
return;
|
||||
};
|
||||
let Expr::Await(ast::ExprAwait { value, .. }) = value.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if checker
|
||||
.semantic()
|
||||
.resolve_call_path(func.as_ref())
|
||||
.is_some_and(|path| matches!(path.as_slice(), ["trio", "sleep" | "sleep_until"]))
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(TrioUnneededSleep, while_stmt.range()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_trio/mod.rs
|
||||
---
|
||||
TRIO110.py:5:5: TRIO110 Use `trio.Event` instead of awaiting `trio.sleep` in a `while` loop
|
||||
|
|
||||
4 | async def func():
|
||||
5 | while True:
|
||||
| _____^
|
||||
6 | | await trio.sleep(10)
|
||||
| |____________________________^ TRIO110
|
||||
|
|
||||
|
||||
TRIO110.py:10:5: TRIO110 Use `trio.Event` instead of awaiting `trio.sleep` in a `while` loop
|
||||
|
|
||||
9 | async def func():
|
||||
10 | while True:
|
||||
| _____^
|
||||
11 | | await trio.sleep_until(10)
|
||||
| |__________________________________^ TRIO110
|
||||
|
|
||||
|
||||
|
1
ruff.schema.json
generated
1
ruff.schema.json
generated
|
@ -3476,6 +3476,7 @@
|
|||
"TRIO100",
|
||||
"TRIO105",
|
||||
"TRIO11",
|
||||
"TRIO110",
|
||||
"TRIO115",
|
||||
"TRY",
|
||||
"TRY0",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue