File: simplify_query.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 (76 lines) | stat: -rw-r--r-- 2,117 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
from dataclasses import dataclass

from mypy.nodes import CallExpr, EllipsisExpr, FuncDef, NameExpr

from refurb.error import Error


@dataclass
class ErrorInfo(Error):
    """
    FastAPI will automatically pass along query parameters to your function, so
    you only need to use `Query()` when you use params other than `default`.

    Bad:

    ```
    @app.get("/")
    def index(name: str = Query()) -> str:
        return f"Your name is {name}"
    ```

    Good:

    ```
    @app.get("/")
    def index(name: str) -> str:
        return f"Your name is {name}"
    ```
    """

    name = "simplify-fastapi-query"
    code = 175
    categories = ("fastapi", "readability")


def check(node: FuncDef, errors: list[Error]) -> None:
    for arg in node.arguments:
        name = arg.variable.fullname

        match arg.initializer:
            case CallExpr(
                callee=NameExpr(fullname="fastapi.param_functions.Query"),
                args=query_args,
                arg_names=query_arg_names,
            ):
                if len(query_arg_names) > 1:
                    continue

                ty = ": T" if arg.type_annotation else ""
                is_ellipsis = False

                if query_arg_names:
                    # Query(...) is special in that it acts the same as Query()
                    # so keep track of this so we can emit a better message.
                    is_ellipsis = isinstance(query_args[0], EllipsisExpr)

                    query_arg = "..." if is_ellipsis else "x"

                    if query_arg_names[0] == "default":
                        query = f"Query(default={query_arg})"

                    elif query_arg_names[0] is None:
                        query = f"Query({query_arg})"

                    else:
                        continue

                else:
                    query = "Query()"

                old = f"{name}{ty} = {query}"
                new = f"{name}{ty}" if is_ellipsis else f"{name}{ty} = x"

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

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