blob: 5e7efe25e39ccc4cb2dc16b3e4847cb045ca4c66 [file] [log] [blame]
Eric V. Smith235a6f02015-09-19 14:51:32 -04001import ast
2import types
3import decimal
4import unittest
5
6a_global = 'global variable'
7
8# You could argue that I'm too strict in looking for specific error
9# values with assertRaisesRegex, but without it it's way too easy to
10# make a syntax error in the test strings. Especially with all of the
11# triple quotes, raw strings, backslashes, etc. I think it's a
12# worthwhile tradeoff. When I switched to this method, I found many
13# examples where I wasn't testing what I thought I was.
14
15class TestCase(unittest.TestCase):
16 def assertAllRaise(self, exception_type, regex, error_strings):
17 for str in error_strings:
18 with self.subTest(str=str):
19 with self.assertRaisesRegex(exception_type, regex):
20 eval(str)
21
22 def test__format__lookup(self):
23 # Make sure __format__ is looked up on the type, not the instance.
24 class X:
25 def __format__(self, spec):
26 return 'class'
27
28 x = X()
29
30 # Add a bound __format__ method to the 'y' instance, but not
31 # the 'x' instance.
32 y = X()
33 y.__format__ = types.MethodType(lambda self, spec: 'instance', y)
34
35 self.assertEqual(f'{y}', format(y))
36 self.assertEqual(f'{y}', 'class')
37 self.assertEqual(format(x), format(y))
38
39 # __format__ is not called this way, but still make sure it
40 # returns what we expect (so we can make sure we're bypassing
41 # it).
42 self.assertEqual(x.__format__(''), 'class')
43 self.assertEqual(y.__format__(''), 'instance')
44
45 # This is how __format__ is actually called.
46 self.assertEqual(type(x).__format__(x, ''), 'class')
47 self.assertEqual(type(y).__format__(y, ''), 'class')
48
49 def test_ast(self):
50 # Inspired by http://bugs.python.org/issue24975
51 class X:
52 def __init__(self):
53 self.called = False
54 def __call__(self):
55 self.called = True
56 return 4
57 x = X()
58 expr = """
59a = 10
60f'{a * x()}'"""
61 t = ast.parse(expr)
62 c = compile(t, '', 'exec')
63
64 # Make sure x was not called.
65 self.assertFalse(x.called)
66
67 # Actually run the code.
68 exec(c)
69
70 # Make sure x was called.
71 self.assertTrue(x.called)
72
Łukasz Langae7c566c2017-09-06 17:27:58 -070073 def test_ast_line_numbers(self):
74 expr = """
75a = 10
76f'{a * x()}'"""
77 t = ast.parse(expr)
78 self.assertEqual(type(t), ast.Module)
79 self.assertEqual(len(t.body), 2)
80 # check `a = 10`
81 self.assertEqual(type(t.body[0]), ast.Assign)
82 self.assertEqual(t.body[0].lineno, 2)
83 # check `f'...'`
84 self.assertEqual(type(t.body[1]), ast.Expr)
85 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
86 self.assertEqual(len(t.body[1].value.values), 1)
87 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
88 self.assertEqual(t.body[1].lineno, 3)
89 self.assertEqual(t.body[1].value.lineno, 3)
90 self.assertEqual(t.body[1].value.values[0].lineno, 3)
91 # check the binop location
92 binop = t.body[1].value.values[0].value
93 self.assertEqual(type(binop), ast.BinOp)
94 self.assertEqual(type(binop.left), ast.Name)
95 self.assertEqual(type(binop.op), ast.Mult)
96 self.assertEqual(type(binop.right), ast.Call)
97 self.assertEqual(binop.lineno, 3)
98 self.assertEqual(binop.left.lineno, 3)
99 self.assertEqual(binop.right.lineno, 3)
100 self.assertEqual(binop.col_offset, 3)
101 self.assertEqual(binop.left.col_offset, 3)
102 self.assertEqual(binop.right.col_offset, 7)
103
104 def test_ast_line_numbers_multiple_formattedvalues(self):
105 expr = """
106f'no formatted values'
107f'eggs {a * x()} spam {b + y()}'"""
108 t = ast.parse(expr)
109 self.assertEqual(type(t), ast.Module)
110 self.assertEqual(len(t.body), 2)
111 # check `f'no formatted value'`
112 self.assertEqual(type(t.body[0]), ast.Expr)
113 self.assertEqual(type(t.body[0].value), ast.JoinedStr)
114 self.assertEqual(t.body[0].lineno, 2)
115 # check `f'...'`
116 self.assertEqual(type(t.body[1]), ast.Expr)
117 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
118 self.assertEqual(len(t.body[1].value.values), 4)
119 self.assertEqual(type(t.body[1].value.values[0]), ast.Str)
120 self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
121 self.assertEqual(type(t.body[1].value.values[2]), ast.Str)
122 self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue)
123 self.assertEqual(t.body[1].lineno, 3)
124 self.assertEqual(t.body[1].value.lineno, 3)
125 self.assertEqual(t.body[1].value.values[0].lineno, 3)
126 self.assertEqual(t.body[1].value.values[1].lineno, 3)
127 self.assertEqual(t.body[1].value.values[2].lineno, 3)
128 self.assertEqual(t.body[1].value.values[3].lineno, 3)
129 # check the first binop location
130 binop1 = t.body[1].value.values[1].value
131 self.assertEqual(type(binop1), ast.BinOp)
132 self.assertEqual(type(binop1.left), ast.Name)
133 self.assertEqual(type(binop1.op), ast.Mult)
134 self.assertEqual(type(binop1.right), ast.Call)
135 self.assertEqual(binop1.lineno, 3)
136 self.assertEqual(binop1.left.lineno, 3)
137 self.assertEqual(binop1.right.lineno, 3)
138 self.assertEqual(binop1.col_offset, 8)
139 self.assertEqual(binop1.left.col_offset, 8)
140 self.assertEqual(binop1.right.col_offset, 12)
141 # check the second binop location
142 binop2 = t.body[1].value.values[3].value
143 self.assertEqual(type(binop2), ast.BinOp)
144 self.assertEqual(type(binop2.left), ast.Name)
145 self.assertEqual(type(binop2.op), ast.Add)
146 self.assertEqual(type(binop2.right), ast.Call)
147 self.assertEqual(binop2.lineno, 3)
148 self.assertEqual(binop2.left.lineno, 3)
149 self.assertEqual(binop2.right.lineno, 3)
150 self.assertEqual(binop2.col_offset, 23)
151 self.assertEqual(binop2.left.col_offset, 23)
152 self.assertEqual(binop2.right.col_offset, 27)
153
154 def test_ast_line_numbers_nested(self):
155 expr = """
156a = 10
157f'{a * f"-{x()}-"}'"""
158 t = ast.parse(expr)
159 self.assertEqual(type(t), ast.Module)
160 self.assertEqual(len(t.body), 2)
161 # check `a = 10`
162 self.assertEqual(type(t.body[0]), ast.Assign)
163 self.assertEqual(t.body[0].lineno, 2)
164 # check `f'...'`
165 self.assertEqual(type(t.body[1]), ast.Expr)
166 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
167 self.assertEqual(len(t.body[1].value.values), 1)
168 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
169 self.assertEqual(t.body[1].lineno, 3)
170 self.assertEqual(t.body[1].value.lineno, 3)
171 self.assertEqual(t.body[1].value.values[0].lineno, 3)
172 # check the binop location
173 binop = t.body[1].value.values[0].value
174 self.assertEqual(type(binop), ast.BinOp)
175 self.assertEqual(type(binop.left), ast.Name)
176 self.assertEqual(type(binop.op), ast.Mult)
177 self.assertEqual(type(binop.right), ast.JoinedStr)
178 self.assertEqual(binop.lineno, 3)
179 self.assertEqual(binop.left.lineno, 3)
180 self.assertEqual(binop.right.lineno, 3)
181 self.assertEqual(binop.col_offset, 3)
182 self.assertEqual(binop.left.col_offset, 3)
183 self.assertEqual(binop.right.col_offset, 7)
184 # check the nested call location
185 self.assertEqual(len(binop.right.values), 3)
186 self.assertEqual(type(binop.right.values[0]), ast.Str)
187 self.assertEqual(type(binop.right.values[1]), ast.FormattedValue)
188 self.assertEqual(type(binop.right.values[2]), ast.Str)
189 self.assertEqual(binop.right.values[0].lineno, 3)
190 self.assertEqual(binop.right.values[1].lineno, 3)
191 self.assertEqual(binop.right.values[2].lineno, 3)
192 call = binop.right.values[1].value
193 self.assertEqual(type(call), ast.Call)
194 self.assertEqual(call.lineno, 3)
195 self.assertEqual(call.col_offset, 11)
196
197 def test_ast_line_numbers_duplicate_expression(self):
198 """Duplicate expression
199
200 NOTE: this is currently broken, always sets location of the first
201 expression.
202 """
203 expr = """
204a = 10
205f'{a * x()} {a * x()} {a * x()}'
206"""
207 t = ast.parse(expr)
208 self.assertEqual(type(t), ast.Module)
209 self.assertEqual(len(t.body), 2)
210 # check `a = 10`
211 self.assertEqual(type(t.body[0]), ast.Assign)
212 self.assertEqual(t.body[0].lineno, 2)
213 # check `f'...'`
214 self.assertEqual(type(t.body[1]), ast.Expr)
215 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
216 self.assertEqual(len(t.body[1].value.values), 5)
217 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
218 self.assertEqual(type(t.body[1].value.values[1]), ast.Str)
219 self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue)
220 self.assertEqual(type(t.body[1].value.values[3]), ast.Str)
221 self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue)
222 self.assertEqual(t.body[1].lineno, 3)
223 self.assertEqual(t.body[1].value.lineno, 3)
224 self.assertEqual(t.body[1].value.values[0].lineno, 3)
225 self.assertEqual(t.body[1].value.values[1].lineno, 3)
226 self.assertEqual(t.body[1].value.values[2].lineno, 3)
227 self.assertEqual(t.body[1].value.values[3].lineno, 3)
228 self.assertEqual(t.body[1].value.values[4].lineno, 3)
229 # check the first binop location
230 binop = t.body[1].value.values[0].value
231 self.assertEqual(type(binop), ast.BinOp)
232 self.assertEqual(type(binop.left), ast.Name)
233 self.assertEqual(type(binop.op), ast.Mult)
234 self.assertEqual(type(binop.right), ast.Call)
235 self.assertEqual(binop.lineno, 3)
236 self.assertEqual(binop.left.lineno, 3)
237 self.assertEqual(binop.right.lineno, 3)
238 self.assertEqual(binop.col_offset, 3)
239 self.assertEqual(binop.left.col_offset, 3)
240 self.assertEqual(binop.right.col_offset, 7)
241 # check the second binop location
242 binop = t.body[1].value.values[2].value
243 self.assertEqual(type(binop), ast.BinOp)
244 self.assertEqual(type(binop.left), ast.Name)
245 self.assertEqual(type(binop.op), ast.Mult)
246 self.assertEqual(type(binop.right), ast.Call)
247 self.assertEqual(binop.lineno, 3)
248 self.assertEqual(binop.left.lineno, 3)
249 self.assertEqual(binop.right.lineno, 3)
250 self.assertEqual(binop.col_offset, 3) # FIXME: this is wrong
251 self.assertEqual(binop.left.col_offset, 3) # FIXME: this is wrong
252 self.assertEqual(binop.right.col_offset, 7) # FIXME: this is wrong
253 # check the third binop location
254 binop = t.body[1].value.values[4].value
255 self.assertEqual(type(binop), ast.BinOp)
256 self.assertEqual(type(binop.left), ast.Name)
257 self.assertEqual(type(binop.op), ast.Mult)
258 self.assertEqual(type(binop.right), ast.Call)
259 self.assertEqual(binop.lineno, 3)
260 self.assertEqual(binop.left.lineno, 3)
261 self.assertEqual(binop.right.lineno, 3)
262 self.assertEqual(binop.col_offset, 3) # FIXME: this is wrong
263 self.assertEqual(binop.left.col_offset, 3) # FIXME: this is wrong
264 self.assertEqual(binop.right.col_offset, 7) # FIXME: this is wrong
265
266 def test_ast_line_numbers_multiline_fstring(self):
267 # FIXME: This test demonstrates invalid behavior due to JoinedStr's
268 # immediate child nodes containing the wrong lineno. The enclosed
269 # expressions have valid line information and column offsets.
270 # See bpo-16806 and bpo-30465 for details.
271 expr = """
272a = 10
273f'''
274 {a
275 *
276 x()}
277non-important content
278'''
279"""
280 t = ast.parse(expr)
281 self.assertEqual(type(t), ast.Module)
282 self.assertEqual(len(t.body), 2)
283 # check `a = 10`
284 self.assertEqual(type(t.body[0]), ast.Assign)
285 self.assertEqual(t.body[0].lineno, 2)
286 # check `f'...'`
287 self.assertEqual(type(t.body[1]), ast.Expr)
288 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
289 self.assertEqual(len(t.body[1].value.values), 3)
290 self.assertEqual(type(t.body[1].value.values[0]), ast.Str)
291 self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
292 self.assertEqual(type(t.body[1].value.values[2]), ast.Str)
293 # NOTE: the following invalid behavior is described in bpo-16806.
294 # - line number should be the *first* line (3), not the *last* (8)
295 # - column offset should not be -1
296 self.assertEqual(t.body[1].lineno, 8)
297 self.assertEqual(t.body[1].value.lineno, 8)
298 self.assertEqual(t.body[1].value.values[0].lineno, 8)
299 self.assertEqual(t.body[1].value.values[1].lineno, 8)
300 self.assertEqual(t.body[1].value.values[2].lineno, 8)
301 self.assertEqual(t.body[1].col_offset, -1)
302 self.assertEqual(t.body[1].value.col_offset, -1)
303 self.assertEqual(t.body[1].value.values[0].col_offset, -1)
304 self.assertEqual(t.body[1].value.values[1].col_offset, -1)
305 self.assertEqual(t.body[1].value.values[2].col_offset, -1)
306 # NOTE: the following lineno information and col_offset is correct for
307 # expressions within FormattedValues.
308 binop = t.body[1].value.values[1].value
309 self.assertEqual(type(binop), ast.BinOp)
310 self.assertEqual(type(binop.left), ast.Name)
311 self.assertEqual(type(binop.op), ast.Mult)
312 self.assertEqual(type(binop.right), ast.Call)
313 self.assertEqual(binop.lineno, 4)
314 self.assertEqual(binop.left.lineno, 4)
315 self.assertEqual(binop.right.lineno, 6)
316 self.assertEqual(binop.col_offset, 3)
317 self.assertEqual(binop.left.col_offset, 3)
318 self.assertEqual(binop.right.col_offset, 7)
319
Serhiy Storchaka4cc30ae2016-12-11 19:37:19 +0200320 def test_docstring(self):
321 def f():
322 f'''Not a docstring'''
323 self.assertIsNone(f.__doc__)
324 def g():
325 '''Not a docstring''' \
326 f''
327 self.assertIsNone(g.__doc__)
328
Eric V. Smith235a6f02015-09-19 14:51:32 -0400329 def test_literal_eval(self):
Eric V. Smith235a6f02015-09-19 14:51:32 -0400330 with self.assertRaisesRegex(ValueError, 'malformed node or string'):
Serhiy Storchaka4cc30ae2016-12-11 19:37:19 +0200331 ast.literal_eval("f'x'")
Eric V. Smith235a6f02015-09-19 14:51:32 -0400332
333 def test_ast_compile_time_concat(self):
334 x = ['']
335
336 expr = """x[0] = 'foo' f'{3}'"""
337 t = ast.parse(expr)
338 c = compile(t, '', 'exec')
339 exec(c)
340 self.assertEqual(x[0], 'foo3')
341
Eric V. Smith9b88fdf2016-11-07 17:54:01 -0500342 def test_compile_time_concat_errors(self):
343 self.assertAllRaise(SyntaxError,
344 'cannot mix bytes and nonbytes literals',
345 [r"""f'' b''""",
346 r"""b'' f''""",
347 ])
348
Eric V. Smith235a6f02015-09-19 14:51:32 -0400349 def test_literal(self):
350 self.assertEqual(f'', '')
351 self.assertEqual(f'a', 'a')
352 self.assertEqual(f' ', ' ')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400353
354 def test_unterminated_string(self):
355 self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
356 [r"""f'{"x'""",
357 r"""f'{"x}'""",
358 r"""f'{("x'""",
359 r"""f'{("x}'""",
360 ])
361
362 def test_mismatched_parens(self):
363 self.assertAllRaise(SyntaxError, 'f-string: mismatched',
364 ["f'{((}'",
365 ])
366
367 def test_double_braces(self):
368 self.assertEqual(f'{{', '{')
369 self.assertEqual(f'a{{', 'a{')
370 self.assertEqual(f'{{b', '{b')
371 self.assertEqual(f'a{{b', 'a{b')
372 self.assertEqual(f'}}', '}')
373 self.assertEqual(f'a}}', 'a}')
374 self.assertEqual(f'}}b', '}b')
375 self.assertEqual(f'a}}b', 'a}b')
Eric V. Smith451d0e32016-09-09 21:56:20 -0400376 self.assertEqual(f'{{}}', '{}')
377 self.assertEqual(f'a{{}}', 'a{}')
378 self.assertEqual(f'{{b}}', '{b}')
379 self.assertEqual(f'{{}}c', '{}c')
380 self.assertEqual(f'a{{b}}', 'a{b}')
381 self.assertEqual(f'a{{}}c', 'a{}c')
382 self.assertEqual(f'{{b}}c', '{b}c')
383 self.assertEqual(f'a{{b}}c', 'a{b}c')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400384
385 self.assertEqual(f'{{{10}', '{10')
386 self.assertEqual(f'}}{10}', '}10')
387 self.assertEqual(f'}}{{{10}', '}{10')
388 self.assertEqual(f'}}a{{{10}', '}a{10')
389
390 self.assertEqual(f'{10}{{', '10{')
391 self.assertEqual(f'{10}}}', '10}')
392 self.assertEqual(f'{10}}}{{', '10}{')
393 self.assertEqual(f'{10}}}a{{' '}', '10}a{}')
394
395 # Inside of strings, don't interpret doubled brackets.
396 self.assertEqual(f'{"{{}}"}', '{{}}')
397
398 self.assertAllRaise(TypeError, 'unhashable type',
399 ["f'{ {{}} }'", # dict in a set
400 ])
401
402 def test_compile_time_concat(self):
403 x = 'def'
404 self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
405 self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi')
406 self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ')
407 self.assertEqual('{x}' f'{x}', '{x}def')
408 self.assertEqual('{x' f'{x}', '{xdef')
409 self.assertEqual('{x}' f'{x}', '{x}def')
410 self.assertEqual('{{x}}' f'{x}', '{{x}}def')
411 self.assertEqual('{{x' f'{x}', '{{xdef')
412 self.assertEqual('x}}' f'{x}', 'x}}def')
413 self.assertEqual(f'{x}' 'x}}', 'defx}}')
414 self.assertEqual(f'{x}' '', 'def')
415 self.assertEqual('' f'{x}' '', 'def')
416 self.assertEqual('' f'{x}', 'def')
417 self.assertEqual(f'{x}' '2', 'def2')
418 self.assertEqual('1' f'{x}' '2', '1def2')
419 self.assertEqual('1' f'{x}', '1def')
420 self.assertEqual(f'{x}' f'-{x}', 'def-def')
421 self.assertEqual('' f'', '')
422 self.assertEqual('' f'' '', '')
423 self.assertEqual('' f'' '' f'', '')
424 self.assertEqual(f'', '')
425 self.assertEqual(f'' '', '')
426 self.assertEqual(f'' '' f'', '')
427 self.assertEqual(f'' '' f'' '', '')
428
429 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
430 ["f'{3' f'}'", # can't concat to get a valid f-string
431 ])
432
433 def test_comments(self):
434 # These aren't comments, since they're in strings.
435 d = {'#': 'hash'}
436 self.assertEqual(f'{"#"}', '#')
437 self.assertEqual(f'{d["#"]}', 'hash')
438
Eric V. Smith09835dc2016-09-11 18:58:20 -0400439 self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400440 ["f'{1#}'", # error because the expression becomes "(1#)"
441 "f'{3(#)}'",
Eric V. Smith09835dc2016-09-11 18:58:20 -0400442 "f'{#}'",
Eric V. Smith35a24c52016-09-11 19:01:22 -0400443 "f'{)#}'", # When wrapped in parens, this becomes
444 # '()#)'. Make sure that doesn't compile.
Eric V. Smith235a6f02015-09-19 14:51:32 -0400445 ])
446
447 def test_many_expressions(self):
448 # Create a string with many expressions in it. Note that
449 # because we have a space in here as a literal, we're actually
450 # going to use twice as many ast nodes: one for each literal
451 # plus one for each expression.
452 def build_fstr(n, extra=''):
453 return "f'" + ('{x} ' * n) + extra + "'"
454
455 x = 'X'
456 width = 1
457
458 # Test around 256.
459 for i in range(250, 260):
460 self.assertEqual(eval(build_fstr(i)), (x+' ')*i)
461
462 # Test concatenating 2 largs fstrings.
463 self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256))
464
465 s = build_fstr(253, '{x:{width}} ')
466 self.assertEqual(eval(s), (x+' ')*254)
467
468 # Test lots of expressions and constants, concatenated.
469 s = "f'{1}' 'x' 'y'" * 1024
470 self.assertEqual(eval(s), '1xy' * 1024)
471
472 def test_format_specifier_expressions(self):
473 width = 10
474 precision = 4
475 value = decimal.Decimal('12.34567')
476 self.assertEqual(f'result: {value:{width}.{precision}}', 'result: 12.35')
477 self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result: 12.35')
478 self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result: 12.35')
479 self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result: 12.35')
480 self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result: 12.35')
481 self.assertEqual(f'{10:#{1}0x}', ' 0xa')
482 self.assertEqual(f'{10:{"#"}1{0}{"x"}}', ' 0xa')
483 self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa')
484 self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa')
485 self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa')
486
487 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
488 ["""f'{"s"!r{":10"}}'""",
489
490 # This looks like a nested format spec.
491 ])
492
493 self.assertAllRaise(SyntaxError, "invalid syntax",
Martin Panter263893c2016-07-28 01:25:31 +0000494 [# Invalid syntax inside a nested spec.
Eric V. Smith235a6f02015-09-19 14:51:32 -0400495 "f'{4:{/5}}'",
496 ])
497
498 self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
499 [# Can't nest format specifiers.
500 "f'result: {value:{width:{0}}.{precision:1}}'",
501 ])
502
503 self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
504 [# No expansion inside conversion or for
505 # the : or ! itself.
506 """f'{"s"!{"r"}}'""",
507 ])
508
509 def test_side_effect_order(self):
510 class X:
511 def __init__(self):
512 self.i = 0
513 def __format__(self, spec):
514 self.i += 1
515 return str(self.i)
516
517 x = X()
518 self.assertEqual(f'{x} {x}', '1 2')
519
520 def test_missing_expression(self):
521 self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
522 ["f'{}'",
523 "f'{ }'"
524 "f' {} '",
525 "f'{!r}'",
526 "f'{ !r}'",
527 "f'{10:{ }}'",
528 "f' { } '",
Eric V. Smith1d44c412015-09-23 07:49:00 -0400529
Serhiy Storchaka2e9cd582017-06-08 23:43:54 +0300530 # The Python parser ignores also the following
531 # whitespace characters in additional to a space.
532 "f'''{\t\f\r\n}'''",
533
Eric V. Smith1d44c412015-09-23 07:49:00 -0400534 # Catch the empty expression before the
535 # invalid conversion.
536 "f'{!x}'",
537 "f'{ !xr}'",
538 "f'{!x:}'",
539 "f'{!x:a}'",
540 "f'{ !xr:}'",
541 "f'{ !xr:a}'",
Eric V. Smith548c4d32015-09-23 08:00:01 -0400542
543 "f'{!}'",
544 "f'{:}'",
Eric V. Smithb2080f62015-09-23 10:24:43 -0400545
546 # We find the empty expression before the
547 # missing closing brace.
548 "f'{!'",
549 "f'{!s:'",
550 "f'{:'",
551 "f'{:x'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400552 ])
553
Serhiy Storchaka2e9cd582017-06-08 23:43:54 +0300554 # Different error message is raised for other whitespace characters.
555 self.assertAllRaise(SyntaxError, 'invalid character in identifier',
556 ["f'''{\xa0}'''",
557 "\xa0",
558 ])
559
Eric V. Smith235a6f02015-09-19 14:51:32 -0400560 def test_parens_in_expressions(self):
561 self.assertEqual(f'{3,}', '(3,)')
562
563 # Add these because when an expression is evaluated, parens
564 # are added around it. But we shouldn't go from an invalid
565 # expression to a valid one. The added parens are just
566 # supposed to allow whitespace (including newlines).
567 self.assertAllRaise(SyntaxError, 'invalid syntax',
568 ["f'{,}'",
569 "f'{,}'", # this is (,), which is an error
570 ])
571
572 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
573 ["f'{3)+(4}'",
574 ])
575
576 self.assertAllRaise(SyntaxError, 'EOL while scanning string literal',
577 ["f'{\n}'",
578 ])
579
Eric V. Smith451d0e32016-09-09 21:56:20 -0400580 def test_backslashes_in_string_part(self):
581 self.assertEqual(f'\t', '\t')
582 self.assertEqual(r'\t', '\\t')
583 self.assertEqual(rf'\t', '\\t')
584 self.assertEqual(f'{2}\t', '2\t')
585 self.assertEqual(f'{2}\t{3}', '2\t3')
586 self.assertEqual(f'\t{3}', '\t3')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400587
Eric V. Smith451d0e32016-09-09 21:56:20 -0400588 self.assertEqual(f'\u0394', '\u0394')
589 self.assertEqual(r'\u0394', '\\u0394')
590 self.assertEqual(rf'\u0394', '\\u0394')
591 self.assertEqual(f'{2}\u0394', '2\u0394')
592 self.assertEqual(f'{2}\u0394{3}', '2\u03943')
593 self.assertEqual(f'\u0394{3}', '\u03943')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400594
Eric V. Smith451d0e32016-09-09 21:56:20 -0400595 self.assertEqual(f'\U00000394', '\u0394')
596 self.assertEqual(r'\U00000394', '\\U00000394')
597 self.assertEqual(rf'\U00000394', '\\U00000394')
598 self.assertEqual(f'{2}\U00000394', '2\u0394')
599 self.assertEqual(f'{2}\U00000394{3}', '2\u03943')
600 self.assertEqual(f'\U00000394{3}', '\u03943')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400601
Eric V. Smith451d0e32016-09-09 21:56:20 -0400602 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394')
603 self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
604 self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943')
605 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943')
606 self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
607 self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943')
608 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400609
Eric V. Smith451d0e32016-09-09 21:56:20 -0400610 self.assertEqual(f'\x20', ' ')
611 self.assertEqual(r'\x20', '\\x20')
612 self.assertEqual(rf'\x20', '\\x20')
613 self.assertEqual(f'{2}\x20', '2 ')
614 self.assertEqual(f'{2}\x20{3}', '2 3')
615 self.assertEqual(f'\x20{3}', ' 3')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400616
Eric V. Smith451d0e32016-09-09 21:56:20 -0400617 self.assertEqual(f'2\x20', '2 ')
618 self.assertEqual(f'2\x203', '2 3')
619 self.assertEqual(f'\x203', ' 3')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400620
Serhiy Storchaka0cd7a3f2017-05-25 13:33:55 +0300621 with self.assertWarns(DeprecationWarning): # invalid escape sequence
622 value = eval(r"f'\{6*7}'")
623 self.assertEqual(value, '\\42')
624 self.assertEqual(f'\\{6*7}', '\\42')
625 self.assertEqual(fr'\{6*7}', '\\42')
626
627 AMPERSAND = 'spam'
628 # Get the right unicode character (&), or pick up local variable
629 # depending on the number of backslashes.
630 self.assertEqual(f'\N{AMPERSAND}', '&')
631 self.assertEqual(f'\\N{AMPERSAND}', '\\Nspam')
632 self.assertEqual(fr'\N{AMPERSAND}', '\\Nspam')
633 self.assertEqual(f'\\\N{AMPERSAND}', '\\&')
634
Eric V. Smith451d0e32016-09-09 21:56:20 -0400635 def test_misformed_unicode_character_name(self):
636 # These test are needed because unicode names are parsed
637 # differently inside f-strings.
638 self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
639 [r"f'\N'",
640 r"f'\N{'",
641 r"f'\N{GREEK CAPITAL LETTER DELTA'",
642
643 # Here are the non-f-string versions,
644 # which should give the same errors.
645 r"'\N'",
646 r"'\N{'",
647 r"'\N{GREEK CAPITAL LETTER DELTA'",
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400648 ])
649
Eric V. Smith451d0e32016-09-09 21:56:20 -0400650 def test_no_backslashes_in_expression_part(self):
651 self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash',
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400652 [r"f'{\'a\'}'",
653 r"f'{\t3}'",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400654 r"f'{\}'",
655 r"rf'{\'a\'}'",
656 r"rf'{\t3}'",
657 r"rf'{\}'",
658 r"""rf'{"\N{LEFT CURLY BRACKET}"}'""",
Jason R. Coombs45cab8c2016-11-06 11:01:08 -0500659 r"f'{\n}'",
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400660 ])
661
Eric V. Smith451d0e32016-09-09 21:56:20 -0400662 def test_no_escapes_for_braces(self):
Jason R. Coombs1c92a762016-11-06 11:25:54 -0500663 """
664 Only literal curly braces begin an expression.
665 """
666 # \x7b is '{'.
667 self.assertEqual(f'\x7b1+1}}', '{1+1}')
668 self.assertEqual(f'\x7b1+1', '{1+1')
669 self.assertEqual(f'\u007b1+1', '{1+1')
670 self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400671
Eric V. Smith235a6f02015-09-19 14:51:32 -0400672 def test_newlines_in_expressions(self):
673 self.assertEqual(f'{0}', '0')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400674 self.assertEqual(rf'''{3+
6754}''', '7')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400676
677 def test_lambda(self):
678 x = 5
679 self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'")
680 self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888' ")
681 self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888 ")
682
683 # lambda doesn't work without parens, because the colon
684 # makes the parser think it's a format_spec
685 self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
686 ["f'{lambda x:x}'",
687 ])
688
689 def test_yield(self):
690 # Not terribly useful, but make sure the yield turns
691 # a function into a generator
692 def fn(y):
693 f'y:{yield y*2}'
694
695 g = fn(4)
696 self.assertEqual(next(g), 8)
697
698 def test_yield_send(self):
699 def fn(x):
700 yield f'x:{yield (lambda i: x * i)}'
701
702 g = fn(10)
703 the_lambda = next(g)
704 self.assertEqual(the_lambda(4), 40)
705 self.assertEqual(g.send('string'), 'x:string')
706
707 def test_expressions_with_triple_quoted_strings(self):
708 self.assertEqual(f"{'''x'''}", 'x')
709 self.assertEqual(f"{'''eric's'''}", "eric's")
Eric V. Smith235a6f02015-09-19 14:51:32 -0400710
711 # Test concatenation within an expression
712 self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy')
713 self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s')
714 self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy')
715 self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy')
716 self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy')
717 self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy')
718
719 def test_multiple_vars(self):
720 x = 98
721 y = 'abc'
722 self.assertEqual(f'{x}{y}', '98abc')
723
724 self.assertEqual(f'X{x}{y}', 'X98abc')
725 self.assertEqual(f'{x}X{y}', '98Xabc')
726 self.assertEqual(f'{x}{y}X', '98abcX')
727
728 self.assertEqual(f'X{x}Y{y}', 'X98Yabc')
729 self.assertEqual(f'X{x}{y}Y', 'X98abcY')
730 self.assertEqual(f'{x}X{y}Y', '98XabcY')
731
732 self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ')
733
734 def test_closure(self):
735 def outer(x):
736 def inner():
737 return f'x:{x}'
738 return inner
739
740 self.assertEqual(outer('987')(), 'x:987')
741 self.assertEqual(outer(7)(), 'x:7')
742
743 def test_arguments(self):
744 y = 2
745 def f(x, width):
746 return f'x={x*y:{width}}'
747
748 self.assertEqual(f('foo', 10), 'x=foofoo ')
749 x = 'bar'
750 self.assertEqual(f(10, 10), 'x= 20')
751
752 def test_locals(self):
753 value = 123
754 self.assertEqual(f'v:{value}', 'v:123')
755
756 def test_missing_variable(self):
757 with self.assertRaises(NameError):
758 f'v:{value}'
759
760 def test_missing_format_spec(self):
761 class O:
762 def __format__(self, spec):
763 if not spec:
764 return '*'
765 return spec
766
767 self.assertEqual(f'{O():x}', 'x')
768 self.assertEqual(f'{O()}', '*')
769 self.assertEqual(f'{O():}', '*')
770
771 self.assertEqual(f'{3:}', '3')
772 self.assertEqual(f'{3!s:}', '3')
773
774 def test_global(self):
775 self.assertEqual(f'g:{a_global}', 'g:global variable')
776 self.assertEqual(f'g:{a_global!r}', "g:'global variable'")
777
778 a_local = 'local variable'
779 self.assertEqual(f'g:{a_global} l:{a_local}',
780 'g:global variable l:local variable')
781 self.assertEqual(f'g:{a_global!r}',
782 "g:'global variable'")
783 self.assertEqual(f'g:{a_global} l:{a_local!r}',
784 "g:global variable l:'local variable'")
785
786 self.assertIn("module 'unittest' from", f'{unittest}')
787
788 def test_shadowed_global(self):
789 a_global = 'really a local'
790 self.assertEqual(f'g:{a_global}', 'g:really a local')
791 self.assertEqual(f'g:{a_global!r}', "g:'really a local'")
792
793 a_local = 'local variable'
794 self.assertEqual(f'g:{a_global} l:{a_local}',
795 'g:really a local l:local variable')
796 self.assertEqual(f'g:{a_global!r}',
797 "g:'really a local'")
798 self.assertEqual(f'g:{a_global} l:{a_local!r}',
799 "g:really a local l:'local variable'")
800
801 def test_call(self):
802 def foo(x):
803 return 'x=' + str(x)
804
805 self.assertEqual(f'{foo(10)}', 'x=10')
806
807 def test_nested_fstrings(self):
808 y = 5
809 self.assertEqual(f'{f"{0}"*3}', '000')
810 self.assertEqual(f'{f"{y}"*3}', '555')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400811
812 def test_invalid_string_prefixes(self):
813 self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
814 ["fu''",
815 "uf''",
816 "Fu''",
817 "fU''",
818 "Uf''",
819 "uF''",
820 "ufr''",
821 "urf''",
822 "fur''",
823 "fru''",
824 "rfu''",
825 "ruf''",
826 "FUR''",
827 "Fur''",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400828 "fb''",
829 "fB''",
830 "Fb''",
831 "FB''",
832 "bf''",
833 "bF''",
834 "Bf''",
835 "BF''",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400836 ])
837
838 def test_leading_trailing_spaces(self):
839 self.assertEqual(f'{ 3}', '3')
840 self.assertEqual(f'{ 3}', '3')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400841 self.assertEqual(f'{3 }', '3')
842 self.assertEqual(f'{3 }', '3')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400843
844 self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}',
845 'expr={1: 2}')
846 self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }',
847 'expr={1: 2}')
848
Eric V. Smith235a6f02015-09-19 14:51:32 -0400849 def test_not_equal(self):
850 # There's a special test for this because there's a special
851 # case in the f-string parser to look for != as not ending an
852 # expression. Normally it would, while looking for !s or !r.
853
854 self.assertEqual(f'{3!=4}', 'True')
855 self.assertEqual(f'{3!=4:}', 'True')
856 self.assertEqual(f'{3!=4!s}', 'True')
857 self.assertEqual(f'{3!=4!s:.3}', 'Tru')
858
859 def test_conversions(self):
860 self.assertEqual(f'{3.14:10.10}', ' 3.14')
861 self.assertEqual(f'{3.14!s:10.10}', '3.14 ')
862 self.assertEqual(f'{3.14!r:10.10}', '3.14 ')
863 self.assertEqual(f'{3.14!a:10.10}', '3.14 ')
864
865 self.assertEqual(f'{"a"}', 'a')
866 self.assertEqual(f'{"a"!r}', "'a'")
867 self.assertEqual(f'{"a"!a}', "'a'")
868
869 # Not a conversion.
870 self.assertEqual(f'{"a!r"}', "a!r")
871
872 # Not a conversion, but show that ! is allowed in a format spec.
873 self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
874
Eric V. Smith235a6f02015-09-19 14:51:32 -0400875 self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
876 ["f'{3!g}'",
877 "f'{3!A}'",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400878 "f'{3!3}'",
879 "f'{3!G}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400880 "f'{3!!}'",
881 "f'{3!:}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400882 "f'{3! s}'", # no space before conversion char
Eric V. Smith235a6f02015-09-19 14:51:32 -0400883 ])
884
885 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
886 ["f'{x!s{y}}'",
887 "f'{3!ss}'",
888 "f'{3!ss:}'",
889 "f'{3!ss:s}'",
890 ])
891
892 def test_assignment(self):
893 self.assertAllRaise(SyntaxError, 'invalid syntax',
894 ["f'' = 3",
895 "f'{0}' = x",
896 "f'{x}' = x",
897 ])
898
899 def test_del(self):
900 self.assertAllRaise(SyntaxError, 'invalid syntax',
901 ["del f''",
902 "del '' f''",
903 ])
904
905 def test_mismatched_braces(self):
906 self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
907 ["f'{{}'",
908 "f'{{}}}'",
909 "f'}'",
910 "f'x}'",
911 "f'x}x'",
Jason R. Coombsda25abf72016-11-06 11:14:48 -0500912 r"f'\u007b}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400913
914 # Can't have { or } in a format spec.
915 "f'{3:}>10}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400916 "f'{3:}}>10}'",
917 ])
918
919 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
920 ["f'{3:{{>10}'",
921 "f'{3'",
922 "f'{3!'",
923 "f'{3:'",
924 "f'{3!s'",
925 "f'{3!s:'",
926 "f'{3!s:3'",
927 "f'x{'",
928 "f'x{x'",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400929 "f'{x'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400930 "f'{3:s'",
931 "f'{{{'",
932 "f'{{}}{'",
933 "f'{'",
934 ])
935
Eric V. Smith235a6f02015-09-19 14:51:32 -0400936 # But these are just normal strings.
937 self.assertEqual(f'{"{"}', '{')
938 self.assertEqual(f'{"}"}', '}')
939 self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3')
940 self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2')
941
942 def test_if_conditional(self):
943 # There's special logic in compile.c to test if the
944 # conditional for an if (and while) are constants. Exercise
945 # that code.
946
947 def test_fstring(x, expected):
948 flag = 0
949 if f'{x}':
950 flag = 1
951 else:
952 flag = 2
953 self.assertEqual(flag, expected)
954
955 def test_concat_empty(x, expected):
956 flag = 0
957 if '' f'{x}':
958 flag = 1
959 else:
960 flag = 2
961 self.assertEqual(flag, expected)
962
963 def test_concat_non_empty(x, expected):
964 flag = 0
965 if ' ' f'{x}':
966 flag = 1
967 else:
968 flag = 2
969 self.assertEqual(flag, expected)
970
971 test_fstring('', 2)
972 test_fstring(' ', 1)
973
974 test_concat_empty('', 2)
975 test_concat_empty(' ', 1)
976
977 test_concat_non_empty('', 1)
978 test_concat_non_empty(' ', 1)
979
980 def test_empty_format_specifier(self):
981 x = 'test'
982 self.assertEqual(f'{x}', 'test')
983 self.assertEqual(f'{x:}', 'test')
984 self.assertEqual(f'{x!s:}', 'test')
985 self.assertEqual(f'{x!r:}', "'test'")
986
987 def test_str_format_differences(self):
988 d = {'a': 'string',
989 0: 'integer',
990 }
991 a = 0
992 self.assertEqual(f'{d[0]}', 'integer')
993 self.assertEqual(f'{d["a"]}', 'string')
994 self.assertEqual(f'{d[a]}', 'integer')
995 self.assertEqual('{d[a]}'.format(d=d), 'string')
996 self.assertEqual('{d[0]}'.format(d=d), 'integer')
997
998 def test_invalid_expressions(self):
999 self.assertAllRaise(SyntaxError, 'invalid syntax',
1000 [r"f'{a[4)}'",
1001 r"f'{a(4]}'",
1002 ])
1003
Eric V. Smith135d5f42016-02-05 18:23:08 -05001004 def test_errors(self):
1005 # see issue 26287
Serhiy Storchaka13c8f322016-10-31 08:13:00 +02001006 self.assertAllRaise(TypeError, 'unsupported',
Eric V. Smith135d5f42016-02-05 18:23:08 -05001007 [r"f'{(lambda: 0):x}'",
1008 r"f'{(0,):x}'",
1009 ])
1010 self.assertAllRaise(ValueError, 'Unknown format code',
1011 [r"f'{1000:j}'",
1012 r"f'{1000:j}'",
1013 ])
1014
Eric V. Smith235a6f02015-09-19 14:51:32 -04001015 def test_loop(self):
1016 for i in range(1000):
1017 self.assertEqual(f'i:{i}', 'i:' + str(i))
1018
1019 def test_dict(self):
1020 d = {'"': 'dquote',
1021 "'": 'squote',
1022 'foo': 'bar',
1023 }
Eric V. Smith235a6f02015-09-19 14:51:32 -04001024 self.assertEqual(f'''{d["'"]}''', 'squote')
1025 self.assertEqual(f"""{d['"']}""", 'dquote')
1026
1027 self.assertEqual(f'{d["foo"]}', 'bar')
1028 self.assertEqual(f"{d['foo']}", 'bar')
Eric V. Smith235a6f02015-09-19 14:51:32 -04001029
ericvsmith11e97f22017-06-16 06:19:32 -04001030 def test_backslash_char(self):
1031 # Check eval of a backslash followed by a control char.
1032 # See bpo-30682: this used to raise an assert in pydebug mode.
1033 self.assertEqual(eval('f"\\\n"'), '')
1034 self.assertEqual(eval('f"\\\r"'), '')
1035
Łukasz Langae7c566c2017-09-06 17:27:58 -07001036
Eric V. Smith235a6f02015-09-19 14:51:32 -04001037if __name__ == '__main__':
1038 unittest.main()