File: no_temp_class_object.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 (60 lines) | stat: -rw-r--r-- 1,663 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
from dataclasses import dataclass

from mypy.nodes import CallExpr, Decorator, FuncDef, MemberExpr, NameExpr, TypeInfo

from refurb.error import Error


@dataclass
class ErrorInfo(Error):
    """
    You don't need to construct a class object to call a static method or a
    class method, just invoke the method on the class directly:

    Bad:

    ```
    cwd = Path().cwd()
    ```

    Good:

    ```
    cwd = Path.cwd()
    ```
    """

    name = "no-temp-class-object"
    code = 165
    categories = ("readability",)


def check(node: CallExpr, errors: list[Error]) -> None:
    match node:
        case CallExpr(
            callee=MemberExpr(
                expr=CallExpr(
                    callee=NameExpr(node=TypeInfo() as klass),
                    args=class_args,
                ),
                name=func_name,
            ),
            args=func_args,
        ):
            for func in klass.defn.defs.body:
                if isinstance(func, Decorator):
                    func = func.func  # noqa: PLW2901

                elif not isinstance(func, FuncDef):
                    continue

                if func.name == func_name and (func.is_class or func.is_static):
                    class_name = klass.defn.name

                    class_args = "..." if class_args else ""  # type: ignore
                    func_args = "..." if func_args else ""  # type: ignore

                    old = f"{class_name}({class_args}).{func_name}({func_args})"  # noqa: E501
                    new = f"{class_name}.{func_name}({func_args})"

                    errors.append(ErrorInfo.from_node(node, f"Replace `{old}` with `{new}`"))