From aa0fe4698134bd3bd402e21bb02d5c8059b6333b Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 5 Jun 2017 18:37:59 +0100 Subject: [PATCH] convert f strings to concat --- py_backwards/transformers/formatted_values.py | 22 ++++++++++++++----- tests/transformers/test_formatted_values.py | 5 +++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/py_backwards/transformers/formatted_values.py b/py_backwards/transformers/formatted_values.py index 8620b47..f8f1481 100644 --- a/py_backwards/transformers/formatted_values.py +++ b/py_backwards/transformers/formatted_values.py @@ -1,3 +1,5 @@ +import functools + from typed_ast import ast3 as ast from ..const import TARGET_ALL from .base import BaseNodeTransformer @@ -7,7 +9,7 @@ class FormattedValuesTransformer(BaseNodeTransformer): """Compiles: f"hello {x}" To - ''.join(['hello ', '{}'.format(x)]) + 'hello ' + '{}'.format(x) """ target = TARGET_ALL @@ -28,9 +30,17 @@ def visit_FormattedValue(self, node: ast.FormattedValue) -> ast.Call: def visit_JoinedStr(self, node: ast.JoinedStr) -> ast.Call: self._tree_changed = True + NONE = ast.Str(s='') + + init = ast.BinOp(left=NONE, right=NONE, op=ast.Add()) + + def to_binop(acc, next): + left, right, op = acc.left, acc.right, acc.op + if left is NONE: + return ast.BinOp(left=right, right=next, op=op) + return ast.BinOp(left=acc, right=next, op=op) + + value = functools.reduce(to_binop, node.values, init) + concat_expr = ast.Expr(value=value) - join_call = ast.Call(func=ast.Attribute(value=ast.Str(s=''), - attr='join'), - args=[ast.List(elts=node.values)], - keywords=[]) - return self.generic_visit(join_call) # type: ignore + return self.generic_visit(concat_expr) # type: ignore diff --git a/tests/transformers/test_formatted_values.py b/tests/transformers/test_formatted_values.py index c4ea950..e025e52 100644 --- a/tests/transformers/test_formatted_values.py +++ b/tests/transformers/test_formatted_values.py @@ -4,9 +4,10 @@ @pytest.mark.parametrize('before, after', [ ("f'hi'", "'hi'"), - ("f'hi {x}'", "''.join(['hi ', '{}'.format(x)])"), + ("f'hi {x}'", "'hi ' + '{}'.format(x)"), + ("d = f'{a} {b}!'", "d = '{}'.format(a) + ' ' + '{}'.format(b) + '!'"), ("f'hi {x.upper()} {y:1}'", - "''.join(['hi ', '{}'.format(x.upper()), ' ', '{:1}'.format(y)])")]) + "'hi ' + '{}'.format(x.upper()) + ' ' + '{:1}'.format(y)")]) def test_transform(transform, ast, before, after): code = transform(FormattedValuesTransformer, before) assert ast(code) == ast(after)