-
-
Notifications
You must be signed in to change notification settings - Fork 54
/
Copy pathno_ignored_enumerate.py
96 lines (74 loc) · 2.23 KB
/
no_ignored_enumerate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from dataclasses import dataclass
from mypy.nodes import (
CallExpr,
DictionaryComprehension,
Expression,
ForStmt,
GeneratorExpr,
NameExpr,
Node,
TupleExpr,
)
from refurb.checks.common import (
check_for_loop_like,
get_mypy_type,
is_name_unused_in_contexts,
is_subclass,
stringify,
)
from refurb.error import Error
@dataclass
class ErrorInfo(Error):
"""
Don't use `enumerate` if you are disregarding either the index or the
value:
Bad:
```
books = ["Ender's Game", "The Black Swan"]
for index, _ in enumerate(books):
print(index)
for _, book in enumerate(books):
print(book)
```
Good:
```
books = ["Ender's Game", "The Black Swan"]
for index in range(len(books)):
print(index)
for book in books:
print(book)
```
"""
name = "no-ignored-enumerate-items"
code = 148
categories = ("builtin",)
def check(
node: ForStmt | GeneratorExpr | DictionaryComprehension,
errors: list[Error],
) -> None:
check_for_loop_like(check_enumerate_call, node, errors)
def check_enumerate_call(
index: Node, expr: Node, contexts: list[Node], errors: list[Error]
) -> None:
match index, expr:
case (
TupleExpr(items=[NameExpr() as index, NameExpr() as value]),
CallExpr(
callee=NameExpr(fullname="builtins.enumerate"),
args=[enumerate_arg],
),
) if is_subclass(get_mypy_type(enumerate_arg), "typing.Sequence"):
check_unused_index_or_value(index, value, contexts, errors, enumerate_arg)
def check_unused_index_or_value(
index: NameExpr,
value: NameExpr,
contexts: list[Node],
errors: list[Error],
enumerate_arg: Expression,
) -> None:
if is_name_unused_in_contexts(index, contexts):
msg = f"Index is unused, use `for {stringify(value)} in {stringify(enumerate_arg)}` instead" # noqa: E501
errors.append(ErrorInfo.from_node(index, msg))
if is_name_unused_in_contexts(value, contexts):
msg = f"Value is unused, use `for {stringify(index)} in range(len({stringify(enumerate_arg)}))` instead" # noqa: E501
errors.append(ErrorInfo.from_node(value, msg))