diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 26908b9ac399..1c7aa79279c4 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -850,6 +850,26 @@ def visit_Str(self, n: ast3.Str) -> Union[UnicodeExpr, StrExpr]: else: return UnicodeExpr(n.s) + # Only available with typed_ast >= 0.6.2 + if hasattr(ast3, 'JoinedStr'): + # JoinedStr(expr* values) + @with_line + def visit_JoinedStr(self, n: ast3.JoinedStr) -> Expression: + result_expression = StrExpr('') # type: Expression + for value_expr in self.translate_expr_list(n.values): + string_method = MemberExpr(value_expr, '__str__') + string_method.set_line(value_expr) + stringified_value_expr = CallExpr(string_method, [], []) + stringified_value_expr.set_line(value_expr) + result_expression = OpExpr('+', result_expression, stringified_value_expr) + result_expression.set_line(value_expr) + return result_expression + + # FormattedValue(expr value) + @with_line + def visit_FormattedValue(self, n: ast3.FormattedValue) -> Expression: + return self.visit(n.value) + # Bytes(bytes s) @with_line def visit_Bytes(self, n: ast3.Bytes) -> Union[BytesExpr, StrExpr]: diff --git a/test-data/unit/check-newsyntax.test b/test-data/unit/check-newsyntax.test index da86ac5157f9..331ad776c1c8 100644 --- a/test-data/unit/check-newsyntax.test +++ b/test-data/unit/check-newsyntax.test @@ -99,11 +99,46 @@ main:4: error: Unsupported target for indexed assignment main:5: error: Type cannot be declared in assignment to non-self attribute main:5: error: "str" has no attribute "x" -[case testNewSyntaxFstringError] -# flags: --fast-parser --python-version 3.5 -f'' # E: Format strings are only supported in Python 3.6 and greater - [case testNewSyntaxAsyncComprehensionError] # flags: --fast-parser --python-version 3.5 async def f(): results = [i async for i in aiter() if i % 2] # E: Async comprehensions are only supported in Python 3.6 and greater + + +[case testNewSyntaxFstringError] +# flags: --fast-parser --python-version 3.5 +f'' # E: Format strings are only supported in Python 3.6 and greater + +[case testNewSyntaxFStringBasics] +# flags: --fast-parser --python-version 3.6 +f'foobar' +f'{"foobar"}' +f'foo{"bar"}' +f'.{1}.' +a: str +a = f'foobar' +a = f'{"foobar"}' +[builtins fixtures/primitives.pyi] + +[case testNewSyntaxFStringExpressionsOk] +# flags: --fast-parser --python-version 3.6 +f'.{1 + 1}.' +f'.{1 + 1}.{"foo" + "bar"}' +[builtins fixtures/primitives.pyi] + +[case testNewSyntaxFStringExpressionsErrors] +# flags: --fast-parser --python-version 3.6 +f'{1 + ""}' +f'.{1 + ""}' +[builtins fixtures/primitives.pyi] +[out] +main:2: error: Unsupported operand types for + ("int" and "str") +main:3: error: Unsupported operand types for + ("int" and "str") + +[case testNewSyntaxFStringParseFormatOptions] +# flags: --fast-parser --python-version 3.6 +value = 10.5142 +width = 10 +precision = 4 +f'result: {value:{width}.{precision}}' +[builtins fixtures/primitives.pyi] diff --git a/test-data/unit/fixtures/primitives.pyi b/test-data/unit/fixtures/primitives.pyi index b6ec4d4a62d7..cb43d926e553 100644 --- a/test-data/unit/fixtures/primitives.pyi +++ b/test-data/unit/fixtures/primitives.pyi @@ -2,15 +2,18 @@ class object: def __init__(self) -> None: pass + def __str__(self) -> str: pass class type: def __init__(self, x) -> None: pass -class int: pass +class int: + def __add__(self, i: int) -> int: pass class float: pass class complex: pass class bool: pass -class str: pass +class str: + def __add__(self, s: str) -> str: pass class bytes: pass class bytearray: pass class tuple: pass