Skip to content

Commit

Permalink
Check f-string arguments for quotes/backslashes instead of _simple_arg
Browse files Browse the repository at this point in the history
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
  • Loading branch information
andersk committed Apr 6, 2021
1 parent 28641fa commit b59cb92
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 14 deletions.
18 changes: 4 additions & 14 deletions pyupgrade/_main.py
Expand Up @@ -510,18 +510,6 @@ def _fix_tokens(contents_text: str, min_version: Version) -> str:
return tokens_to_src(tokens).lstrip()


def _simple_arg(arg: ast.expr) -> bool:
return (
isinstance(arg, ast.Name) or
(isinstance(arg, ast.Attribute) and _simple_arg(arg.value)) or
(
isinstance(arg, ast.Call) and
_simple_arg(arg.func) and
not arg.args and not arg.keywords
)
)


def _format_params(call: ast.Call) -> Set[str]:
params = {str(i) for i, arg in enumerate(call.args)}
for kwd in call.keywords:
Expand Down Expand Up @@ -566,8 +554,6 @@ def _parse(self, node: ast.Call) -> Optional[Tuple[DotFormatPart, ...]]:
isinstance(node.func, ast.Attribute) and
isinstance(node.func.value, ast.Str) and
node.func.attr == 'format' and
all(_simple_arg(arg) for arg in node.args) and
all(_simple_arg(k.value) for k in node.keywords) and
not has_starargs(node)
):
return None
Expand Down Expand Up @@ -794,6 +780,10 @@ def _fix_py36_plus(contents_text: str) -> str:
if tokens[end - 1].line != token.line:
continue

args_src = tokens_to_src(tokens[paren:end])
if '\\' in args_src or '"' in args_src or "'" in args_src:
continue

tokens[i] = token._replace(
src=_to_fstring(token.src, tokens, args),
)
Expand Down
5 changes: 5 additions & 0 deletions tests/features/fstrings_test.py
Expand Up @@ -30,6 +30,10 @@
r'"\N{snowman} {}".format(a)',
# not enough placeholders / placeholders missing
'"{}{}".format(a)', '"{a}{b}".format(a=a)',
# backslashes and quotes cannot nest
r'''"{}".format(a['\\'])''',
'"{}".format(a["b"])',
"'{}'.format(a['b'])",
),
)
def test_fix_fstrings_noop(s):
Expand All @@ -50,6 +54,7 @@ def test_fix_fstrings_noop(s):
('"hello {}!".format(name)', 'f"hello {name}!"'),
('"{}{{}}{}".format(escaped, y)', 'f"{escaped}{{}}{y}"'),
('"{}{b}{}".format(a, c, b=b)', 'f"{a}{b}{c}"'),
('"{}".format(0x0)', 'f"{0x0}"'),
# TODO: poor man's f-strings?
# '"{foo}".format(**locals())'
),
Expand Down

0 comments on commit b59cb92

Please sign in to comment.