Only flag flake8-trio rule when trio is present (#8550)

## Summary

Hoping to avoid some false positives by narrowing the scope of
https://github.com/astral-sh/ruff/pull/8534.
This commit is contained in:
Charlie Marsh 2023-11-07 14:27:58 -08:00 committed by GitHub
parent e2c7b1ece6
commit 71e93a9fa4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 6 deletions

View file

@ -1,3 +1,6 @@
import trio
async def func(): async def func():
... ...

View file

@ -13,6 +13,10 @@ use crate::checkers::ast::Checker;
/// trio's built-in timeout functionality, available as `trio.fail_after`, /// trio's built-in timeout functionality, available as `trio.fail_after`,
/// `trio.move_on_after`, `trio.fail_at`, and `trio.move_on_at`. /// `trio.move_on_after`, `trio.fail_at`, and `trio.move_on_at`.
/// ///
/// ## Known problems
/// To avoid false positives, this rule is only enabled if `trio` is imported
/// in the module.
///
/// ## Example /// ## Example
/// ```python /// ```python
/// async def func(): /// async def func():
@ -40,12 +44,19 @@ pub(crate) fn async_function_with_timeout(
checker: &mut Checker, checker: &mut Checker,
function_def: &ast::StmtFunctionDef, function_def: &ast::StmtFunctionDef,
) { ) {
// Detect `async` calls with a `timeout` argument.
if !function_def.is_async { if !function_def.is_async {
return; return;
} }
let Some(timeout) = function_def.parameters.find("timeout") else { let Some(timeout) = function_def.parameters.find("timeout") else {
return; return;
}; };
// If `trio` isn't in scope, avoid raising the diagnostic.
if !checker.semantic().seen(&["trio"]) {
return;
}
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
TrioAsyncFunctionWithTimeout, TrioAsyncFunctionWithTimeout,
timeout.range(), timeout.range(),

View file

@ -1,18 +1,18 @@
--- ---
source: crates/ruff_linter/src/rules/flake8_trio/mod.rs source: crates/ruff_linter/src/rules/flake8_trio/mod.rs
--- ---
TRIO109.py:5:16: TRIO109 Prefer `trio.fail_after` and `trio.move_on_after` over manual `async` timeout behavior TRIO109.py:8:16: TRIO109 Prefer `trio.fail_after` and `trio.move_on_after` over manual `async` timeout behavior
| |
5 | async def func(timeout): 8 | async def func(timeout):
| ^^^^^^^ TRIO109 | ^^^^^^^ TRIO109
6 | ... 9 | ...
| |
TRIO109.py:9:16: TRIO109 Prefer `trio.fail_after` and `trio.move_on_after` over manual `async` timeout behavior TRIO109.py:12:16: TRIO109 Prefer `trio.fail_after` and `trio.move_on_after` over manual `async` timeout behavior
| |
9 | async def func(timeout=10): 12 | async def func(timeout=10):
| ^^^^^^^^^^ TRIO109 | ^^^^^^^^^^ TRIO109
10 | ... 13 | ...
| |

View file

@ -1207,6 +1207,16 @@ impl<'a> SemanticModel<'a> {
exceptions exceptions
} }
/// Return `true` if the module at the given path was seen anywhere in the semantic model.
/// This includes both direct imports (`import trio`) and member imports (`from trio import
/// TrioTask`).
pub fn seen(&self, module: &[&str]) -> bool {
self.bindings
.iter()
.filter_map(Binding::as_any_import)
.any(|import| import.call_path().starts_with(module))
}
/// Generate a [`Snapshot`] of the current semantic model. /// Generate a [`Snapshot`] of the current semantic model.
pub fn snapshot(&self) -> Snapshot { pub fn snapshot(&self) -> Snapshot {
Snapshot { Snapshot {