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
|
from dataclasses import dataclass
from mypy.nodes import (
Block,
CallExpr,
ExpressionStmt,
ForStmt,
MemberExpr,
NameExpr,
Var,
WithStmt,
)
from refurb.error import Error
@dataclass
class ErrorInfo(Error):
r"""
When you want to write a list of lines to a file, don't call `.write()`
for every line, use `.writelines()` instead:
Bad:
```
lines = ["line 1\n", "line 2\n", "line 3\n"]
with open("file") as f:
for line in lines:
f.write(line)
```
Good:
```
lines = ["line 1\n", "line 2\n", "line 3\n"]
with open("file") as f:
f.writelines(lines)
```
Note: If you have a more complex expression then just `lines`, you may
need to use a list comprehension instead. For example:
```
f.writelines(f"{line}\n" for line in lines)
```
"""
name = "use-writelines"
code = 122
msg: str = "Replace `for line in lines: f.write(line)` with `f.writelines(lines)`"
categories = ("builtin", "readability")
def check(node: WithStmt, errors: list[Error]) -> None:
match node:
case WithStmt(
target=[NameExpr(node=Var(type=ty)) as resource],
body=Block(
body=[
ForStmt(
index=NameExpr(),
body=Block(
body=[
ExpressionStmt(
expr=CallExpr(
callee=MemberExpr(
expr=NameExpr() as file,
name="write",
)
)
)
]
),
) as for_stmt
]
),
) if str(ty).startswith("io.") and resource.fullname == file.fullname:
errors.append(ErrorInfo.from_node(for_stmt))
|