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
|
from dataclasses import dataclass
from mypy.nodes import ArgKind, AssignmentStmt, CallExpr, NameExpr, Var
from refurb.checks.common import stringify, unmangle_name
from refurb.error import Error
@dataclass
class ErrorInfo(Error):
"""
Don't use `sorted()` to sort a list and reassign it to itself, use the
faster in-place `.sort()` method instead.
Bad:
```
names = ["Bob", "Alice", "Charlie"]
names = sorted(names)
```
Good:
```
names = ["Bob", "Alice", "Charlie"]
names.sort()
```
"""
name = "use-sort"
categories = ("performance", "readability")
code = 186
def check(node: AssignmentStmt, errors: list[Error]) -> None:
match node:
case AssignmentStmt(
lvalues=[NameExpr(fullname=assign_name) as assign_ref],
rvalue=CallExpr(
callee=NameExpr(fullname="builtins.sorted"),
args=[
NameExpr(fullname=sort_name, node=Var(type=ty)),
*rest,
],
arg_names=[_, *arg_names],
arg_kinds=[_, *arg_kinds],
),
) if (
unmangle_name(assign_name) == unmangle_name(sort_name)
and str(ty).startswith("builtins.list[")
and all(arg_kind == ArgKind.ARG_NAMED for arg_kind in arg_kinds)
):
old_args: list[str] = []
new_args: list[str] = []
name = stringify(assign_ref)
old_args.append(name)
if rest:
for arg_name, expr in zip(arg_names, rest):
arg = f"{arg_name}={stringify(expr)}"
old_args.append(arg)
new_args.append(arg)
old = f"{name} = sorted({', '.join(old_args)})"
new = f"{name}.sort({', '.join(new_args)})"
msg = f"Replace `{old}` with `{new}`"
errors.append(ErrorInfo.from_node(node, msg))
|