File: writelines.py

package info (click to toggle)
python-refurb 1.27.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,700 kB
  • sloc: python: 9,468; makefile: 40; sh: 6
file content (80 lines) | stat: -rw-r--r-- 2,058 bytes parent folder | download
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))