diff --git a/refurb/checks/readability/use_str_func.py b/refurb/checks/readability/use_str_func.py index fe80625..d8d5c85 100644 --- a/refurb/checks/readability/use_str_func.py +++ b/refurb/checks/readability/use_str_func.py @@ -5,6 +5,7 @@ from refurb.checks.common import stringify from refurb.checks.string.use_fstring_fmt import CONVERSIONS as FURB_119_FUNCS from refurb.error import Error +from refurb.visitor import TraverserVisitor @dataclass @@ -36,6 +37,14 @@ class ErrorInfo(Error): ignore = set[int]() +# TODO: add support for returning False from check to indicate it shouldnt prapogate +class NestedFstringIgnorer(TraverserVisitor): + def visit_call_expr(self, o: CallExpr) -> None: + ignore.add(id(o)) + + super().visit_call_expr(o) + + def check(node: CallExpr, errors: list[Error]) -> None: if id(node) in ignore: return @@ -48,7 +57,10 @@ def check(node: CallExpr, errors: list[Error]) -> None: ), args=[ListExpr(items=items)], ): - ignore.update(id(item) for item in items) + visitor = NestedFstringIgnorer() + + for item in items: + visitor.accept(item) case CallExpr( callee=MemberExpr( @@ -66,3 +78,12 @@ def check(node: CallExpr, errors: list[Error]) -> None: msg = f'Replace `f"{{{x}}}"` with `str({x})`' errors.append(ErrorInfo.from_node(node, msg)) + + case CallExpr( + callee=MemberExpr( + expr=StrExpr(value="{:{}}"), + name="format", + ), + args=[_, arg], + ): + NestedFstringIgnorer().accept(arg) diff --git a/test/data/err_183.py b/test/data/err_183.py index 423d35d..9ab948f 100644 --- a/test/data/err_183.py +++ b/test/data/err_183.py @@ -10,3 +10,5 @@ f"hello{x}world" f"{x} {x}" + +f"{x:{x}}"