Skip to content

Commit e4f6448

Browse files
authored
[perflint] Ignore rule if target is global or nonlocal (PERF401) (#19539)
## Summary Resolves #19531 I've implemented a check to determine whether the for_stmt target is declared as global or nonlocal. I believe we should skip the rule in all such cases, since variables declared this way are intended for use outside the loop scope, making value changes expected behavior. ## Test Plan Added two test cases for global and nonlocal variable to snapshot.
1 parent 4016aff commit e4f6448

File tree

4 files changed

+28
-1
lines changed

4 files changed

+28
-1
lines changed

crates/ruff_linter/resources/test/fixtures/perflint/PERF401.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,4 +289,19 @@ def f():
289289
i = "xyz"
290290
result = []
291291
for i in range(3):
292-
result.append((x for x in [i]))
292+
result.append((x for x in [i]))
293+
294+
G_INDEX = None
295+
def f():
296+
global G_INDEX
297+
result = []
298+
for G_INDEX in range(3):
299+
result.append(G_INDEX)
300+
301+
def f():
302+
NL_INDEX = None
303+
def x():
304+
nonlocal NL_INDEX
305+
result = []
306+
for NL_INDEX in range(3):
307+
result.append(NL_INDEX)

crates/ruff_linter/src/rules/perflint/rules/manual_list_comprehension.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ pub(crate) fn manual_list_comprehension(checker: &Checker, for_stmt: &ast::StmtF
249249
.iter()
250250
.find(|binding| for_stmt.target.range() == binding.range)
251251
.unwrap();
252+
// If the target variable is global (e.g., `global INDEX`) or nonlocal (e.g., `nonlocal INDEX`),
253+
// then it is intended to be used elsewhere outside the for loop.
254+
if target_binding.is_global() || target_binding.is_nonlocal() {
255+
return;
256+
}
252257
// If any references to the loop target variable are after the loop,
253258
// then converting it into a comprehension would cause a NameError
254259
if target_binding

crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF401_PERF401.py.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,5 +263,7 @@ PERF401.py:292:9: PERF401 Use a list comprehension to create a transformed list
263263
291 | for i in range(3):
264264
292 | result.append((x for x in [i]))
265265
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PERF401
266+
293 |
267+
294 | G_INDEX = None
266268
|
267269
= help: Replace for loop with list comprehension

crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__preview__PERF401_PERF401.py.snap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ PERF401.py:292:9: PERF401 [*] Use a list comprehension to create a transformed l
612612
291 | for i in range(3):
613613
292 | result.append((x for x in [i]))
614614
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PERF401
615+
293 |
616+
294 | G_INDEX = None
615617
|
616618
= help: Replace for loop with list comprehension
617619

@@ -623,3 +625,6 @@ PERF401.py:292:9: PERF401 [*] Use a list comprehension to create a transformed l
623625
291 |- for i in range(3):
624626
292 |- result.append((x for x in [i]))
625627
290 |+ result = [(x for x in [i]) for i in range(3)]
628+
293 291 |
629+
294 292 | G_INDEX = None
630+
295 293 | def f():

0 commit comments

Comments
 (0)