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
|
from dataclasses import dataclass
from mypy.nodes import CallExpr, IndexExpr, IntExpr, NameExpr, SliceExpr
from refurb.error import Error
@dataclass
class ErrorInfo(Error):
"""
The `bin()`, `oct()`, and `hex()` functions return the string
representation of a number but with a prefix attached. If you don't want
the prefix, you might be tempted to just slice it off, but using an
f-string will give you more flexibility and let you work with negative
numbers:
Bad:
```
print(bin(1337)[2:])
```
Good:
```
print(f"{1337:b}")
```
"""
name = "use-fstring-number-format"
code = 116
categories = ("builtin", "fstring")
FUNC_CONVERSIONS = {
"builtins.bin": "b",
"builtins.oct": "o",
"builtins.hex": "x",
}
def check(node: IndexExpr, errors: list[Error]) -> None:
match node:
case IndexExpr(
base=CallExpr(callee=NameExpr() as name_node),
index=SliceExpr(begin_index=IntExpr(value=2), end_index=None),
) if name_node.fullname in FUNC_CONVERSIONS:
format = FUNC_CONVERSIONS[name_node.fullname or ""]
fstring = f'f"{{num:{format}}}"'
errors.append(
ErrorInfo.from_node(
node,
f"Replace `{name_node.name}(num)[2:]` with `{fstring}`",
)
)
|