Re-code flake8-trio and flake8-async rules to match upstream (#10416)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Auguste Lalande 2024-06-26 04:42:39 -04:00 committed by Micha Reiser
parent 4b3278fe0b
commit 8cc96d7868
51 changed files with 1422 additions and 595 deletions

View file

@ -334,7 +334,6 @@ quality tools, including:
- [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
- [flake8-todos](https://pypi.org/project/flake8-todos/)
- [flake8-trio](https://pypi.org/project/flake8-trio/)
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))

View file

@ -1,23 +1,27 @@
import urllib.request
import requests
import httpx
import trio
async def foo():
urllib.request.urlopen("http://example.com/foo/bar").read()
async def func():
with trio.fail_after():
...
async def foo():
requests.get()
async def func():
with trio.fail_at():
await ...
async def foo():
httpx.get()
async def func():
with trio.move_on_after():
...
async def foo():
requests.post()
async def func():
with trio.move_at():
await ...
async def foo():
httpx.post()
async def func():
with trio.move_at():
async with trio.open_nursery() as nursery:
...

View file

@ -1,13 +0,0 @@
import os
async def foo():
os.popen()
async def foo():
os.spawnl()
async def foo():
os.fspath("foo")

View file

@ -26,7 +26,7 @@ async def func() -> None:
await trio.lowlevel.wait_task_rescheduled(foo)
await trio.lowlevel.wait_writable(foo)
# TRIO105
# ASYNC105
trio.aclose_forcefully(foo)
trio.open_file(foo)
trio.open_ssl_over_tcp_listeners(foo, foo)
@ -55,10 +55,10 @@ async def func() -> None:
async with await trio.open_file(foo): # Ok
pass
async with trio.open_file(foo): # TRIO105
async with trio.open_file(foo): # ASYNC105
pass
def func() -> None:
# TRIO105 (without fix)
# ASYNC105 (without fix)
trio.open_file(foo)

View file

@ -2,19 +2,19 @@ async def func():
import trio
from trio import sleep
await trio.sleep(0) # TRIO115
await trio.sleep(0) # ASYNC115
await trio.sleep(1) # OK
await trio.sleep(0, 1) # OK
await trio.sleep(...) # OK
await trio.sleep() # OK
trio.sleep(0) # TRIO115
trio.sleep(0) # ASYNC115
foo = 0
trio.sleep(foo) # OK
trio.sleep(1) # OK
time.sleep(0) # OK
sleep(0) # TRIO115
sleep(0) # ASYNC115
bar = "bar"
trio.sleep(bar)
@ -45,18 +45,18 @@ async def func():
def func():
import trio
trio.run(trio.sleep(0)) # TRIO115
trio.run(trio.sleep(0)) # ASYNC115
from trio import Event, sleep
def func():
sleep(0) # TRIO115
sleep(0) # ASYNC115
async def func():
await sleep(seconds=0) # TRIO115
await sleep(seconds=0) # ASYNC115
def func():

View file

@ -0,0 +1,69 @@
import urllib
import requests
import httpx
import urllib3
async def foo():
urllib.request.urlopen("http://example.com/foo/bar").read() # ASYNC210
async def foo():
requests.get() # ASYNC210
async def foo():
httpx.get() # ASYNC210
async def foo():
requests.post() # ASYNC210
async def foo():
httpx.post() # ASYNC210
async def foo():
requests.get() # ASYNC210
requests.get(...) # ASYNC210
requests.get # Ok
print(requests.get()) # ASYNC210
print(requests.get(requests.get())) # ASYNC210
requests.options() # ASYNC210
requests.head() # ASYNC210
requests.post() # ASYNC210
requests.put() # ASYNC210
requests.patch() # ASYNC210
requests.delete() # ASYNC210
requests.foo()
httpx.options("") # ASYNC210
httpx.head("") # ASYNC210
httpx.post("") # ASYNC210
httpx.put("") # ASYNC210
httpx.patch("") # ASYNC210
httpx.delete("") # ASYNC210
httpx.foo() # Ok
urllib3.request() # ASYNC210
urllib3.request(...) # ASYNC210
urllib.request.urlopen("") # ASYNC210
r = {}
r.get("not a sync http client") # Ok
async def bar():
def request():
pass
request() # Ok
def urlopen():
pass
urlopen() # Ok

View file

@ -0,0 +1,98 @@
import os
import subprocess
# Violation cases:
async def func():
subprocess.run("foo") # ASYNC221
async def func():
subprocess.call("foo") # ASYNC221
async def func():
subprocess.foo(0) # OK
async def func():
os.wait4(10) # ASYNC222
async def func():
os.wait(12) # ASYNC222
async def foo():
await async_fun(
subprocess.getoutput() # ASYNC221
)
subprocess.Popen() # ASYNC220
os.system() # ASYNC221
system()
os.system.anything()
os.anything()
subprocess.run() # ASYNC221
subprocess.call() # ASYNC221
subprocess.check_call() # ASYNC221
subprocess.check_output() # ASYNC221
subprocess.getoutput() # ASYNC221
subprocess.getstatusoutput() # ASYNC221
await async_fun(
subprocess.getoutput() # ASYNC221
)
subprocess.anything()
subprocess.foo()
subprocess.bar.foo()
subprocess()
os.posix_spawn() # ASYNC221
os.posix_spawnp() # ASYNC221
os.spawn()
os.spawn
os.spawnllll()
os.spawnl() # ASYNC221
os.spawnle() # ASYNC221
os.spawnlp() # ASYNC221
os.spawnlpe() # ASYNC221
os.spawnv() # ASYNC221
os.spawnve() # ASYNC221
os.spawnvp() # ASYNC221
os.spawnvpe() # ASYNC221
P_NOWAIT = os.P_NOWAIT
# if mode is given, and is not os.P_WAIT: ASYNC220
os.spawnl(os.P_NOWAIT) # ASYNC220
os.spawnl(P_NOWAIT) # ASYNC220
os.spawnl(mode=os.P_NOWAIT) # ASYNC220
os.spawnl(mode=P_NOWAIT) # ASYNC220
P_WAIT = os.P_WAIT
# if it is P_WAIT, ASYNC221
os.spawnl(P_WAIT) # ASYNC221
os.spawnl(mode=os.P_WAIT) # ASYNC221
os.spawnl(mode=P_WAIT) # ASYNC221
# other weird cases: ASYNC220
os.spawnl(0) # ASYNC220
os.spawnl(1) # ASYNC220
os.spawnl(foo()) # ASYNC220
# ASYNC222
os.wait() # ASYNC222
os.wait3() # ASYNC222
os.wait4() # ASYNC222
os.waitid() # ASYNC222
os.waitpid() # ASYNC222
os.waitpi()
os.waiti()

View file

@ -1,53 +1,48 @@
import os
import subprocess
import time
import io
from pathlib import Path
async def foo():
open("") # ASYNC230
io.open_code("") # ASYNC230
with open(""): # ASYNC230
...
with open("") as f: # ASYNC230
...
with foo(), open(""): # ASYNC230
...
async with open(""): # ASYNC230
...
def foo_sync():
open("")
# Violation cases:
async def func():
open("foo")
async def func():
time.sleep(1)
async def func():
subprocess.run("foo")
async def func():
subprocess.call("foo")
async def func():
subprocess.foo(0)
async def func():
os.wait4(10)
async def func():
os.wait(12)
open("foo") # ASYNC230
# Violation cases for pathlib:
async def func():
Path("foo").open() # ASYNC101
Path("foo").open() # ASYNC230
async def func():
p = Path("foo")
p.open() # ASYNC101
p.open() # ASYNC230
async def func():
with Path("foo").open() as f: # ASYNC101
with Path("foo").open() as f: # ASYNC230
pass
@ -55,13 +50,13 @@ async def func() -> None:
p = Path("foo")
async def bar():
p.open() # ASYNC101
p.open() # ASYNC230
async def func() -> None:
(p1, p2) = (Path("foo"), Path("bar"))
p1.open() # ASYNC101
p1.open() # ASYNC230
# Non-violation cases for pathlib:

View file

@ -0,0 +1,14 @@
import time
import asyncio
async def func():
time.sleep(1) # ASYNC251
def func():
time.sleep(1) # OK
async def func():
asyncio.sleep(1) # OK

View file

@ -1,27 +0,0 @@
import trio
async def func():
with trio.fail_after():
...
async def func():
with trio.fail_at():
await ...
async def func():
with trio.move_on_after():
...
async def func():
with trio.move_at():
await ...
async def func():
with trio.move_at():
async with trio.open_nursery() as nursery:
...

View file

@ -15,8 +15,8 @@ use crate::rules::{
flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_django,
flake8_future_annotations, flake8_gettext, flake8_implicit_str_concat, flake8_logging,
flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self,
flake8_simplify, flake8_tidy_imports, flake8_trio, flake8_type_checking, flake8_use_pathlib,
flynt, numpy, pandas_vet, pep8_naming, pycodestyle, pyflakes, pylint, pyupgrade, refurb, ruff,
flake8_simplify, flake8_tidy_imports, flake8_type_checking, flake8_use_pathlib, flynt, numpy,
pandas_vet, pep8_naming, pycodestyle, pyflakes, pylint, pyupgrade, refurb, ruff,
};
use crate::settings::types::PythonVersion;
@ -505,11 +505,18 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::BlockingHttpCallInAsyncFunction) {
flake8_async::rules::blocking_http_call(checker, call);
}
if checker.enabled(Rule::OpenSleepOrSubprocessInAsyncFunction) {
flake8_async::rules::open_sleep_or_subprocess_call(checker, call);
if checker.enabled(Rule::BlockingOpenCallInAsyncFunction) {
flake8_async::rules::blocking_open_call(checker, call);
}
if checker.enabled(Rule::BlockingOsCallInAsyncFunction) {
flake8_async::rules::blocking_os_call(checker, call);
if checker.any_enabled(&[
Rule::CreateSubprocessInAsyncFunction,
Rule::RunProcessInAsyncFunction,
Rule::WaitForProcessInAsyncFunction,
]) {
flake8_async::rules::blocking_process_invocation(checker, call);
}
if checker.enabled(Rule::BlockingSleepInAsyncFunction) {
flake8_async::rules::blocking_sleep(checker, call);
}
if checker.enabled(Rule::SleepForeverCall) {
flake8_async::rules::sleep_forever_call(checker, call);
@ -963,10 +970,10 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
refurb::rules::no_implicit_cwd(checker, call);
}
if checker.enabled(Rule::TrioSyncCall) {
flake8_trio::rules::sync_call(checker, call);
flake8_async::rules::sync_call(checker, call);
}
if checker.enabled(Rule::TrioZeroSleepCall) {
flake8_trio::rules::zero_sleep_call(checker, call);
flake8_async::rules::zero_sleep_call(checker, call);
}
if checker.enabled(Rule::UnnecessaryDunderCall) {
pylint::rules::unnecessary_dunder_call(checker, call);

View file

@ -8,11 +8,11 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::registry::Rule;
use crate::rules::{
airflow, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_debugger,
flake8_django, flake8_errmsg, flake8_import_conventions, flake8_pie, flake8_pyi,
flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_slots,
flake8_tidy_imports, flake8_trio, flake8_type_checking, mccabe, pandas_vet, pep8_naming,
perflint, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
airflow, flake8_async, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins,
flake8_debugger, flake8_django, flake8_errmsg, flake8_import_conventions, flake8_pie,
flake8_pyi, flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_slots,
flake8_tidy_imports, flake8_type_checking, mccabe, pandas_vet, pep8_naming, perflint,
pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
};
use crate::settings::types::PythonVersion;
@ -357,7 +357,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
if checker.enabled(Rule::TrioAsyncFunctionWithTimeout) {
flake8_trio::rules::async_function_with_timeout(checker, function_def);
flake8_async::rules::async_function_with_timeout(checker, function_def);
}
if checker.enabled(Rule::ReimplementedOperator) {
refurb::rules::reimplemented_operator(checker, &function_def.into());
@ -1303,7 +1303,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pylint::rules::useless_with_lock(checker, with_stmt);
}
if checker.enabled(Rule::TrioTimeoutWithoutAwait) {
flake8_trio::rules::timeout_without_await(checker, with_stmt, items);
flake8_async::rules::timeout_without_await(checker, with_stmt, items);
}
}
Stmt::While(while_stmt @ ast::StmtWhile { body, orelse, .. }) => {
@ -1320,7 +1320,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
perflint::rules::try_except_in_loop(checker, body);
}
if checker.enabled(Rule::TrioUnneededSleep) {
flake8_trio::rules::unneeded_sleep(checker, while_stmt);
flake8_async::rules::unneeded_sleep(checker, while_stmt);
}
}
Stmt::For(

View file

@ -292,17 +292,18 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "W3301") => (RuleGroup::Stable, rules::pylint::rules::NestedMinMax),
// flake8-async
(Flake8Async, "100") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingHttpCallInAsyncFunction),
(Flake8Async, "101") => (RuleGroup::Stable, rules::flake8_async::rules::OpenSleepOrSubprocessInAsyncFunction),
(Flake8Async, "102") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingOsCallInAsyncFunction),
(Flake8Async, "100") => (RuleGroup::Stable, rules::flake8_async::rules::TrioTimeoutWithoutAwait),
(Flake8Async, "105") => (RuleGroup::Stable, rules::flake8_async::rules::TrioSyncCall),
(Flake8Async, "109") => (RuleGroup::Stable, rules::flake8_async::rules::TrioAsyncFunctionWithTimeout),
(Flake8Async, "110") => (RuleGroup::Stable, rules::flake8_async::rules::TrioUnneededSleep),
(Flake8Async, "115") => (RuleGroup::Stable, rules::flake8_async::rules::TrioZeroSleepCall),
(Flake8Async, "116") => (RuleGroup::Preview, rules::flake8_async::rules::SleepForeverCall),
// flake8-trio
(Flake8Trio, "100") => (RuleGroup::Stable, rules::flake8_trio::rules::TrioTimeoutWithoutAwait),
(Flake8Trio, "105") => (RuleGroup::Stable, rules::flake8_trio::rules::TrioSyncCall),
(Flake8Trio, "109") => (RuleGroup::Stable, rules::flake8_trio::rules::TrioAsyncFunctionWithTimeout),
(Flake8Trio, "110") => (RuleGroup::Stable, rules::flake8_trio::rules::TrioUnneededSleep),
(Flake8Trio, "115") => (RuleGroup::Stable, rules::flake8_trio::rules::TrioZeroSleepCall),
(Flake8Async, "210") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingHttpCallInAsyncFunction),
(Flake8Async, "220") => (RuleGroup::Stable, rules::flake8_async::rules::CreateSubprocessInAsyncFunction),
(Flake8Async, "221") => (RuleGroup::Stable, rules::flake8_async::rules::RunProcessInAsyncFunction),
(Flake8Async, "222") => (RuleGroup::Stable, rules::flake8_async::rules::WaitForProcessInAsyncFunction),
(Flake8Async, "230") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingOpenCallInAsyncFunction),
(Flake8Async, "251") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingSleepInAsyncFunction),
// flake8-builtins
(Flake8Builtins, "001") => (RuleGroup::Stable, rules::flake8_builtins::rules::BuiltinVariableShadowing),

View file

@ -64,9 +64,6 @@ pub enum Linter {
/// [flake8-async](https://pypi.org/project/flake8-async/)
#[prefix = "ASYNC"]
Flake8Async,
/// [flake8-trio](https://pypi.org/project/flake8-trio/)
#[prefix = "TRIO"]
Flake8Trio,
/// [flake8-bandit](https://pypi.org/project/flake8-bandit/)
#[prefix = "S"]
Flake8Bandit,

View file

@ -103,6 +103,16 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("TRY200", "B904"),
("PGH001", "S307"),
("PGH002", "G010"),
// flake8-trio and flake8-async merged with name flake8-async
("TRIO", "ASYNC1"),
("TRIO1", "ASYNC1"),
("TRIO10", "ASYNC10"),
("TRIO100", "ASYNC100"),
("TRIO105", "ASYNC105"),
("TRIO109", "ASYNC109"),
("TRIO11", "ASYNC11"),
("TRIO110", "ASYNC110"),
("TRIO115", "ASYNC115"),
// Removed in v0.5
("PLR1701", "SIM101"),
// Test redirect by exact code

View file

@ -1,4 +1,5 @@
//! Rules from [flake8-async](https://pypi.org/project/flake8-async/).
mod helpers;
pub(crate) mod rules;
#[cfg(test)]
@ -13,10 +14,18 @@ mod tests {
use crate::settings::LinterSettings;
use crate::test::test_path;
#[test_case(Rule::BlockingHttpCallInAsyncFunction, Path::new("ASYNC100.py"))]
#[test_case(Rule::OpenSleepOrSubprocessInAsyncFunction, Path::new("ASYNC101.py"))]
#[test_case(Rule::BlockingOsCallInAsyncFunction, Path::new("ASYNC102.py"))]
#[test_case(Rule::TrioTimeoutWithoutAwait, Path::new("ASYNC100.py"))]
#[test_case(Rule::TrioSyncCall, Path::new("ASYNC105.py"))]
#[test_case(Rule::TrioAsyncFunctionWithTimeout, Path::new("ASYNC109.py"))]
#[test_case(Rule::TrioUnneededSleep, Path::new("ASYNC110.py"))]
#[test_case(Rule::TrioZeroSleepCall, Path::new("ASYNC115.py"))]
#[test_case(Rule::SleepForeverCall, Path::new("ASYNC116.py"))]
#[test_case(Rule::BlockingHttpCallInAsyncFunction, Path::new("ASYNC210.py"))]
#[test_case(Rule::CreateSubprocessInAsyncFunction, Path::new("ASYNC22x.py"))]
#[test_case(Rule::RunProcessInAsyncFunction, Path::new("ASYNC22x.py"))]
#[test_case(Rule::WaitForProcessInAsyncFunction, Path::new("ASYNC22x.py"))]
#[test_case(Rule::BlockingOpenCallInAsyncFunction, Path::new("ASYNC230.py"))]
#[test_case(Rule::BlockingSleepInAsyncFunction, Path::new("ASYNC251.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(

View file

@ -40,7 +40,7 @@ impl Violation for TrioAsyncFunctionWithTimeout {
}
}
/// TRIO109
/// ASYNC109
pub(crate) fn async_function_with_timeout(
checker: &mut Checker,
function_def: &ast::StmtFunctionDef,

View file

@ -45,6 +45,7 @@ fn is_blocking_http_call(qualified_name: &QualifiedName) -> bool {
matches!(
qualified_name.segments(),
["urllib", "request", "urlopen"]
| ["urllib3", "request"]
| [
"httpx" | "requests",
"get"
@ -60,7 +61,7 @@ fn is_blocking_http_call(qualified_name: &QualifiedName) -> bool {
)
}
/// ASYNC100
/// ASYNC210
pub(crate) fn blocking_http_call(checker: &mut Checker, call: &ExprCall) {
if checker.semantic().in_async_context() {
if checker

View file

@ -7,8 +7,7 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks that async functions do not contain calls to `open`, `time.sleep`,
/// or `subprocess` methods.
/// Checks that async functions do not open files with blocking methods like `open`.
///
/// ## Why is this bad?
/// Blocking an async function via a blocking call will block the entire
@ -21,61 +20,53 @@ use crate::checkers::ast::Checker;
/// ## Example
/// ```python
/// async def foo():
/// time.sleep(1000)
/// with open("bar.txt") as f:
/// contents = f.read()
/// ```
///
/// Use instead:
/// ```python
/// import anyio
///
///
/// async def foo():
/// await asyncio.sleep(1000)
/// async with await anyio.open_file("bar.txt") as f:
/// contents = await f.read()
/// ```
#[violation]
pub struct OpenSleepOrSubprocessInAsyncFunction;
pub struct BlockingOpenCallInAsyncFunction;
impl Violation for OpenSleepOrSubprocessInAsyncFunction {
impl Violation for BlockingOpenCallInAsyncFunction {
#[derive_message_formats]
fn message(&self) -> String {
format!("Async functions should not call `open`, `time.sleep`, or `subprocess` methods")
format!("Async functions should not open files with blocking methods like `open`")
}
}
/// ASYNC101
pub(crate) fn open_sleep_or_subprocess_call(checker: &mut Checker, call: &ast::ExprCall) {
/// ASYNC230
pub(crate) fn blocking_open_call(checker: &mut Checker, call: &ast::ExprCall) {
if !checker.semantic().in_async_context() {
return;
}
if is_open_sleep_or_subprocess_call(&call.func, checker.semantic())
if is_open_call(&call.func, checker.semantic())
|| is_open_call_from_pathlib(call.func.as_ref(), checker.semantic())
{
checker.diagnostics.push(Diagnostic::new(
OpenSleepOrSubprocessInAsyncFunction,
BlockingOpenCallInAsyncFunction,
call.func.range(),
));
}
}
/// Returns `true` if the expression resolves to a blocking call, like `time.sleep` or
/// `subprocess.run`.
fn is_open_sleep_or_subprocess_call(func: &Expr, semantic: &SemanticModel) -> bool {
/// Returns `true` if the expression resolves to a blocking open call, like `open` or `Path().open()`.
fn is_open_call(func: &Expr, semantic: &SemanticModel) -> bool {
semantic
.resolve_qualified_name(func)
.is_some_and(|qualified_name| {
matches!(
qualified_name.segments(),
["" | "builtins", "open"]
| ["time", "sleep"]
| [
"subprocess",
"run"
| "Popen"
| "call"
| "check_call"
| "check_output"
| "getoutput"
| "getstatusoutput"
]
| ["os", "wait" | "wait3" | "wait4" | "waitid" | "waitpid"]
["" | "io", "open"] | ["io", "open_code"]
)
})
}

View file

@ -1,82 +0,0 @@
use ruff_python_ast::ExprCall;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::QualifiedName;
use ruff_python_semantic::Modules;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks that async functions do not contain calls to blocking synchronous
/// process calls via the `os` module.
///
/// ## Why is this bad?
/// Blocking an async function via a blocking call will block the entire
/// event loop, preventing it from executing other tasks while waiting for the
/// call to complete, negating the benefits of asynchronous programming.
///
/// Instead of making a blocking call, use an equivalent asynchronous library
/// or function.
///
/// ## Example
/// ```python
/// async def foo():
/// os.popen()
/// ```
///
/// Use instead:
/// ```python
/// def foo():
/// os.popen()
/// ```
#[violation]
pub struct BlockingOsCallInAsyncFunction;
impl Violation for BlockingOsCallInAsyncFunction {
#[derive_message_formats]
fn message(&self) -> String {
format!("Async functions should not call synchronous `os` methods")
}
}
/// ASYNC102
pub(crate) fn blocking_os_call(checker: &mut Checker, call: &ExprCall) {
if checker.semantic().seen_module(Modules::OS) {
if checker.semantic().in_async_context() {
if checker
.semantic()
.resolve_qualified_name(call.func.as_ref())
.as_ref()
.is_some_and(is_unsafe_os_method)
{
checker.diagnostics.push(Diagnostic::new(
BlockingOsCallInAsyncFunction,
call.func.range(),
));
}
}
}
}
fn is_unsafe_os_method(qualified_name: &QualifiedName) -> bool {
matches!(
qualified_name.segments(),
[
"os",
"popen"
| "posix_spawn"
| "posix_spawnp"
| "spawnl"
| "spawnle"
| "spawnlp"
| "spawnlpe"
| "spawnv"
| "spawnve"
| "spawnvp"
| "spawnvpe"
| "system"
]
)
}

View file

@ -0,0 +1,166 @@
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr};
use ruff_python_semantic::analyze::typing::find_assigned_value;
use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks that async functions do not create subprocesses with blocking methods.
///
/// ## Why is this bad?
/// Blocking an async function via a blocking call will block the entire
/// event loop, preventing it from executing other tasks while waiting for the
/// call to complete, negating the benefits of asynchronous programming.
///
/// Instead of making a blocking call, use an equivalent asynchronous library
/// or function.
///
/// ## Example
/// ```python
/// async def foo():
/// os.popen(cmd)
/// ```
///
/// Use instead:
/// ```python
/// async def foo():
/// asyncio.create_subprocess_shell(cmd)
/// ```
#[violation]
pub struct CreateSubprocessInAsyncFunction;
impl Violation for CreateSubprocessInAsyncFunction {
#[derive_message_formats]
fn message(&self) -> String {
format!("Async functions should not create subprocesses with blocking methods")
}
}
/// ## What it does
/// Checks that async functions do not run processes with blocking methods.
///
/// ## Why is this bad?
/// Blocking an async function via a blocking call will block the entire
/// event loop, preventing it from executing other tasks while waiting for the
/// call to complete, negating the benefits of asynchronous programming.
///
/// Instead of making a blocking call, use an equivalent asynchronous library
/// or function.
///
/// ## Example
/// ```python
/// async def foo():
/// subprocess.run(cmd)
/// ```
///
/// Use instead:
/// ```python
/// async def foo():
/// asyncio.create_subprocess_shell(cmd)
/// ```
#[violation]
pub struct RunProcessInAsyncFunction;
impl Violation for RunProcessInAsyncFunction {
#[derive_message_formats]
fn message(&self) -> String {
format!("Async functions should not run processes with blocking methods")
}
}
/// ## What it does
/// Checks that async functions do not wait on processes with blocking methods.
///
/// ## Why is this bad?
/// Blocking an async function via a blocking call will block the entire
/// event loop, preventing it from executing other tasks while waiting for the
/// call to complete, negating the benefits of asynchronous programming.
///
/// Instead of making a blocking call, use an equivalent asynchronous library
/// or function.
///
/// ## Example
/// ```python
/// async def foo():
/// os.waitpid(0)
/// ```
///
/// Use instead:
/// ```python
/// def wait_for_process():
/// os.waitpid(0)
///
///
/// async def foo():
/// await asyncio.loop.run_in_executor(None, wait_for_process)
/// ```
#[violation]
pub struct WaitForProcessInAsyncFunction;
impl Violation for WaitForProcessInAsyncFunction {
#[derive_message_formats]
fn message(&self) -> String {
format!("Async functions should not wait on processes with blocking methods")
}
}
/// ASYNC220, ASYNC221, ASYNC222
pub(crate) fn blocking_process_invocation(checker: &mut Checker, call: &ast::ExprCall) {
if !checker.semantic().in_async_context() {
return;
}
let Some(diagnostic_kind) =
checker
.semantic()
.resolve_qualified_name(call.func.as_ref())
.and_then(|qualified_name| match qualified_name.segments() {
["subprocess", "Popen"] | ["os", "popen"] => {
Some(CreateSubprocessInAsyncFunction.into())
}
["os", "system" | "posix_spawn" | "posix_spawnp"]
| ["subprocess", "run" | "call" | "check_call" | "check_output" | "getoutput"
| "getstatusoutput"] => Some(RunProcessInAsyncFunction.into()),
["os", "wait" | "wait3" | "wait4" | "waitid" | "waitpid"] => {
Some(WaitForProcessInAsyncFunction.into())
}
["os", "spawnl" | "spawnle" | "spawnlp" | "spawnlpe" | "spawnv" | "spawnve"
| "spawnvp" | "spawnvpe"] => {
if is_p_wait(call, checker.semantic()) {
Some(RunProcessInAsyncFunction.into())
} else {
Some(CreateSubprocessInAsyncFunction.into())
}
}
_ => None,
})
else {
return;
};
let diagnostic = Diagnostic::new::<DiagnosticKind>(diagnostic_kind, call.func.range());
if checker.enabled(diagnostic.kind.rule()) {
checker.diagnostics.push(diagnostic);
}
}
fn is_p_wait(call: &ast::ExprCall, semantic: &SemanticModel) -> bool {
let Some(arg) = call.arguments.find_argument("mode", 0) else {
return true;
};
if let Some(qualified_name) = semantic.resolve_qualified_name(arg) {
return matches!(qualified_name.segments(), ["os", "P_WAIT"]);
} else if let Expr::Name(ast::ExprName { id, .. }) = arg {
let Some(value) = find_assigned_value(id, semantic) else {
return false;
};
if let Some(qualified_name) = semantic.resolve_qualified_name(value) {
return matches!(qualified_name.segments(), ["os", "P_WAIT"]);
}
}
false
}

View file

@ -0,0 +1,60 @@
use ruff_python_ast::ExprCall;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::QualifiedName;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks that async functions do not call `time.sleep`.
///
/// ## Why is this bad?
/// Blocking an async function via a `time.sleep` call will block the entire
/// event loop, preventing it from executing other tasks while waiting for the
/// `time.sleep`, negating the benefits of asynchronous programming.
///
/// Instead of `time.sleep`, use `asyncio.sleep`.
///
/// ## Example
/// ```python
/// async def fetch():
/// time.sleep(1)
/// ```
///
/// Use instead:
/// ```python
/// async def fetch():
/// await asyncio.sleep(1)
/// ```
#[violation]
pub struct BlockingSleepInAsyncFunction;
impl Violation for BlockingSleepInAsyncFunction {
#[derive_message_formats]
fn message(&self) -> String {
format!("Async functions should not call `time.sleep`")
}
}
fn is_blocking_sleep(qualified_name: &QualifiedName) -> bool {
matches!(qualified_name.segments(), ["time", "sleep"])
}
/// ASYNC251
pub(crate) fn blocking_sleep(checker: &mut Checker, call: &ExprCall) {
if checker.semantic().in_async_context() {
if checker
.semantic()
.resolve_qualified_name(call.func.as_ref())
.as_ref()
.is_some_and(is_blocking_sleep)
{
checker.diagnostics.push(Diagnostic::new(
BlockingSleepInAsyncFunction,
call.func.range(),
));
}
}
}

View file

@ -1,9 +1,21 @@
pub(crate) use async_function_with_timeout::*;
pub(crate) use blocking_http_call::*;
pub(crate) use blocking_os_call::*;
pub(crate) use open_sleep_or_subprocess_call::*;
pub(crate) use blocking_open_call::*;
pub(crate) use blocking_process_invocation::*;
pub(crate) use blocking_sleep::*;
pub(crate) use sleep_forever_call::*;
pub(crate) use sync_call::*;
pub(crate) use timeout_without_await::*;
pub(crate) use unneeded_sleep::*;
pub(crate) use zero_sleep_call::*;
mod async_function_with_timeout;
mod blocking_http_call;
mod blocking_os_call;
mod open_sleep_or_subprocess_call;
mod blocking_open_call;
mod blocking_process_invocation;
mod blocking_sleep;
mod sleep_forever_call;
mod sync_call;
mod timeout_without_await;
mod unneeded_sleep;
mod zero_sleep_call;

View file

@ -6,7 +6,7 @@ use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
use crate::fix::edits::pad;
use crate::rules::flake8_trio::method_name::MethodName;
use crate::rules::flake8_async::helpers::MethodName;
/// ## What it does
/// Checks for calls to trio functions that are not immediately awaited.
@ -50,7 +50,7 @@ impl Violation for TrioSyncCall {
}
}
/// TRIO105
/// ASYNC105
pub(crate) fn sync_call(checker: &mut Checker, call: &ExprCall) {
if !checker.semantic().seen_module(Modules::TRIO) {
return;

View file

@ -6,7 +6,7 @@ use ruff_python_ast::{StmtWith, WithItem};
use ruff_python_semantic::Modules;
use crate::checkers::ast::Checker;
use crate::rules::flake8_trio::method_name::MethodName;
use crate::rules::flake8_async::helpers::MethodName;
/// ## What it does
/// Checks for trio functions that should contain await but don't.
@ -44,7 +44,7 @@ impl Violation for TrioTimeoutWithoutAwait {
}
}
/// TRIO100
/// ASYNC100
pub(crate) fn timeout_without_await(
checker: &mut Checker,
with_stmt: &StmtWith,

View file

@ -41,7 +41,7 @@ impl Violation for TrioUnneededSleep {
}
}
/// TRIO110
/// ASYNC110
pub(crate) fn unneeded_sleep(checker: &mut Checker, while_stmt: &ast::StmtWhile) {
if !checker.semantic().seen_module(Modules::TRIO) {
return;

View file

@ -45,7 +45,7 @@ impl AlwaysFixableViolation for TrioZeroSleepCall {
}
}
/// TRIO115
/// ASYNC115
pub(crate) fn zero_sleep_call(checker: &mut Checker, call: &ExprCall) {
if !checker.semantic().seen_module(Modules::TRIO) {
return;

View file

@ -1,39 +1,20 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC100.py:7:5: ASYNC100 Async functions should not call blocking HTTP methods
ASYNC100.py:5:5: ASYNC100 A `with trio.fail_after(...):` context does not contain any `await` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint.
|
6 | async def foo():
7 | urllib.request.urlopen("http://example.com/foo/bar").read()
| ^^^^^^^^^^^^^^^^^^^^^^ ASYNC100
4 | async def func():
5 | with trio.fail_after():
| _____^
6 | | ...
| |___________^ ASYNC100
|
ASYNC100.py:11:5: ASYNC100 Async functions should not call blocking HTTP methods
ASYNC100.py:15:5: ASYNC100 A `with trio.move_on_after(...):` context does not contain any `await` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint.
|
10 | async def foo():
11 | requests.get()
| ^^^^^^^^^^^^ ASYNC100
14 | async def func():
15 | with trio.move_on_after():
| _____^
16 | | ...
| |___________^ ASYNC100
|
ASYNC100.py:15:5: ASYNC100 Async functions should not call blocking HTTP methods
|
14 | async def foo():
15 | httpx.get()
| ^^^^^^^^^ ASYNC100
|
ASYNC100.py:19:5: ASYNC100 Async functions should not call blocking HTTP methods
|
18 | async def foo():
19 | requests.post()
| ^^^^^^^^^^^^^ ASYNC100
|
ASYNC100.py:23:5: ASYNC100 Async functions should not call blocking HTTP methods
|
22 | async def foo():
23 | httpx.post()
| ^^^^^^^^^^ ASYNC100
|

View file

@ -1,84 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC101.py:10:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
9 | async def func():
10 | open("foo")
| ^^^^ ASYNC101
|
ASYNC101.py:14:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
13 | async def func():
14 | time.sleep(1)
| ^^^^^^^^^^ ASYNC101
|
ASYNC101.py:18:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
17 | async def func():
18 | subprocess.run("foo")
| ^^^^^^^^^^^^^^ ASYNC101
|
ASYNC101.py:22:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
21 | async def func():
22 | subprocess.call("foo")
| ^^^^^^^^^^^^^^^ ASYNC101
|
ASYNC101.py:30:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
29 | async def func():
30 | os.wait4(10)
| ^^^^^^^^ ASYNC101
|
ASYNC101.py:34:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
33 | async def func():
34 | os.wait(12)
| ^^^^^^^ ASYNC101
|
ASYNC101.py:41:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
40 | async def func():
41 | Path("foo").open() # ASYNC101
| ^^^^^^^^^^^^^^^^ ASYNC101
|
ASYNC101.py:46:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
44 | async def func():
45 | p = Path("foo")
46 | p.open() # ASYNC101
| ^^^^^^ ASYNC101
|
ASYNC101.py:50:10: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
49 | async def func():
50 | with Path("foo").open() as f: # ASYNC101
| ^^^^^^^^^^^^^^^^ ASYNC101
51 | pass
|
ASYNC101.py:58:9: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
57 | async def bar():
58 | p.open() # ASYNC101
| ^^^^^^ ASYNC101
|
ASYNC101.py:64:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
62 | (p1, p2) = (Path("foo"), Path("bar"))
63 |
64 | p1.open() # ASYNC101
| ^^^^^^^ ASYNC101
|

View file

@ -1,18 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC102.py:5:5: ASYNC102 Async functions should not call synchronous `os` methods
|
4 | async def foo():
5 | os.popen()
| ^^^^^^^^ ASYNC102
|
ASYNC102.py:9:5: ASYNC102 Async functions should not call synchronous `os` methods
|
8 | async def foo():
9 | os.spawnl()
| ^^^^^^^^^ ASYNC102
|

View file

@ -1,11 +1,11 @@
---
source: crates/ruff_linter/src/rules/flake8_trio/mod.rs
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
TRIO105.py:30:5: TRIO105 [*] Call to `trio.aclose_forcefully` is not immediately awaited
ASYNC105.py:30:5: ASYNC105 [*] Call to `trio.aclose_forcefully` is not immediately awaited
|
29 | # TRIO105
29 | # ASYNC105
30 | trio.aclose_forcefully(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
31 | trio.open_file(foo)
32 | trio.open_ssl_over_tcp_listeners(foo, foo)
|
@ -14,19 +14,19 @@ TRIO105.py:30:5: TRIO105 [*] Call to `trio.aclose_forcefully` is not immediately
Unsafe fix
27 27 | await trio.lowlevel.wait_writable(foo)
28 28 |
29 29 | # TRIO105
29 29 | # ASYNC105
30 |- trio.aclose_forcefully(foo)
30 |+ await trio.aclose_forcefully(foo)
31 31 | trio.open_file(foo)
32 32 | trio.open_ssl_over_tcp_listeners(foo, foo)
33 33 | trio.open_ssl_over_tcp_stream(foo, foo)
TRIO105.py:31:5: TRIO105 [*] Call to `trio.open_file` is not immediately awaited
ASYNC105.py:31:5: ASYNC105 [*] Call to `trio.open_file` is not immediately awaited
|
29 | # TRIO105
29 | # ASYNC105
30 | trio.aclose_forcefully(foo)
31 | trio.open_file(foo)
| ^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^ ASYNC105
32 | trio.open_ssl_over_tcp_listeners(foo, foo)
33 | trio.open_ssl_over_tcp_stream(foo, foo)
|
@ -34,7 +34,7 @@ TRIO105.py:31:5: TRIO105 [*] Call to `trio.open_file` is not immediately awaited
Unsafe fix
28 28 |
29 29 | # TRIO105
29 29 | # ASYNC105
30 30 | trio.aclose_forcefully(foo)
31 |- trio.open_file(foo)
31 |+ await trio.open_file(foo)
@ -42,19 +42,19 @@ TRIO105.py:31:5: TRIO105 [*] Call to `trio.open_file` is not immediately awaited
33 33 | trio.open_ssl_over_tcp_stream(foo, foo)
34 34 | trio.open_tcp_listeners(foo)
TRIO105.py:32:5: TRIO105 [*] Call to `trio.open_ssl_over_tcp_listeners` is not immediately awaited
ASYNC105.py:32:5: ASYNC105 [*] Call to `trio.open_ssl_over_tcp_listeners` is not immediately awaited
|
30 | trio.aclose_forcefully(foo)
31 | trio.open_file(foo)
32 | trio.open_ssl_over_tcp_listeners(foo, foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
33 | trio.open_ssl_over_tcp_stream(foo, foo)
34 | trio.open_tcp_listeners(foo)
|
= help: Add `await`
Unsafe fix
29 29 | # TRIO105
29 29 | # ASYNC105
30 30 | trio.aclose_forcefully(foo)
31 31 | trio.open_file(foo)
32 |- trio.open_ssl_over_tcp_listeners(foo, foo)
@ -63,12 +63,12 @@ TRIO105.py:32:5: TRIO105 [*] Call to `trio.open_ssl_over_tcp_listeners` is not i
34 34 | trio.open_tcp_listeners(foo)
35 35 | trio.open_tcp_stream(foo, foo)
TRIO105.py:33:5: TRIO105 [*] Call to `trio.open_ssl_over_tcp_stream` is not immediately awaited
ASYNC105.py:33:5: ASYNC105 [*] Call to `trio.open_ssl_over_tcp_stream` is not immediately awaited
|
31 | trio.open_file(foo)
32 | trio.open_ssl_over_tcp_listeners(foo, foo)
33 | trio.open_ssl_over_tcp_stream(foo, foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
34 | trio.open_tcp_listeners(foo)
35 | trio.open_tcp_stream(foo, foo)
|
@ -84,12 +84,12 @@ TRIO105.py:33:5: TRIO105 [*] Call to `trio.open_ssl_over_tcp_stream` is not imme
35 35 | trio.open_tcp_stream(foo, foo)
36 36 | trio.open_unix_socket(foo)
TRIO105.py:34:5: TRIO105 [*] Call to `trio.open_tcp_listeners` is not immediately awaited
ASYNC105.py:34:5: ASYNC105 [*] Call to `trio.open_tcp_listeners` is not immediately awaited
|
32 | trio.open_ssl_over_tcp_listeners(foo, foo)
33 | trio.open_ssl_over_tcp_stream(foo, foo)
34 | trio.open_tcp_listeners(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
35 | trio.open_tcp_stream(foo, foo)
36 | trio.open_unix_socket(foo)
|
@ -105,12 +105,12 @@ TRIO105.py:34:5: TRIO105 [*] Call to `trio.open_tcp_listeners` is not immediatel
36 36 | trio.open_unix_socket(foo)
37 37 | trio.run_process(foo)
TRIO105.py:35:5: TRIO105 [*] Call to `trio.open_tcp_stream` is not immediately awaited
ASYNC105.py:35:5: ASYNC105 [*] Call to `trio.open_tcp_stream` is not immediately awaited
|
33 | trio.open_ssl_over_tcp_stream(foo, foo)
34 | trio.open_tcp_listeners(foo)
35 | trio.open_tcp_stream(foo, foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
36 | trio.open_unix_socket(foo)
37 | trio.run_process(foo)
|
@ -126,12 +126,12 @@ TRIO105.py:35:5: TRIO105 [*] Call to `trio.open_tcp_stream` is not immediately a
37 37 | trio.run_process(foo)
38 38 | trio.serve_listeners(foo, foo)
TRIO105.py:36:5: TRIO105 [*] Call to `trio.open_unix_socket` is not immediately awaited
ASYNC105.py:36:5: ASYNC105 [*] Call to `trio.open_unix_socket` is not immediately awaited
|
34 | trio.open_tcp_listeners(foo)
35 | trio.open_tcp_stream(foo, foo)
36 | trio.open_unix_socket(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
37 | trio.run_process(foo)
38 | trio.serve_listeners(foo, foo)
|
@ -147,12 +147,12 @@ TRIO105.py:36:5: TRIO105 [*] Call to `trio.open_unix_socket` is not immediately
38 38 | trio.serve_listeners(foo, foo)
39 39 | trio.serve_ssl_over_tcp(foo, foo, foo)
TRIO105.py:37:5: TRIO105 [*] Call to `trio.run_process` is not immediately awaited
ASYNC105.py:37:5: ASYNC105 [*] Call to `trio.run_process` is not immediately awaited
|
35 | trio.open_tcp_stream(foo, foo)
36 | trio.open_unix_socket(foo)
37 | trio.run_process(foo)
| ^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^ ASYNC105
38 | trio.serve_listeners(foo, foo)
39 | trio.serve_ssl_over_tcp(foo, foo, foo)
|
@ -168,12 +168,12 @@ TRIO105.py:37:5: TRIO105 [*] Call to `trio.run_process` is not immediately await
39 39 | trio.serve_ssl_over_tcp(foo, foo, foo)
40 40 | trio.serve_tcp(foo, foo)
TRIO105.py:38:5: TRIO105 [*] Call to `trio.serve_listeners` is not immediately awaited
ASYNC105.py:38:5: ASYNC105 [*] Call to `trio.serve_listeners` is not immediately awaited
|
36 | trio.open_unix_socket(foo)
37 | trio.run_process(foo)
38 | trio.serve_listeners(foo, foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
39 | trio.serve_ssl_over_tcp(foo, foo, foo)
40 | trio.serve_tcp(foo, foo)
|
@ -189,12 +189,12 @@ TRIO105.py:38:5: TRIO105 [*] Call to `trio.serve_listeners` is not immediately a
40 40 | trio.serve_tcp(foo, foo)
41 41 | trio.sleep(foo)
TRIO105.py:39:5: TRIO105 [*] Call to `trio.serve_ssl_over_tcp` is not immediately awaited
ASYNC105.py:39:5: ASYNC105 [*] Call to `trio.serve_ssl_over_tcp` is not immediately awaited
|
37 | trio.run_process(foo)
38 | trio.serve_listeners(foo, foo)
39 | trio.serve_ssl_over_tcp(foo, foo, foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
40 | trio.serve_tcp(foo, foo)
41 | trio.sleep(foo)
|
@ -210,12 +210,12 @@ TRIO105.py:39:5: TRIO105 [*] Call to `trio.serve_ssl_over_tcp` is not immediatel
41 41 | trio.sleep(foo)
42 42 | trio.sleep_forever()
TRIO105.py:40:5: TRIO105 [*] Call to `trio.serve_tcp` is not immediately awaited
ASYNC105.py:40:5: ASYNC105 [*] Call to `trio.serve_tcp` is not immediately awaited
|
38 | trio.serve_listeners(foo, foo)
39 | trio.serve_ssl_over_tcp(foo, foo, foo)
40 | trio.serve_tcp(foo, foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
41 | trio.sleep(foo)
42 | trio.sleep_forever()
|
@ -231,12 +231,12 @@ TRIO105.py:40:5: TRIO105 [*] Call to `trio.serve_tcp` is not immediately awaited
42 42 | trio.sleep_forever()
43 43 | trio.sleep_until(foo)
TRIO105.py:41:5: TRIO105 [*] Call to `trio.sleep` is not immediately awaited
ASYNC105.py:41:5: ASYNC105 [*] Call to `trio.sleep` is not immediately awaited
|
39 | trio.serve_ssl_over_tcp(foo, foo, foo)
40 | trio.serve_tcp(foo, foo)
41 | trio.sleep(foo)
| ^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^ ASYNC105
42 | trio.sleep_forever()
43 | trio.sleep_until(foo)
|
@ -252,12 +252,12 @@ TRIO105.py:41:5: TRIO105 [*] Call to `trio.sleep` is not immediately awaited
43 43 | trio.sleep_until(foo)
44 44 | trio.lowlevel.cancel_shielded_checkpoint()
TRIO105.py:42:5: TRIO105 [*] Call to `trio.sleep_forever` is not immediately awaited
ASYNC105.py:42:5: ASYNC105 [*] Call to `trio.sleep_forever` is not immediately awaited
|
40 | trio.serve_tcp(foo, foo)
41 | trio.sleep(foo)
42 | trio.sleep_forever()
| ^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^ ASYNC105
43 | trio.sleep_until(foo)
44 | trio.lowlevel.cancel_shielded_checkpoint()
|
@ -273,12 +273,12 @@ TRIO105.py:42:5: TRIO105 [*] Call to `trio.sleep_forever` is not immediately awa
44 44 | trio.lowlevel.cancel_shielded_checkpoint()
45 45 | trio.lowlevel.checkpoint()
TRIO105.py:44:5: TRIO105 [*] Call to `trio.lowlevel.cancel_shielded_checkpoint` is not immediately awaited
ASYNC105.py:44:5: ASYNC105 [*] Call to `trio.lowlevel.cancel_shielded_checkpoint` is not immediately awaited
|
42 | trio.sleep_forever()
43 | trio.sleep_until(foo)
44 | trio.lowlevel.cancel_shielded_checkpoint()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
45 | trio.lowlevel.checkpoint()
46 | trio.lowlevel.checkpoint_if_cancelled()
|
@ -294,12 +294,12 @@ TRIO105.py:44:5: TRIO105 [*] Call to `trio.lowlevel.cancel_shielded_checkpoint`
46 46 | trio.lowlevel.checkpoint_if_cancelled()
47 47 | trio.lowlevel.open_process()
TRIO105.py:45:5: TRIO105 [*] Call to `trio.lowlevel.checkpoint` is not immediately awaited
ASYNC105.py:45:5: ASYNC105 [*] Call to `trio.lowlevel.checkpoint` is not immediately awaited
|
43 | trio.sleep_until(foo)
44 | trio.lowlevel.cancel_shielded_checkpoint()
45 | trio.lowlevel.checkpoint()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
46 | trio.lowlevel.checkpoint_if_cancelled()
47 | trio.lowlevel.open_process()
|
@ -315,12 +315,12 @@ TRIO105.py:45:5: TRIO105 [*] Call to `trio.lowlevel.checkpoint` is not immediate
47 47 | trio.lowlevel.open_process()
48 48 | trio.lowlevel.permanently_detach_coroutine_object(foo)
TRIO105.py:46:5: TRIO105 [*] Call to `trio.lowlevel.checkpoint_if_cancelled` is not immediately awaited
ASYNC105.py:46:5: ASYNC105 [*] Call to `trio.lowlevel.checkpoint_if_cancelled` is not immediately awaited
|
44 | trio.lowlevel.cancel_shielded_checkpoint()
45 | trio.lowlevel.checkpoint()
46 | trio.lowlevel.checkpoint_if_cancelled()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
47 | trio.lowlevel.open_process()
48 | trio.lowlevel.permanently_detach_coroutine_object(foo)
|
@ -336,12 +336,12 @@ TRIO105.py:46:5: TRIO105 [*] Call to `trio.lowlevel.checkpoint_if_cancelled` is
48 48 | trio.lowlevel.permanently_detach_coroutine_object(foo)
49 49 | trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
TRIO105.py:47:5: TRIO105 [*] Call to `trio.lowlevel.open_process` is not immediately awaited
ASYNC105.py:47:5: ASYNC105 [*] Call to `trio.lowlevel.open_process` is not immediately awaited
|
45 | trio.lowlevel.checkpoint()
46 | trio.lowlevel.checkpoint_if_cancelled()
47 | trio.lowlevel.open_process()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
48 | trio.lowlevel.permanently_detach_coroutine_object(foo)
49 | trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
|
@ -357,12 +357,12 @@ TRIO105.py:47:5: TRIO105 [*] Call to `trio.lowlevel.open_process` is not immedia
49 49 | trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
50 50 | trio.lowlevel.temporarily_detach_coroutine_object(foo)
TRIO105.py:48:5: TRIO105 [*] Call to `trio.lowlevel.permanently_detach_coroutine_object` is not immediately awaited
ASYNC105.py:48:5: ASYNC105 [*] Call to `trio.lowlevel.permanently_detach_coroutine_object` is not immediately awaited
|
46 | trio.lowlevel.checkpoint_if_cancelled()
47 | trio.lowlevel.open_process()
48 | trio.lowlevel.permanently_detach_coroutine_object(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
49 | trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
50 | trio.lowlevel.temporarily_detach_coroutine_object(foo)
|
@ -378,12 +378,12 @@ TRIO105.py:48:5: TRIO105 [*] Call to `trio.lowlevel.permanently_detach_coroutine
50 50 | trio.lowlevel.temporarily_detach_coroutine_object(foo)
51 51 | trio.lowlevel.wait_readable(foo)
TRIO105.py:49:5: TRIO105 [*] Call to `trio.lowlevel.reattach_detached_coroutine_object` is not immediately awaited
ASYNC105.py:49:5: ASYNC105 [*] Call to `trio.lowlevel.reattach_detached_coroutine_object` is not immediately awaited
|
47 | trio.lowlevel.open_process()
48 | trio.lowlevel.permanently_detach_coroutine_object(foo)
49 | trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
50 | trio.lowlevel.temporarily_detach_coroutine_object(foo)
51 | trio.lowlevel.wait_readable(foo)
|
@ -399,12 +399,12 @@ TRIO105.py:49:5: TRIO105 [*] Call to `trio.lowlevel.reattach_detached_coroutine_
51 51 | trio.lowlevel.wait_readable(foo)
52 52 | trio.lowlevel.wait_task_rescheduled(foo)
TRIO105.py:50:5: TRIO105 [*] Call to `trio.lowlevel.temporarily_detach_coroutine_object` is not immediately awaited
ASYNC105.py:50:5: ASYNC105 [*] Call to `trio.lowlevel.temporarily_detach_coroutine_object` is not immediately awaited
|
48 | trio.lowlevel.permanently_detach_coroutine_object(foo)
49 | trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
50 | trio.lowlevel.temporarily_detach_coroutine_object(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
51 | trio.lowlevel.wait_readable(foo)
52 | trio.lowlevel.wait_task_rescheduled(foo)
|
@ -420,12 +420,12 @@ TRIO105.py:50:5: TRIO105 [*] Call to `trio.lowlevel.temporarily_detach_coroutine
52 52 | trio.lowlevel.wait_task_rescheduled(foo)
53 53 | trio.lowlevel.wait_writable(foo)
TRIO105.py:51:5: TRIO105 [*] Call to `trio.lowlevel.wait_readable` is not immediately awaited
ASYNC105.py:51:5: ASYNC105 [*] Call to `trio.lowlevel.wait_readable` is not immediately awaited
|
49 | trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
50 | trio.lowlevel.temporarily_detach_coroutine_object(foo)
51 | trio.lowlevel.wait_readable(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
52 | trio.lowlevel.wait_task_rescheduled(foo)
53 | trio.lowlevel.wait_writable(foo)
|
@ -441,12 +441,12 @@ TRIO105.py:51:5: TRIO105 [*] Call to `trio.lowlevel.wait_readable` is not immedi
53 53 | trio.lowlevel.wait_writable(foo)
54 54 |
TRIO105.py:52:5: TRIO105 [*] Call to `trio.lowlevel.wait_task_rescheduled` is not immediately awaited
ASYNC105.py:52:5: ASYNC105 [*] Call to `trio.lowlevel.wait_task_rescheduled` is not immediately awaited
|
50 | trio.lowlevel.temporarily_detach_coroutine_object(foo)
51 | trio.lowlevel.wait_readable(foo)
52 | trio.lowlevel.wait_task_rescheduled(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
53 | trio.lowlevel.wait_writable(foo)
|
= help: Add `await`
@ -461,12 +461,12 @@ TRIO105.py:52:5: TRIO105 [*] Call to `trio.lowlevel.wait_task_rescheduled` is no
54 54 |
55 55 | async with await trio.open_file(foo): # Ok
TRIO105.py:53:5: TRIO105 [*] Call to `trio.lowlevel.wait_writable` is not immediately awaited
ASYNC105.py:53:5: ASYNC105 [*] Call to `trio.lowlevel.wait_writable` is not immediately awaited
|
51 | trio.lowlevel.wait_readable(foo)
52 | trio.lowlevel.wait_task_rescheduled(foo)
53 | trio.lowlevel.wait_writable(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC105
54 |
55 | async with await trio.open_file(foo): # Ok
|
@ -482,12 +482,12 @@ TRIO105.py:53:5: TRIO105 [*] Call to `trio.lowlevel.wait_writable` is not immedi
55 55 | async with await trio.open_file(foo): # Ok
56 56 | pass
TRIO105.py:58:16: TRIO105 [*] Call to `trio.open_file` is not immediately awaited
ASYNC105.py:58:16: ASYNC105 [*] Call to `trio.open_file` is not immediately awaited
|
56 | pass
57 |
58 | async with trio.open_file(foo): # TRIO105
| ^^^^^^^^^^^^^^^^^^^ TRIO105
58 | async with trio.open_file(foo): # ASYNC105
| ^^^^^^^^^^^^^^^^^^^ ASYNC105
59 | pass
|
= help: Add `await`
@ -496,19 +496,17 @@ TRIO105.py:58:16: TRIO105 [*] Call to `trio.open_file` is not immediately awaite
55 55 | async with await trio.open_file(foo): # Ok
56 56 | pass
57 57 |
58 |- async with trio.open_file(foo): # TRIO105
58 |+ async with await trio.open_file(foo): # TRIO105
58 |- async with trio.open_file(foo): # ASYNC105
58 |+ async with await trio.open_file(foo): # ASYNC105
59 59 | pass
60 60 |
61 61 |
TRIO105.py:64:5: TRIO105 Call to `trio.open_file` is not immediately awaited
ASYNC105.py:64:5: ASYNC105 Call to `trio.open_file` is not immediately awaited
|
62 | def func() -> None:
63 | # TRIO105 (without fix)
63 | # ASYNC105 (without fix)
64 | trio.open_file(foo)
| ^^^^^^^^^^^^^^^^^^^ TRIO105
| ^^^^^^^^^^^^^^^^^^^ ASYNC105
|
= help: Add `await`

View file

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

View file

@ -0,0 +1,20 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC110.py:5:5: ASYNC110 Use `trio.Event` instead of awaiting `trio.sleep` in a `while` loop
|
4 | async def func():
5 | while True:
| _____^
6 | | await trio.sleep(10)
| |____________________________^ ASYNC110
|
ASYNC110.py:10:5: ASYNC110 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)
| |__________________________________^ ASYNC110
|

View file

@ -1,12 +1,12 @@
---
source: crates/ruff_linter/src/rules/flake8_trio/mod.rs
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
TRIO115.py:5:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
ASYNC115.py:5:11: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
|
3 | from trio import sleep
4 |
5 | await trio.sleep(0) # TRIO115
| ^^^^^^^^^^^^^ TRIO115
5 | await trio.sleep(0) # ASYNC115
| ^^^^^^^^^^^^^ ASYNC115
6 | await trio.sleep(1) # OK
7 | await trio.sleep(0, 1) # OK
|
@ -16,18 +16,18 @@ TRIO115.py:5:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s
2 2 | import trio
3 3 | from trio import sleep
4 4 |
5 |- await trio.sleep(0) # TRIO115
5 |+ await trio.lowlevel.checkpoint() # TRIO115
5 |- await trio.sleep(0) # ASYNC115
5 |+ await trio.lowlevel.checkpoint() # ASYNC115
6 6 | await trio.sleep(1) # OK
7 7 | await trio.sleep(0, 1) # OK
8 8 | await trio.sleep(...) # OK
TRIO115.py:11:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
ASYNC115.py:11:5: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
|
9 | await trio.sleep() # OK
10 |
11 | trio.sleep(0) # TRIO115
| ^^^^^^^^^^^^^ TRIO115
11 | trio.sleep(0) # ASYNC115
| ^^^^^^^^^^^^^ ASYNC115
12 | foo = 0
13 | trio.sleep(foo) # OK
|
@ -37,18 +37,18 @@ TRIO115.py:11:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s
8 8 | await trio.sleep(...) # OK
9 9 | await trio.sleep() # OK
10 10 |
11 |- trio.sleep(0) # TRIO115
11 |+ trio.lowlevel.checkpoint() # TRIO115
11 |- trio.sleep(0) # ASYNC115
11 |+ trio.lowlevel.checkpoint() # ASYNC115
12 12 | foo = 0
13 13 | trio.sleep(foo) # OK
14 14 | trio.sleep(1) # OK
TRIO115.py:17:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
ASYNC115.py:17:5: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
|
15 | time.sleep(0) # OK
16 |
17 | sleep(0) # TRIO115
| ^^^^^^^^ TRIO115
17 | sleep(0) # ASYNC115
| ^^^^^^^^ ASYNC115
18 |
19 | bar = "bar"
|
@ -58,18 +58,18 @@ TRIO115.py:17:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s
14 14 | trio.sleep(1) # OK
15 15 | time.sleep(0) # OK
16 16 |
17 |- sleep(0) # TRIO115
17 |+ trio.lowlevel.checkpoint() # TRIO115
17 |- sleep(0) # ASYNC115
17 |+ trio.lowlevel.checkpoint() # ASYNC115
18 18 |
19 19 | bar = "bar"
20 20 | trio.sleep(bar)
TRIO115.py:48:14: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
ASYNC115.py:48:14: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
|
46 | import trio
47 |
48 | trio.run(trio.sleep(0)) # TRIO115
| ^^^^^^^^^^^^^ TRIO115
48 | trio.run(trio.sleep(0)) # ASYNC115
| ^^^^^^^^^^^^^ ASYNC115
|
= help: Replace with `trio.lowlevel.checkpoint()`
@ -77,22 +77,22 @@ TRIO115.py:48:14: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.
45 45 | def func():
46 46 | import trio
47 47 |
48 |- trio.run(trio.sleep(0)) # TRIO115
48 |+ trio.run(trio.lowlevel.checkpoint()) # TRIO115
48 |- trio.run(trio.sleep(0)) # ASYNC115
48 |+ trio.run(trio.lowlevel.checkpoint()) # ASYNC115
49 49 |
50 50 |
51 51 | from trio import Event, sleep
TRIO115.py:55:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
ASYNC115.py:55:5: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
|
54 | def func():
55 | sleep(0) # TRIO115
| ^^^^^^^^ TRIO115
55 | sleep(0) # ASYNC115
| ^^^^^^^^ ASYNC115
|
= help: Replace with `trio.lowlevel.checkpoint()`
Safe fix
48 48 | trio.run(trio.sleep(0)) # TRIO115
48 48 | trio.run(trio.sleep(0)) # ASYNC115
49 49 |
50 50 |
51 |-from trio import Event, sleep
@ -100,22 +100,22 @@ TRIO115.py:55:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s
52 52 |
53 53 |
54 54 | def func():
55 |- sleep(0) # TRIO115
55 |+ lowlevel.checkpoint() # TRIO115
55 |- sleep(0) # ASYNC115
55 |+ lowlevel.checkpoint() # ASYNC115
56 56 |
57 57 |
58 58 | async def func():
TRIO115.py:59:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
ASYNC115.py:59:11: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
|
58 | async def func():
59 | await sleep(seconds=0) # TRIO115
| ^^^^^^^^^^^^^^^^ TRIO115
59 | await sleep(seconds=0) # ASYNC115
| ^^^^^^^^^^^^^^^^ ASYNC115
|
= help: Replace with `trio.lowlevel.checkpoint()`
Safe fix
48 48 | trio.run(trio.sleep(0)) # TRIO115
48 48 | trio.run(trio.sleep(0)) # ASYNC115
49 49 |
50 50 |
51 |-from trio import Event, sleep
@ -127,8 +127,8 @@ TRIO115.py:59:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.
56 56 |
57 57 |
58 58 | async def func():
59 |- await sleep(seconds=0) # TRIO115
59 |+ await lowlevel.checkpoint() # TRIO115
59 |- await sleep(seconds=0) # ASYNC115
59 |+ await lowlevel.checkpoint() # ASYNC115
60 60 |
61 61 |
62 62 | def func():

View file

@ -0,0 +1,229 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC210.py:8:5: ASYNC210 Async functions should not call blocking HTTP methods
|
7 | async def foo():
8 | urllib.request.urlopen("http://example.com/foo/bar").read() # ASYNC210
| ^^^^^^^^^^^^^^^^^^^^^^ ASYNC210
|
ASYNC210.py:12:5: ASYNC210 Async functions should not call blocking HTTP methods
|
11 | async def foo():
12 | requests.get() # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
|
ASYNC210.py:16:5: ASYNC210 Async functions should not call blocking HTTP methods
|
15 | async def foo():
16 | httpx.get() # ASYNC210
| ^^^^^^^^^ ASYNC210
|
ASYNC210.py:20:5: ASYNC210 Async functions should not call blocking HTTP methods
|
19 | async def foo():
20 | requests.post() # ASYNC210
| ^^^^^^^^^^^^^ ASYNC210
|
ASYNC210.py:24:5: ASYNC210 Async functions should not call blocking HTTP methods
|
23 | async def foo():
24 | httpx.post() # ASYNC210
| ^^^^^^^^^^ ASYNC210
|
ASYNC210.py:28:5: ASYNC210 Async functions should not call blocking HTTP methods
|
27 | async def foo():
28 | requests.get() # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
29 | requests.get(...) # ASYNC210
30 | requests.get # Ok
|
ASYNC210.py:29:5: ASYNC210 Async functions should not call blocking HTTP methods
|
27 | async def foo():
28 | requests.get() # ASYNC210
29 | requests.get(...) # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
30 | requests.get # Ok
31 | print(requests.get()) # ASYNC210
|
ASYNC210.py:31:11: ASYNC210 Async functions should not call blocking HTTP methods
|
29 | requests.get(...) # ASYNC210
30 | requests.get # Ok
31 | print(requests.get()) # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
32 | print(requests.get(requests.get())) # ASYNC210
|
ASYNC210.py:32:11: ASYNC210 Async functions should not call blocking HTTP methods
|
30 | requests.get # Ok
31 | print(requests.get()) # ASYNC210
32 | print(requests.get(requests.get())) # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
33 |
34 | requests.options() # ASYNC210
|
ASYNC210.py:32:24: ASYNC210 Async functions should not call blocking HTTP methods
|
30 | requests.get # Ok
31 | print(requests.get()) # ASYNC210
32 | print(requests.get(requests.get())) # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
33 |
34 | requests.options() # ASYNC210
|
ASYNC210.py:34:5: ASYNC210 Async functions should not call blocking HTTP methods
|
32 | print(requests.get(requests.get())) # ASYNC210
33 |
34 | requests.options() # ASYNC210
| ^^^^^^^^^^^^^^^^ ASYNC210
35 | requests.head() # ASYNC210
36 | requests.post() # ASYNC210
|
ASYNC210.py:35:5: ASYNC210 Async functions should not call blocking HTTP methods
|
34 | requests.options() # ASYNC210
35 | requests.head() # ASYNC210
| ^^^^^^^^^^^^^ ASYNC210
36 | requests.post() # ASYNC210
37 | requests.put() # ASYNC210
|
ASYNC210.py:36:5: ASYNC210 Async functions should not call blocking HTTP methods
|
34 | requests.options() # ASYNC210
35 | requests.head() # ASYNC210
36 | requests.post() # ASYNC210
| ^^^^^^^^^^^^^ ASYNC210
37 | requests.put() # ASYNC210
38 | requests.patch() # ASYNC210
|
ASYNC210.py:37:5: ASYNC210 Async functions should not call blocking HTTP methods
|
35 | requests.head() # ASYNC210
36 | requests.post() # ASYNC210
37 | requests.put() # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
38 | requests.patch() # ASYNC210
39 | requests.delete() # ASYNC210
|
ASYNC210.py:38:5: ASYNC210 Async functions should not call blocking HTTP methods
|
36 | requests.post() # ASYNC210
37 | requests.put() # ASYNC210
38 | requests.patch() # ASYNC210
| ^^^^^^^^^^^^^^ ASYNC210
39 | requests.delete() # ASYNC210
40 | requests.foo()
|
ASYNC210.py:39:5: ASYNC210 Async functions should not call blocking HTTP methods
|
37 | requests.put() # ASYNC210
38 | requests.patch() # ASYNC210
39 | requests.delete() # ASYNC210
| ^^^^^^^^^^^^^^^ ASYNC210
40 | requests.foo()
|
ASYNC210.py:42:5: ASYNC210 Async functions should not call blocking HTTP methods
|
40 | requests.foo()
41 |
42 | httpx.options("") # ASYNC210
| ^^^^^^^^^^^^^ ASYNC210
43 | httpx.head("") # ASYNC210
44 | httpx.post("") # ASYNC210
|
ASYNC210.py:43:5: ASYNC210 Async functions should not call blocking HTTP methods
|
42 | httpx.options("") # ASYNC210
43 | httpx.head("") # ASYNC210
| ^^^^^^^^^^ ASYNC210
44 | httpx.post("") # ASYNC210
45 | httpx.put("") # ASYNC210
|
ASYNC210.py:44:5: ASYNC210 Async functions should not call blocking HTTP methods
|
42 | httpx.options("") # ASYNC210
43 | httpx.head("") # ASYNC210
44 | httpx.post("") # ASYNC210
| ^^^^^^^^^^ ASYNC210
45 | httpx.put("") # ASYNC210
46 | httpx.patch("") # ASYNC210
|
ASYNC210.py:45:5: ASYNC210 Async functions should not call blocking HTTP methods
|
43 | httpx.head("") # ASYNC210
44 | httpx.post("") # ASYNC210
45 | httpx.put("") # ASYNC210
| ^^^^^^^^^ ASYNC210
46 | httpx.patch("") # ASYNC210
47 | httpx.delete("") # ASYNC210
|
ASYNC210.py:46:5: ASYNC210 Async functions should not call blocking HTTP methods
|
44 | httpx.post("") # ASYNC210
45 | httpx.put("") # ASYNC210
46 | httpx.patch("") # ASYNC210
| ^^^^^^^^^^^ ASYNC210
47 | httpx.delete("") # ASYNC210
48 | httpx.foo() # Ok
|
ASYNC210.py:47:5: ASYNC210 Async functions should not call blocking HTTP methods
|
45 | httpx.put("") # ASYNC210
46 | httpx.patch("") # ASYNC210
47 | httpx.delete("") # ASYNC210
| ^^^^^^^^^^^^ ASYNC210
48 | httpx.foo() # Ok
|
ASYNC210.py:50:5: ASYNC210 Async functions should not call blocking HTTP methods
|
48 | httpx.foo() # Ok
49 |
50 | urllib3.request() # ASYNC210
| ^^^^^^^^^^^^^^^ ASYNC210
51 | urllib3.request(...) # ASYNC210
|
ASYNC210.py:51:5: ASYNC210 Async functions should not call blocking HTTP methods
|
50 | urllib3.request() # ASYNC210
51 | urllib3.request(...) # ASYNC210
| ^^^^^^^^^^^^^^^ ASYNC210
52 |
53 | urllib.request.urlopen("") # ASYNC210
|
ASYNC210.py:53:5: ASYNC210 Async functions should not call blocking HTTP methods
|
51 | urllib3.request(...) # ASYNC210
52 |
53 | urllib.request.urlopen("") # ASYNC210
| ^^^^^^^^^^^^^^^^^^^^^^ ASYNC210
54 |
55 | r = {}
|

View file

@ -0,0 +1,77 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC22x.py:31:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
29 | subprocess.getoutput() # ASYNC221
30 | )
31 | subprocess.Popen() # ASYNC220
| ^^^^^^^^^^^^^^^^ ASYNC220
32 | os.system() # ASYNC221
|
ASYNC22x.py:73:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
72 | # if mode is given, and is not os.P_WAIT: ASYNC220
73 | os.spawnl(os.P_NOWAIT) # ASYNC220
| ^^^^^^^^^ ASYNC220
74 | os.spawnl(P_NOWAIT) # ASYNC220
75 | os.spawnl(mode=os.P_NOWAIT) # ASYNC220
|
ASYNC22x.py:74:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
72 | # if mode is given, and is not os.P_WAIT: ASYNC220
73 | os.spawnl(os.P_NOWAIT) # ASYNC220
74 | os.spawnl(P_NOWAIT) # ASYNC220
| ^^^^^^^^^ ASYNC220
75 | os.spawnl(mode=os.P_NOWAIT) # ASYNC220
76 | os.spawnl(mode=P_NOWAIT) # ASYNC220
|
ASYNC22x.py:75:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
73 | os.spawnl(os.P_NOWAIT) # ASYNC220
74 | os.spawnl(P_NOWAIT) # ASYNC220
75 | os.spawnl(mode=os.P_NOWAIT) # ASYNC220
| ^^^^^^^^^ ASYNC220
76 | os.spawnl(mode=P_NOWAIT) # ASYNC220
|
ASYNC22x.py:76:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
74 | os.spawnl(P_NOWAIT) # ASYNC220
75 | os.spawnl(mode=os.P_NOWAIT) # ASYNC220
76 | os.spawnl(mode=P_NOWAIT) # ASYNC220
| ^^^^^^^^^ ASYNC220
77 |
78 | P_WAIT = os.P_WAIT
|
ASYNC22x.py:86:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
85 | # other weird cases: ASYNC220
86 | os.spawnl(0) # ASYNC220
| ^^^^^^^^^ ASYNC220
87 | os.spawnl(1) # ASYNC220
88 | os.spawnl(foo()) # ASYNC220
|
ASYNC22x.py:87:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
85 | # other weird cases: ASYNC220
86 | os.spawnl(0) # ASYNC220
87 | os.spawnl(1) # ASYNC220
| ^^^^^^^^^ ASYNC220
88 | os.spawnl(foo()) # ASYNC220
|
ASYNC22x.py:88:5: ASYNC220 Async functions should not create subprocesses with blocking methods
|
86 | os.spawnl(0) # ASYNC220
87 | os.spawnl(1) # ASYNC220
88 | os.spawnl(foo()) # ASYNC220
| ^^^^^^^^^ ASYNC220
89 |
90 | # ASYNC222
|

View file

@ -0,0 +1,226 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC22x.py:8:5: ASYNC221 Async functions should not run processes with blocking methods
|
7 | async def func():
8 | subprocess.run("foo") # ASYNC221
| ^^^^^^^^^^^^^^ ASYNC221
|
ASYNC22x.py:12:5: ASYNC221 Async functions should not run processes with blocking methods
|
11 | async def func():
12 | subprocess.call("foo") # ASYNC221
| ^^^^^^^^^^^^^^^ ASYNC221
|
ASYNC22x.py:29:9: ASYNC221 Async functions should not run processes with blocking methods
|
27 | async def foo():
28 | await async_fun(
29 | subprocess.getoutput() # ASYNC221
| ^^^^^^^^^^^^^^^^^^^^ ASYNC221
30 | )
31 | subprocess.Popen() # ASYNC220
|
ASYNC22x.py:32:5: ASYNC221 Async functions should not run processes with blocking methods
|
30 | )
31 | subprocess.Popen() # ASYNC220
32 | os.system() # ASYNC221
| ^^^^^^^^^ ASYNC221
33 |
34 | system()
|
ASYNC22x.py:38:5: ASYNC221 Async functions should not run processes with blocking methods
|
36 | os.anything()
37 |
38 | subprocess.run() # ASYNC221
| ^^^^^^^^^^^^^^ ASYNC221
39 | subprocess.call() # ASYNC221
40 | subprocess.check_call() # ASYNC221
|
ASYNC22x.py:39:5: ASYNC221 Async functions should not run processes with blocking methods
|
38 | subprocess.run() # ASYNC221
39 | subprocess.call() # ASYNC221
| ^^^^^^^^^^^^^^^ ASYNC221
40 | subprocess.check_call() # ASYNC221
41 | subprocess.check_output() # ASYNC221
|
ASYNC22x.py:40:5: ASYNC221 Async functions should not run processes with blocking methods
|
38 | subprocess.run() # ASYNC221
39 | subprocess.call() # ASYNC221
40 | subprocess.check_call() # ASYNC221
| ^^^^^^^^^^^^^^^^^^^^^ ASYNC221
41 | subprocess.check_output() # ASYNC221
42 | subprocess.getoutput() # ASYNC221
|
ASYNC22x.py:41:5: ASYNC221 Async functions should not run processes with blocking methods
|
39 | subprocess.call() # ASYNC221
40 | subprocess.check_call() # ASYNC221
41 | subprocess.check_output() # ASYNC221
| ^^^^^^^^^^^^^^^^^^^^^^^ ASYNC221
42 | subprocess.getoutput() # ASYNC221
43 | subprocess.getstatusoutput() # ASYNC221
|
ASYNC22x.py:42:5: ASYNC221 Async functions should not run processes with blocking methods
|
40 | subprocess.check_call() # ASYNC221
41 | subprocess.check_output() # ASYNC221
42 | subprocess.getoutput() # ASYNC221
| ^^^^^^^^^^^^^^^^^^^^ ASYNC221
43 | subprocess.getstatusoutput() # ASYNC221
|
ASYNC22x.py:43:5: ASYNC221 Async functions should not run processes with blocking methods
|
41 | subprocess.check_output() # ASYNC221
42 | subprocess.getoutput() # ASYNC221
43 | subprocess.getstatusoutput() # ASYNC221
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC221
44 |
45 | await async_fun(
|
ASYNC22x.py:46:9: ASYNC221 Async functions should not run processes with blocking methods
|
45 | await async_fun(
46 | subprocess.getoutput() # ASYNC221
| ^^^^^^^^^^^^^^^^^^^^ ASYNC221
47 | )
|
ASYNC22x.py:54:5: ASYNC221 Async functions should not run processes with blocking methods
|
52 | subprocess()
53 |
54 | os.posix_spawn() # ASYNC221
| ^^^^^^^^^^^^^^ ASYNC221
55 | os.posix_spawnp() # ASYNC221
|
ASYNC22x.py:55:5: ASYNC221 Async functions should not run processes with blocking methods
|
54 | os.posix_spawn() # ASYNC221
55 | os.posix_spawnp() # ASYNC221
| ^^^^^^^^^^^^^^^ ASYNC221
56 |
57 | os.spawn()
|
ASYNC22x.py:61:5: ASYNC221 Async functions should not run processes with blocking methods
|
59 | os.spawnllll()
60 |
61 | os.spawnl() # ASYNC221
| ^^^^^^^^^ ASYNC221
62 | os.spawnle() # ASYNC221
63 | os.spawnlp() # ASYNC221
|
ASYNC22x.py:62:5: ASYNC221 Async functions should not run processes with blocking methods
|
61 | os.spawnl() # ASYNC221
62 | os.spawnle() # ASYNC221
| ^^^^^^^^^^ ASYNC221
63 | os.spawnlp() # ASYNC221
64 | os.spawnlpe() # ASYNC221
|
ASYNC22x.py:63:5: ASYNC221 Async functions should not run processes with blocking methods
|
61 | os.spawnl() # ASYNC221
62 | os.spawnle() # ASYNC221
63 | os.spawnlp() # ASYNC221
| ^^^^^^^^^^ ASYNC221
64 | os.spawnlpe() # ASYNC221
65 | os.spawnv() # ASYNC221
|
ASYNC22x.py:64:5: ASYNC221 Async functions should not run processes with blocking methods
|
62 | os.spawnle() # ASYNC221
63 | os.spawnlp() # ASYNC221
64 | os.spawnlpe() # ASYNC221
| ^^^^^^^^^^^ ASYNC221
65 | os.spawnv() # ASYNC221
66 | os.spawnve() # ASYNC221
|
ASYNC22x.py:65:5: ASYNC221 Async functions should not run processes with blocking methods
|
63 | os.spawnlp() # ASYNC221
64 | os.spawnlpe() # ASYNC221
65 | os.spawnv() # ASYNC221
| ^^^^^^^^^ ASYNC221
66 | os.spawnve() # ASYNC221
67 | os.spawnvp() # ASYNC221
|
ASYNC22x.py:66:5: ASYNC221 Async functions should not run processes with blocking methods
|
64 | os.spawnlpe() # ASYNC221
65 | os.spawnv() # ASYNC221
66 | os.spawnve() # ASYNC221
| ^^^^^^^^^^ ASYNC221
67 | os.spawnvp() # ASYNC221
68 | os.spawnvpe() # ASYNC221
|
ASYNC22x.py:67:5: ASYNC221 Async functions should not run processes with blocking methods
|
65 | os.spawnv() # ASYNC221
66 | os.spawnve() # ASYNC221
67 | os.spawnvp() # ASYNC221
| ^^^^^^^^^^ ASYNC221
68 | os.spawnvpe() # ASYNC221
|
ASYNC22x.py:68:5: ASYNC221 Async functions should not run processes with blocking methods
|
66 | os.spawnve() # ASYNC221
67 | os.spawnvp() # ASYNC221
68 | os.spawnvpe() # ASYNC221
| ^^^^^^^^^^^ ASYNC221
69 |
70 | P_NOWAIT = os.P_NOWAIT
|
ASYNC22x.py:81:5: ASYNC221 Async functions should not run processes with blocking methods
|
80 | # if it is P_WAIT, ASYNC221
81 | os.spawnl(P_WAIT) # ASYNC221
| ^^^^^^^^^ ASYNC221
82 | os.spawnl(mode=os.P_WAIT) # ASYNC221
83 | os.spawnl(mode=P_WAIT) # ASYNC221
|
ASYNC22x.py:82:5: ASYNC221 Async functions should not run processes with blocking methods
|
80 | # if it is P_WAIT, ASYNC221
81 | os.spawnl(P_WAIT) # ASYNC221
82 | os.spawnl(mode=os.P_WAIT) # ASYNC221
| ^^^^^^^^^ ASYNC221
83 | os.spawnl(mode=P_WAIT) # ASYNC221
|
ASYNC22x.py:83:5: ASYNC221 Async functions should not run processes with blocking methods
|
81 | os.spawnl(P_WAIT) # ASYNC221
82 | os.spawnl(mode=os.P_WAIT) # ASYNC221
83 | os.spawnl(mode=P_WAIT) # ASYNC221
| ^^^^^^^^^ ASYNC221
84 |
85 | # other weird cases: ASYNC220
|

View file

@ -0,0 +1,64 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC22x.py:20:5: ASYNC222 Async functions should not wait on processes with blocking methods
|
19 | async def func():
20 | os.wait4(10) # ASYNC222
| ^^^^^^^^ ASYNC222
|
ASYNC22x.py:24:5: ASYNC222 Async functions should not wait on processes with blocking methods
|
23 | async def func():
24 | os.wait(12) # ASYNC222
| ^^^^^^^ ASYNC222
|
ASYNC22x.py:91:5: ASYNC222 Async functions should not wait on processes with blocking methods
|
90 | # ASYNC222
91 | os.wait() # ASYNC222
| ^^^^^^^ ASYNC222
92 | os.wait3() # ASYNC222
93 | os.wait4() # ASYNC222
|
ASYNC22x.py:92:5: ASYNC222 Async functions should not wait on processes with blocking methods
|
90 | # ASYNC222
91 | os.wait() # ASYNC222
92 | os.wait3() # ASYNC222
| ^^^^^^^^ ASYNC222
93 | os.wait4() # ASYNC222
94 | os.waitid() # ASYNC222
|
ASYNC22x.py:93:5: ASYNC222 Async functions should not wait on processes with blocking methods
|
91 | os.wait() # ASYNC222
92 | os.wait3() # ASYNC222
93 | os.wait4() # ASYNC222
| ^^^^^^^^ ASYNC222
94 | os.waitid() # ASYNC222
95 | os.waitpid() # ASYNC222
|
ASYNC22x.py:94:5: ASYNC222 Async functions should not wait on processes with blocking methods
|
92 | os.wait3() # ASYNC222
93 | os.wait4() # ASYNC222
94 | os.waitid() # ASYNC222
| ^^^^^^^^^ ASYNC222
95 | os.waitpid() # ASYNC222
|
ASYNC22x.py:95:5: ASYNC222 Async functions should not wait on processes with blocking methods
|
93 | os.wait4() # ASYNC222
94 | os.waitid() # ASYNC222
95 | os.waitpid() # ASYNC222
| ^^^^^^^^^^ ASYNC222
96 |
97 | os.waitpi()
|

View file

@ -0,0 +1,101 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC230.py:6:5: ASYNC230 Async functions should not open files with blocking methods like `open`
|
5 | async def foo():
6 | open("") # ASYNC230
| ^^^^ ASYNC230
7 | io.open_code("") # ASYNC230
|
ASYNC230.py:7:5: ASYNC230 Async functions should not open files with blocking methods like `open`
|
5 | async def foo():
6 | open("") # ASYNC230
7 | io.open_code("") # ASYNC230
| ^^^^^^^^^^^^ ASYNC230
8 |
9 | with open(""): # ASYNC230
|
ASYNC230.py:9:10: ASYNC230 Async functions should not open files with blocking methods like `open`
|
7 | io.open_code("") # ASYNC230
8 |
9 | with open(""): # ASYNC230
| ^^^^ ASYNC230
10 | ...
|
ASYNC230.py:12:10: ASYNC230 Async functions should not open files with blocking methods like `open`
|
10 | ...
11 |
12 | with open("") as f: # ASYNC230
| ^^^^ ASYNC230
13 | ...
|
ASYNC230.py:15:17: ASYNC230 Async functions should not open files with blocking methods like `open`
|
13 | ...
14 |
15 | with foo(), open(""): # ASYNC230
| ^^^^ ASYNC230
16 | ...
|
ASYNC230.py:18:16: ASYNC230 Async functions should not open files with blocking methods like `open`
|
16 | ...
17 |
18 | async with open(""): # ASYNC230
| ^^^^ ASYNC230
19 | ...
|
ASYNC230.py:29:5: ASYNC230 Async functions should not open files with blocking methods like `open`
|
28 | async def func():
29 | open("foo") # ASYNC230
| ^^^^ ASYNC230
|
ASYNC230.py:36:5: ASYNC230 Async functions should not open files with blocking methods like `open`
|
35 | async def func():
36 | Path("foo").open() # ASYNC230
| ^^^^^^^^^^^^^^^^ ASYNC230
|
ASYNC230.py:41:5: ASYNC230 Async functions should not open files with blocking methods like `open`
|
39 | async def func():
40 | p = Path("foo")
41 | p.open() # ASYNC230
| ^^^^^^ ASYNC230
|
ASYNC230.py:45:10: ASYNC230 Async functions should not open files with blocking methods like `open`
|
44 | async def func():
45 | with Path("foo").open() as f: # ASYNC230
| ^^^^^^^^^^^^^^^^ ASYNC230
46 | pass
|
ASYNC230.py:53:9: ASYNC230 Async functions should not open files with blocking methods like `open`
|
52 | async def bar():
53 | p.open() # ASYNC230
| ^^^^^^ ASYNC230
|
ASYNC230.py:59:5: ASYNC230 Async functions should not open files with blocking methods like `open`
|
57 | (p1, p2) = (Path("foo"), Path("bar"))
58 |
59 | p1.open() # ASYNC230
| ^^^^^^^ ASYNC230
|

View file

@ -0,0 +1,9 @@
---
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
---
ASYNC251.py:6:5: ASYNC251 Async functions should not call `time.sleep`
|
5 | async def func():
6 | time.sleep(1) # ASYNC251
| ^^^^^^^^^^ ASYNC251
|

View file

@ -1,31 +0,0 @@
//! Rules from [flake8-trio](https://pypi.org/project/flake8-trio/).
pub(super) mod method_name;
pub(crate) mod rules;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::LinterSettings;
use crate::test::test_path;
#[test_case(Rule::TrioTimeoutWithoutAwait, Path::new("TRIO100.py"))]
#[test_case(Rule::TrioSyncCall, Path::new("TRIO105.py"))]
#[test_case(Rule::TrioAsyncFunctionWithTimeout, Path::new("TRIO109.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());
let diagnostics = test_path(
Path::new("flake8_trio").join(path).as_path(),
&LinterSettings::for_rule(rule_code),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View file

@ -1,11 +0,0 @@
pub(crate) use async_function_with_timeout::*;
pub(crate) use sync_call::*;
pub(crate) use timeout_without_await::*;
pub(crate) use unneeded_sleep::*;
pub(crate) use zero_sleep_call::*;
mod async_function_with_timeout;
mod sync_call;
mod timeout_without_await;
mod unneeded_sleep;
mod zero_sleep_call;

View file

@ -1,22 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_trio/mod.rs
---
TRIO100.py:5:5: TRIO100 A `with trio.fail_after(...):` context does not contain any `await` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint.
|
4 | async def func():
5 | with trio.fail_after():
| _____^
6 | | ...
| |___________^ TRIO100
|
TRIO100.py:15:5: TRIO100 A `with trio.move_on_after(...):` context does not contain any `await` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint.
|
14 | async def func():
15 | with trio.move_on_after():
| _____^
16 | | ...
| |___________^ TRIO100
|

View file

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

View file

@ -1,22 +0,0 @@
---
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
|

View file

@ -37,7 +37,6 @@ pub mod flake8_simplify;
pub mod flake8_slots;
pub mod flake8_tidy_imports;
pub mod flake8_todos;
pub mod flake8_trio;
pub mod flake8_type_checking;
pub mod flake8_unused_arguments;
pub mod flake8_use_pathlib;

View file

@ -81,7 +81,6 @@ natively, including:
- [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
- [flake8-todos](https://pypi.org/project/flake8-todos/)
- [flake8-trio](https://pypi.org/project/flake8-trio/) ([#8451](https://github.com/astral-sh/ruff/issues/8451))
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
@ -194,7 +193,6 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
- [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
- [flake8-todos](https://pypi.org/project/flake8-todos/)
- [flake8-trio](https://pypi.org/project/flake8-trio/) ([#8451](https://github.com/astral-sh/ruff/issues/8451))
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))

26
ruff.schema.json generated
View file

@ -2703,10 +2703,23 @@
"ASYNC1",
"ASYNC10",
"ASYNC100",
"ASYNC101",
"ASYNC102",
"ASYNC105",
"ASYNC109",
"ASYNC11",
"ASYNC110",
"ASYNC115",
"ASYNC116",
"ASYNC2",
"ASYNC21",
"ASYNC210",
"ASYNC22",
"ASYNC220",
"ASYNC221",
"ASYNC222",
"ASYNC23",
"ASYNC230",
"ASYNC25",
"ASYNC251",
"B",
"B0",
"B00",
@ -3847,15 +3860,6 @@
"TID251",
"TID252",
"TID253",
"TRIO",
"TRIO1",
"TRIO10",
"TRIO100",
"TRIO105",
"TRIO109",
"TRIO11",
"TRIO110",
"TRIO115",
"TRY",
"TRY0",
"TRY00",