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
|
from dataclasses import dataclass
from mypy.nodes import CallExpr, MemberExpr, NameExpr, StrExpr
from refurb.error import Error
@dataclass
class ErrorInfo(Error):
"""
Certain expressions which are passed to f-strings are redundant because
the f-string itself is capable of formatting it. For example:
Bad:
```
print(f"{bin(1337)}")
print(f"{ascii(input())}")
print(f"{str(123)}")
```
Good:
```
print(f"{1337:#b}")
print(f"{input()!a}")
print(f"{123}")
```
"""
name = "use-fstring-format"
code = 119
categories = ("builtin", "fstring")
CONVERSIONS = {
"builtins.str": "x",
"builtins.repr": "x!r",
"builtins.ascii": "x!a",
"builtins.bin": "x:#b",
"builtins.oct": "x:#o",
"builtins.hex": "x:#x",
"builtins.chr": "x:c",
"builtins.format": "x",
}
def check(node: CallExpr, errors: list[Error]) -> None:
match node:
case CallExpr(
callee=MemberExpr(expr=StrExpr(value="{:{}}"), name="format"),
args=[inner, _],
):
match inner:
case CallExpr(
callee=NameExpr(fullname=fullname) as func,
args=[_],
) if fullname in CONVERSIONS:
func_name = f"{{{func.name}(x)}}"
conversion = f"{{{CONVERSIONS[fullname or '']}}}" # noqa: FURB143, E501
errors.append(
ErrorInfo.from_node(node, f"Replace `{func_name}` with `{conversion}`")
)
|