File: use_cache.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 (63 lines) | stat: -rw-r--r-- 1,582 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
from dataclasses import dataclass

from mypy.nodes import ArgKind, CallExpr, Decorator, MemberExpr, NameExpr, RefExpr

from refurb.error import Error
from refurb.settings import Settings


@dataclass
class ErrorInfo(Error):
    """
    Python 3.9 introduces the `@cache` decorator which can be used as a
    short-hand for `@lru_cache(maxsize=None)`.

    Bad:

    ```
    from functools import lru_cache

    @lru_cache(maxsize=None)
    def f(x: int) -> int:
        return x + 1
    ```

    Good:

    ```
    from functools import cache

    @cache
    def f(x: int) -> int:
        return x + 1
    ```
    """

    name = "use-cache"
    code = 134
    msg: str = "Replace `@lru_cache(maxsize=None)` with `@cache`"
    categories = ("functools", "python39", "readability")


def check(node: Decorator, errors: list[Error], settings: Settings) -> None:
    if settings.get_python_version() < (3, 9):
        return  # pragma: no cover

    match node:
        case Decorator(
            decorators=[
                CallExpr(
                    callee=RefExpr(fullname="functools.lru_cache") as ref,
                    arg_names=["maxsize"],
                    arg_kinds=[ArgKind.ARG_NAMED],
                    args=[NameExpr(fullname="builtins.None")],
                )
            ]
        ):
            prefix = "functools." if isinstance(ref, MemberExpr) else ""
            old = f"@{prefix}lru_cache(maxsize=None)"
            new = f"@{prefix}cache"

            msg = f"Replace `{old}` with `{new}`"

            errors.append(ErrorInfo.from_node(node, msg))