Skip to content

Commit 435963c

Browse files
authored
Don't emit FURB135/FURB148 when using _ in comprehensions (#312):
Closes #311. See #311 (comment) for a detailed explaination of the problem and how I went about fixing it.
1 parent e76e8d5 commit 435963c

File tree

8 files changed

+34
-31
lines changed

8 files changed

+34
-31
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "refurb"
3-
version = "1.24.0"
3+
version = "1.25.0"
44
description = "A tool for refurbish and modernize Python codebases"
55
authors = ["dosisod"]
66
license = "GPL-3.0-only"

refurb/checks/builtin/no_ignored_dict_items.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
Var,
1313
)
1414

15-
from refurb.checks.common import check_for_loop_like, is_name_unused_in_contexts, is_placeholder
15+
from refurb.checks.common import check_for_loop_like, is_name_unused_in_contexts
1616
from refurb.error import Error
1717

1818

@@ -78,10 +78,10 @@ def check_dict_items_call(
7878
def check_unused_key_or_value(
7979
key: NameExpr, value: NameExpr, contexts: list[Node], errors: list[Error]
8080
) -> None:
81-
if is_placeholder(key) or is_name_unused_in_contexts(key, contexts):
81+
if is_name_unused_in_contexts(key, contexts):
8282
errors.append(
8383
ErrorInfo.from_node(key, "Key is unused, use `for value in d.values()` instead")
8484
)
8585

86-
if is_placeholder(value) or is_name_unused_in_contexts(value, contexts):
86+
if is_name_unused_in_contexts(value, contexts):
8787
errors.append(ErrorInfo.from_node(value, "Value is unused, use `for key in d` instead"))

refurb/checks/builtin/no_ignored_enumerate.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
Var,
1212
)
1313

14-
from refurb.checks.common import check_for_loop_like, is_name_unused_in_contexts, is_placeholder
14+
from refurb.checks.common import check_for_loop_like, is_name_unused_in_contexts
1515
from refurb.error import Error
1616

1717

@@ -75,10 +75,10 @@ def check_enumerate_call(
7575
def check_unused_index_or_value(
7676
index: NameExpr, value: NameExpr, contexts: list[Node], errors: list[Error]
7777
) -> None:
78-
if is_placeholder(index) or is_name_unused_in_contexts(index, contexts):
78+
if is_name_unused_in_contexts(index, contexts):
7979
errors.append(ErrorInfo.from_node(index, "Index is unused, use `for x in y` instead"))
8080

81-
if is_placeholder(value) or is_name_unused_in_contexts(value, contexts):
81+
if is_name_unused_in_contexts(value, contexts):
8282
errors.append(
8383
ErrorInfo.from_node(value, "Value is unused, use `for x in range(len(y))` instead")
8484
)

refurb/checks/common.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def check_for_loop_like(
7171
) -> None:
7272
match node:
7373
case ForStmt(index=index, expr=expr):
74-
func(index, expr, [], errors)
74+
func(index, expr, [node.body], errors)
7575

7676
case GeneratorExpr(
7777
indices=[index],
@@ -228,14 +228,7 @@ def was_read(self) -> int:
228228
return self.read_count > 0
229229

230230

231-
def is_placeholder(name: NameExpr) -> bool:
232-
return unmangle_name(name.name) == "_"
233-
234-
235231
def is_name_unused_in_contexts(name: NameExpr, contexts: list[Node]) -> bool:
236-
if not contexts:
237-
return False
238-
239232
for ctx in contexts:
240233
visitor = ReadCountVisitor(name)
241234
visitor.accept(ctx)

test/data/err_135.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,21 @@ def f5():
3030
{v: "" for k, v in d.items()} # "k" is unused, warn
3131

3232

33+
def f6():
34+
k=v=0
35+
36+
# don't warn because we can't know if "k" or "v" are unused simply by
37+
# looking at the for block, we need to account for the surrounding context,
38+
# which is not possible currently.
39+
for k, v in d.items():
40+
pass
41+
42+
print(k, v)
43+
44+
3345
# these should not
3446

35-
def f6():
47+
def f7():
3648
for k, v in d.items():
3749
print(k, v)
3850

@@ -41,24 +53,13 @@ class Shelf:
4153
def items(self) -> list[tuple[str, int]]:
4254
return [("bagels", 123)]
4355

44-
def f7():
56+
def f8():
4557
shelf = Shelf()
4658

4759
for name, count in shelf.items():
4860
pass
4961

5062

51-
def f8():
52-
k=v=0
53-
54-
# don't warn because we can't know if "k" or "v" are unused simply by
55-
# looking at the for block, we need to account for the surrounding context,
56-
# which is not possible currently.
57-
for k, v in d.items():
58-
pass
59-
60-
print(k, v)
61-
6263
def f9():
6364
{k: "" for k, v in d.items() if v}
6465
{v: "" for k, v in d.items() if k}

test/data/err_135.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ test/data/err_135.py:26:15 [FURB135]: Value is unused, use `for key in d` instea
88
test/data/err_135.py:27:12 [FURB135]: Key is unused, use `for value in d.values()` instead
99
test/data/err_135.py:29:19 [FURB135]: Value is unused, use `for key in d` instead
1010
test/data/err_135.py:30:16 [FURB135]: Key is unused, use `for value in d.values()` instead
11+
test/data/err_135.py:39:9 [FURB135]: Key is unused, use `for value in d.values()` instead
12+
test/data/err_135.py:39:12 [FURB135]: Value is unused, use `for key in d` instead

test/data/err_148.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@
2525

2626
_ = (index for index, _ in enumerate(nums3))
2727

28-
29-
# these should not
30-
3128
for index, num in enumerate(nums):
3229
pass
3330

31+
# these should not
32+
3433
# "count" is an infinite generator. In general, we only want to warn on
3534
# sequence types because you can call len() on them without exhausting some
3635
# iterator.
@@ -39,3 +38,9 @@
3938
pass
4039

4140
_ = (num for index, num in enumerate(nums) if index)
41+
42+
for index, _ in enumerate(nums):
43+
print(index, _)
44+
45+
_ = ((index, _) for index, _ in enumerate(nums))
46+
_ = ((_, num) for _, num in enumerate(nums))

test/data/err_148.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ test/data/err_148.py:19:19 [FURB148]: Value is unused, use `for x in range(len(y
99
test/data/err_148.py:21:25 [FURB148]: Index is unused, use `for x in y` instead
1010
test/data/err_148.py:21:32 [FURB148]: Value is unused, use `for x in range(len(y))` instead
1111
test/data/err_148.py:26:23 [FURB148]: Value is unused, use `for x in range(len(y))` instead
12+
test/data/err_148.py:28:5 [FURB148]: Index is unused, use `for x in y` instead
13+
test/data/err_148.py:28:12 [FURB148]: Value is unused, use `for x in range(len(y))` instead

0 commit comments

Comments
 (0)