Fix SIM110 with a yield in the condition (#7801)

And allow "await" in the loop iterable.

Fixes #7800
This commit is contained in:
Jelle Zijlstra
2023-10-04 05:59:19 -07:00
committed by GitHub
parent a1509dfc7c
commit 600471e45f
3 changed files with 61 additions and 4 deletions

View File

@@ -185,3 +185,24 @@ async def f():
if check(x):
return True
return False
async def f():
# SIM110
for x in await iterable:
if check(x):
return True
return False
def f():
# OK (can't turn this into any() because the yield would end up inside a genexp)
for x in iterable:
if (yield check(x)):
return True
return False
def f():
# OK (same)
for x in iterable:
if (yield from check(x)):
return True
return False

View File

@@ -80,8 +80,9 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) {
return;
};
// Check if any of the expressions contain an `await` expression.
if contains_await(loop_.target) || contains_await(loop_.iter) || contains_await(loop_.test) {
// Check if any of the expressions contain an `await`, `yield`, or `yield from` expression.
// If so, turning the code into an any() or all() call would produce a SyntaxError.
if contains_yield_like(loop_.target) || contains_yield_like(loop_.test) {
return;
}
@@ -413,7 +414,9 @@ fn return_stmt(id: &str, test: &Expr, target: &Expr, iter: &Expr, generator: Gen
generator.stmt(&node3.into())
}
/// Return `true` if the [`Expr`] contains an `await` expression.
fn contains_await(expr: &Expr) -> bool {
/// Return `true` if the [`Expr`] contains an `await`, `yield`, or `yield from` expression.
fn contains_yield_like(expr: &Expr) -> bool {
any_over_expr(expr, &Expr::is_await_expr)
|| any_over_expr(expr, &Expr::is_yield_expr)
|| any_over_expr(expr, &Expr::is_yield_from_expr)
}

View File

@@ -304,6 +304,8 @@ SIM110.py:184:5: SIM110 [*] Use `return any(check(x) for x in iterable)` instead
186 | | return True
187 | | return False
| |________________^ SIM110
188 |
189 | async def f():
|
= help: Replace with `return any(check(x) for x in iterable)`
@@ -316,5 +318,36 @@ SIM110.py:184:5: SIM110 [*] Use `return any(check(x) for x in iterable)` instead
186 |- return True
187 |- return False
184 |+ return any(check(x) for x in iterable)
188 185 |
189 186 | async def f():
190 187 | # SIM110
SIM110.py:191:5: SIM110 [*] Use `return any(check(x) for x in await iterable)` instead of `for` loop
|
189 | async def f():
190 | # SIM110
191 | for x in await iterable:
| _____^
192 | | if check(x):
193 | | return True
194 | | return False
| |________________^ SIM110
195 |
196 | def f():
|
= help: Replace with `return any(check(x) for x in await iterable)`
Suggested fix
188 188 |
189 189 | async def f():
190 190 | # SIM110
191 |- for x in await iterable:
192 |- if check(x):
193 |- return True
194 |- return False
191 |+ return any(check(x) for x in await iterable)
195 192 |
196 193 | def f():
197 194 | # OK (can't turn this into any() because the yield would end up inside a genexp)