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 77 78 79 80 81 82 83 84 85
|
from dataclasses import dataclass
from mypy.nodes import ComparisonExpr, ConditionalExpr
from refurb.checks.common import is_equivalent
from refurb.error import Error
@dataclass
class ErrorInfo(Error):
"""
Certain ternary expressions can be written more succinctly using the
builtin `min`/`max` functions:
Bad:
```
score1 = 90
score2 = 99
highest_score = score1 if score1 > score2 else score2
```
Good:
```
score1 = 90
score2 = 99
highest_score = max(score1, score2)
```
"""
name = "use-min-max"
code = 136
categories = ("builtin", "logical", "readability")
FUNC_TABLE = {
"<": "min",
"<=": "min",
">": "max",
">=": "max",
}
def flip_comparison_oper(oper: str) -> str:
return {
"<": ">",
"<=": ">=",
">": "<",
">=": "<=",
}.get(oper, oper)
def check(node: ConditionalExpr, errors: list[Error]) -> None:
match node:
case ConditionalExpr(
if_expr=if_expr,
cond=ComparisonExpr(operators=[oper], operands=[lhs, rhs]),
else_expr=else_expr,
):
if (
is_equivalent(if_expr, lhs)
and is_equivalent(rhs, else_expr)
and (func := FUNC_TABLE.get(oper))
):
errors.append(
ErrorInfo.from_node(
node,
f"Replace `x if x {oper} y else y` with `{func}(x, y)`", # noqa: E501
)
)
if (
is_equivalent(if_expr, rhs)
and is_equivalent(lhs, else_expr)
and (func := FUNC_TABLE.get(flip_comparison_oper(oper)))
):
errors.append(
ErrorInfo.from_node(
node,
f"Replace `x if y {oper} x else y` with `{func}(y, x)`", # noqa: E501
)
)
|