Skip to content

Commit e62ae02

Browse files
committed
Use value field to generate code when None in str field of ast.Interpolation
1 parent 58c8c1a commit e62ae02

File tree

2 files changed

+86
-3
lines changed

2 files changed

+86
-3
lines changed

Lib/_ast_unparse.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -658,9 +658,9 @@ def _unparse_interpolation_value(self, inner):
658658
unparser.set_precedence(_Precedence.TEST.next(), inner)
659659
return unparser.visit(inner)
660660

661-
def _write_interpolation(self, node, is_interpolation=False):
661+
def _write_interpolation(self, node, use_str_attr=False):
662662
with self.delimit("{", "}"):
663-
if is_interpolation:
663+
if use_str_attr:
664664
expr = node.str
665665
else:
666666
expr = self._unparse_interpolation_value(node.value)
@@ -678,7 +678,8 @@ def visit_FormattedValue(self, node):
678678
self._write_interpolation(node)
679679

680680
def visit_Interpolation(self, node):
681-
self._write_interpolation(node, is_interpolation=True)
681+
# If `str` is set to `None`, use the `value` to generate the source code.
682+
self._write_interpolation(node, use_str_attr=node.str is not None)
682683

683684
def visit_Name(self, node):
684685
self.write(node.id)

Lib/test/test_unparse.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,88 @@ def test_tstrings(self):
215215
self.check_ast_roundtrip("t''")
216216
self.check_ast_roundtrip('t""')
217217
self.check_ast_roundtrip("t'{(lambda x: x)}'")
218+
self.check_ast_roundtrip("t'{t'{x}'}'")
219+
220+
def test_tstring_with_nonsensical_str_field(self):
221+
# `value` suggests that the original code is `t'{test1}`, but `str` suggests otherwise
222+
self.assertEqual(
223+
ast.unparse(
224+
ast.TemplateStr(
225+
values=[
226+
ast.Interpolation(
227+
value=ast.Name(id="test1", ctx=ast.Load()), str="test2", conversion=-1
228+
)
229+
]
230+
)
231+
),
232+
"t'{test2}'",
233+
)
234+
235+
def test_tstring_with_none_str_field(self):
236+
self.assertEqual(
237+
ast.unparse(
238+
ast.TemplateStr(
239+
[ast.Interpolation(value=ast.Name(id="test1"), str=None, conversion=-1)]
240+
)
241+
),
242+
"t'{test1}'",
243+
)
244+
self.assertEqual(
245+
ast.unparse(
246+
ast.TemplateStr(
247+
[
248+
ast.Interpolation(
249+
value=ast.Lambda(
250+
args=ast.arguments(args=[ast.arg(arg="x")]),
251+
body=ast.Name(id="x"),
252+
),
253+
str=None,
254+
conversion=-1,
255+
)
256+
]
257+
)
258+
),
259+
"t'{(lambda x: x)}'",
260+
)
261+
self.assertEqual(
262+
ast.unparse(
263+
ast.TemplateStr(
264+
values=[
265+
ast.Interpolation(
266+
value=ast.TemplateStr(
267+
# `str` field kept here
268+
[ast.Interpolation(value=ast.Name(id="x"), str="y", conversion=-1)]
269+
),
270+
str=None,
271+
conversion=-1,
272+
)
273+
]
274+
)
275+
),
276+
'''t"{t'{y}'}"''',
277+
)
278+
self.assertEqual(
279+
ast.unparse(
280+
ast.TemplateStr(
281+
values=[
282+
ast.Interpolation(
283+
value=ast.TemplateStr(
284+
[ast.Interpolation(value=ast.Name(id="x"), str=None, conversion=-1)]
285+
),
286+
str=None,
287+
conversion=-1,
288+
)
289+
]
290+
)
291+
),
292+
'''t"{t'{x}'}"''',
293+
)
294+
self.assertEqual(
295+
ast.unparse(ast.TemplateStr(
296+
[ast.Interpolation(value=ast.Constant(value="foo"), str=None, conversion=114)]
297+
)),
298+
'''t"{'foo'!r}"''',
299+
)
218300

219301
def test_strings(self):
220302
self.check_ast_roundtrip("u'foo'")

0 commit comments

Comments
 (0)