Skip to content

Commit 136443b

Browse files
[flake8-async] Mark autofix for ASYNC115 as unsafe if the call expression contains comments (#18753)
Co-authored-by: Micha Reiser <micha@reiser.io>
1 parent f7a741a commit 136443b

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_async/ASYNC115.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,15 @@ async def test_trio_async115_helpers():
165165

166166
await trio.sleep(seconds=0) # ASYNC115
167167
await trio.sleep(delay=0) # OK
168+
169+
# https://github.com/astral-sh/ruff/issues/18740
170+
# The autofix for this is unsafe due to the comments.
171+
async def func():
172+
import trio
173+
174+
await (
175+
trio # comment
176+
.sleep( # comment
177+
0 # comment
178+
)
179+
)

crates/ruff_linter/src/rules/flake8_async/rules/async_zero_sleep.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use ruff_diagnostics::Applicability;
12
use ruff_macros::{ViolationMetadata, derive_message_formats};
23
use ruff_python_ast::{self as ast, Expr, ExprCall, Int, Number};
34
use ruff_python_semantic::Modules;
@@ -32,6 +33,21 @@ use crate::{AlwaysFixableViolation, Edit, Fix};
3233
/// async def func():
3334
/// await trio.lowlevel.checkpoint()
3435
/// ```
36+
/// ## Fix safety
37+
/// This rule's fix is marked as unsafe if there's comments in the
38+
/// `trio.sleep(0)` expression, as comments may be removed.
39+
///
40+
/// For example, the fix would be marked as unsafe in the following case:
41+
/// ```python
42+
/// import trio
43+
///
44+
///
45+
/// async def func():
46+
/// await trio.sleep( # comment
47+
/// # comment
48+
/// 0
49+
/// )
50+
/// ```
3551
#[derive(ViolationMetadata)]
3652
pub(crate) struct AsyncZeroSleep {
3753
module: AsyncModule,
@@ -119,7 +135,15 @@ pub(crate) fn async_zero_sleep(checker: &Checker, call: &ExprCall) {
119135
let reference_edit =
120136
Edit::range_replacement(format!("{binding}.checkpoint"), call.func.range());
121137
let arg_edit = Edit::range_replacement("()".to_string(), call.arguments.range());
122-
Ok(Fix::safe_edits(import_edit, [reference_edit, arg_edit]))
138+
Ok(Fix::applicable_edits(
139+
import_edit,
140+
[reference_edit, arg_edit],
141+
if checker.comment_ranges().intersects(call.range()) {
142+
Applicability::Unsafe
143+
} else {
144+
Applicability::Safe
145+
},
146+
))
123147
});
124148
}
125149
}

crates/ruff_linter/src/rules/flake8_async/snapshots/ruff_linter__rules__flake8_async__tests__ASYNC115_ASYNC115.py.snap

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,28 @@ ASYNC115.py:166:11: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `tr
252252
166 |- await trio.sleep(seconds=0) # ASYNC115
253253
166 |+ await trio.lowlevel.checkpoint() # ASYNC115
254254
167 167 | await trio.sleep(delay=0) # OK
255+
168 168 |
256+
169 169 | # https://github.com/astral-sh/ruff/issues/18740
257+
258+
ASYNC115.py:175:5: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
259+
|
260+
174 | await (
261+
175 | / trio # comment
262+
176 | | .sleep( # comment
263+
177 | | 0 # comment
264+
178 | | )
265+
| |_____^ ASYNC115
266+
179 | )
267+
|
268+
= help: Replace with `trio.lowlevel.checkpoint()`
269+
270+
Unsafe fix
271+
172 172 | import trio
272+
173 173 |
273+
174 174 | await (
274+
175 |- trio # comment
275+
176 |- .sleep( # comment
276+
177 |- 0 # comment
277+
178 |- )
278+
175 |+ trio.lowlevel.checkpoint()
279+
179 176 | )

0 commit comments

Comments
 (0)