File: list_extend.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 (84 lines) | stat: -rw-r--r-- 1,850 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
81
82
83
84
from dataclasses import dataclass

from mypy.nodes import (
    Block,
    CallExpr,
    ExpressionStmt,
    MemberExpr,
    MypyFile,
    NameExpr,
    Statement,
    Var,
)

from refurb.checks.common import check_block_like
from refurb.error import Error


@dataclass
class ErrorInfo(Error):
    """
    When appending multiple values to a list, you can use the `.extend()`
    method to add an iterable to the end of an existing list. This way, you
    don't have to call `.append()` on every element:

    Bad:

    ```
    nums = [1, 2, 3]

    nums.append(4)
    nums.append(5)
    nums.append(6)
    ```

    Good:

    ```
    nums = [1, 2, 3]

    nums.extend((4, 5, 6))
    ```
    """

    name = "use-list-extend"
    code = 113
    msg: str = "Use `x.extend(...)` instead of repeatedly calling `x.append()`"
    categories = ("list",)


@dataclass
class Last:
    name: str = ""
    line: int = 0
    column: int = 0
    did_error: bool = False


def check(node: Block | MypyFile, errors: list[Error]) -> None:
    check_block_like(check_stmts, node, errors)


def check_stmts(stmts: list[Statement], errors: list[Error]) -> None:
    last = Last()

    for stmt in stmts:
        match stmt:
            case ExpressionStmt(
                expr=CallExpr(
                    callee=MemberExpr(
                        expr=NameExpr(name=name, node=Var(type=ty)),
                        name="append",
                    ),
                )
            ) if str(ty).startswith("builtins.list["):
                if not last.did_error and name == last.name:
                    errors.append(ErrorInfo(last.line, last.column))
                    last.did_error = True

                last.name = name
                last.line = stmt.line
                last.column = stmt.column

            case _:
                last = Last()