File: in_tuple.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 (61 lines) | stat: -rw-r--r-- 1,562 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
from dataclasses import dataclass

from mypy.nodes import ComparisonExpr, ForStmt, GeneratorExpr, ListExpr

from refurb.error import Error


@dataclass
class ErrorInfo(Error):
    """
    Since tuple, list, and set literals can be used with the `in` operator, it
    is best to pick one and stick with it.

    Bad:

    ```
    for x in (1, 2, 3):
        pass

    nums = [str(x) for x in [1, 2, 3]]
    ```

    Good:

    ```
    for x in (1, 2, 3):
        pass

    nums = [str(x) for x in (1, 2, 3)]
    ```
    """

    # Currently this check is hard-coded for tuples, but once we have the
    # ability to pass parameters into checks this check will be able to work
    # with a variety of bracket types.
    name = "use-consistent-in-bracket"
    code = 109
    categories = ("iterable", "readability")


def error_msg(oper: str) -> str:
    return f"Replace `{oper} [x, y, z]` with `{oper} (x, y, z)`"


def check(node: ComparisonExpr | ForStmt | GeneratorExpr, errors: list[Error]) -> None:
    match node:
        case ComparisonExpr(
            operators=["in" | "not in" as oper],
            operands=[_, ListExpr() as expr],
        ):
            errors.append(ErrorInfo.from_node(expr, error_msg(oper)))

        case ForStmt(expr=ListExpr() as expr):
            errors.append(ErrorInfo.from_node(expr, error_msg("in")))

        case GeneratorExpr():
            errors.extend(
                ErrorInfo.from_node(expr, error_msg("in"))
                for expr in node.sequences
                if isinstance(expr, ListExpr)
            )