blob: 9d60be3a29a176d61ea74fd4d43be7bd2ad187d1 [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)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300119 self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)
120 self.assertEqual(type(t.body[1].value.values[0].value), str)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700121 self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300122 self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)
123 self.assertEqual(type(t.body[1].value.values[2].value), str)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700124 self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue)
125 self.assertEqual(t.body[1].lineno, 3)
126 self.assertEqual(t.body[1].value.lineno, 3)
127 self.assertEqual(t.body[1].value.values[0].lineno, 3)
128 self.assertEqual(t.body[1].value.values[1].lineno, 3)
129 self.assertEqual(t.body[1].value.values[2].lineno, 3)
130 self.assertEqual(t.body[1].value.values[3].lineno, 3)
131 # check the first binop location
132 binop1 = t.body[1].value.values[1].value
133 self.assertEqual(type(binop1), ast.BinOp)
134 self.assertEqual(type(binop1.left), ast.Name)
135 self.assertEqual(type(binop1.op), ast.Mult)
136 self.assertEqual(type(binop1.right), ast.Call)
137 self.assertEqual(binop1.lineno, 3)
138 self.assertEqual(binop1.left.lineno, 3)
139 self.assertEqual(binop1.right.lineno, 3)
140 self.assertEqual(binop1.col_offset, 8)
141 self.assertEqual(binop1.left.col_offset, 8)
142 self.assertEqual(binop1.right.col_offset, 12)
143 # check the second binop location
144 binop2 = t.body[1].value.values[3].value
145 self.assertEqual(type(binop2), ast.BinOp)
146 self.assertEqual(type(binop2.left), ast.Name)
147 self.assertEqual(type(binop2.op), ast.Add)
148 self.assertEqual(type(binop2.right), ast.Call)
149 self.assertEqual(binop2.lineno, 3)
150 self.assertEqual(binop2.left.lineno, 3)
151 self.assertEqual(binop2.right.lineno, 3)
152 self.assertEqual(binop2.col_offset, 23)
153 self.assertEqual(binop2.left.col_offset, 23)
154 self.assertEqual(binop2.right.col_offset, 27)
155
156 def test_ast_line_numbers_nested(self):
157 expr = """
158a = 10
159f'{a * f"-{x()}-"}'"""
160 t = ast.parse(expr)
161 self.assertEqual(type(t), ast.Module)
162 self.assertEqual(len(t.body), 2)
163 # check `a = 10`
164 self.assertEqual(type(t.body[0]), ast.Assign)
165 self.assertEqual(t.body[0].lineno, 2)
166 # check `f'...'`
167 self.assertEqual(type(t.body[1]), ast.Expr)
168 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
169 self.assertEqual(len(t.body[1].value.values), 1)
170 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
171 self.assertEqual(t.body[1].lineno, 3)
172 self.assertEqual(t.body[1].value.lineno, 3)
173 self.assertEqual(t.body[1].value.values[0].lineno, 3)
174 # check the binop location
175 binop = t.body[1].value.values[0].value
176 self.assertEqual(type(binop), ast.BinOp)
177 self.assertEqual(type(binop.left), ast.Name)
178 self.assertEqual(type(binop.op), ast.Mult)
179 self.assertEqual(type(binop.right), ast.JoinedStr)
180 self.assertEqual(binop.lineno, 3)
181 self.assertEqual(binop.left.lineno, 3)
182 self.assertEqual(binop.right.lineno, 3)
183 self.assertEqual(binop.col_offset, 3)
184 self.assertEqual(binop.left.col_offset, 3)
185 self.assertEqual(binop.right.col_offset, 7)
186 # check the nested call location
187 self.assertEqual(len(binop.right.values), 3)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300188 self.assertEqual(type(binop.right.values[0]), ast.Constant)
189 self.assertEqual(type(binop.right.values[0].value), str)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700190 self.assertEqual(type(binop.right.values[1]), ast.FormattedValue)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300191 self.assertEqual(type(binop.right.values[2]), ast.Constant)
192 self.assertEqual(type(binop.right.values[2].value), str)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700193 self.assertEqual(binop.right.values[0].lineno, 3)
194 self.assertEqual(binop.right.values[1].lineno, 3)
195 self.assertEqual(binop.right.values[2].lineno, 3)
196 call = binop.right.values[1].value
197 self.assertEqual(type(call), ast.Call)
198 self.assertEqual(call.lineno, 3)
199 self.assertEqual(call.col_offset, 11)
200
201 def test_ast_line_numbers_duplicate_expression(self):
202 """Duplicate expression
203
204 NOTE: this is currently broken, always sets location of the first
205 expression.
206 """
207 expr = """
208a = 10
209f'{a * x()} {a * x()} {a * x()}'
210"""
211 t = ast.parse(expr)
212 self.assertEqual(type(t), ast.Module)
213 self.assertEqual(len(t.body), 2)
214 # check `a = 10`
215 self.assertEqual(type(t.body[0]), ast.Assign)
216 self.assertEqual(t.body[0].lineno, 2)
217 # check `f'...'`
218 self.assertEqual(type(t.body[1]), ast.Expr)
219 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
220 self.assertEqual(len(t.body[1].value.values), 5)
221 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300222 self.assertEqual(type(t.body[1].value.values[1]), ast.Constant)
223 self.assertEqual(type(t.body[1].value.values[1].value), str)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700224 self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300225 self.assertEqual(type(t.body[1].value.values[3]), ast.Constant)
226 self.assertEqual(type(t.body[1].value.values[3].value), str)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700227 self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue)
228 self.assertEqual(t.body[1].lineno, 3)
229 self.assertEqual(t.body[1].value.lineno, 3)
230 self.assertEqual(t.body[1].value.values[0].lineno, 3)
231 self.assertEqual(t.body[1].value.values[1].lineno, 3)
232 self.assertEqual(t.body[1].value.values[2].lineno, 3)
233 self.assertEqual(t.body[1].value.values[3].lineno, 3)
234 self.assertEqual(t.body[1].value.values[4].lineno, 3)
235 # check the first binop location
236 binop = t.body[1].value.values[0].value
237 self.assertEqual(type(binop), ast.BinOp)
238 self.assertEqual(type(binop.left), ast.Name)
239 self.assertEqual(type(binop.op), ast.Mult)
240 self.assertEqual(type(binop.right), ast.Call)
241 self.assertEqual(binop.lineno, 3)
242 self.assertEqual(binop.left.lineno, 3)
243 self.assertEqual(binop.right.lineno, 3)
244 self.assertEqual(binop.col_offset, 3)
245 self.assertEqual(binop.left.col_offset, 3)
246 self.assertEqual(binop.right.col_offset, 7)
247 # check the second binop location
248 binop = t.body[1].value.values[2].value
249 self.assertEqual(type(binop), ast.BinOp)
250 self.assertEqual(type(binop.left), ast.Name)
251 self.assertEqual(type(binop.op), ast.Mult)
252 self.assertEqual(type(binop.right), ast.Call)
253 self.assertEqual(binop.lineno, 3)
254 self.assertEqual(binop.left.lineno, 3)
255 self.assertEqual(binop.right.lineno, 3)
256 self.assertEqual(binop.col_offset, 3) # FIXME: this is wrong
257 self.assertEqual(binop.left.col_offset, 3) # FIXME: this is wrong
258 self.assertEqual(binop.right.col_offset, 7) # FIXME: this is wrong
259 # check the third binop location
260 binop = t.body[1].value.values[4].value
261 self.assertEqual(type(binop), ast.BinOp)
262 self.assertEqual(type(binop.left), ast.Name)
263 self.assertEqual(type(binop.op), ast.Mult)
264 self.assertEqual(type(binop.right), ast.Call)
265 self.assertEqual(binop.lineno, 3)
266 self.assertEqual(binop.left.lineno, 3)
267 self.assertEqual(binop.right.lineno, 3)
268 self.assertEqual(binop.col_offset, 3) # FIXME: this is wrong
269 self.assertEqual(binop.left.col_offset, 3) # FIXME: this is wrong
270 self.assertEqual(binop.right.col_offset, 7) # FIXME: this is wrong
271
272 def test_ast_line_numbers_multiline_fstring(self):
Anthony Sottile995d9b92019-01-12 20:05:13 -0800273 # See bpo-30465 for details.
Łukasz Langae7c566c2017-09-06 17:27:58 -0700274 expr = """
275a = 10
276f'''
277 {a
278 *
279 x()}
280non-important content
281'''
282"""
283 t = ast.parse(expr)
284 self.assertEqual(type(t), ast.Module)
285 self.assertEqual(len(t.body), 2)
286 # check `a = 10`
287 self.assertEqual(type(t.body[0]), ast.Assign)
288 self.assertEqual(t.body[0].lineno, 2)
289 # check `f'...'`
290 self.assertEqual(type(t.body[1]), ast.Expr)
291 self.assertEqual(type(t.body[1].value), ast.JoinedStr)
292 self.assertEqual(len(t.body[1].value.values), 3)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300293 self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)
294 self.assertEqual(type(t.body[1].value.values[0].value), str)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700295 self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300296 self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)
297 self.assertEqual(type(t.body[1].value.values[2].value), str)
Anthony Sottile995d9b92019-01-12 20:05:13 -0800298 self.assertEqual(t.body[1].lineno, 3)
299 self.assertEqual(t.body[1].value.lineno, 3)
300 self.assertEqual(t.body[1].value.values[0].lineno, 3)
301 self.assertEqual(t.body[1].value.values[1].lineno, 3)
302 self.assertEqual(t.body[1].value.values[2].lineno, 3)
303 self.assertEqual(t.body[1].col_offset, 0)
304 self.assertEqual(t.body[1].value.col_offset, 0)
305 self.assertEqual(t.body[1].value.values[0].col_offset, 0)
306 self.assertEqual(t.body[1].value.values[1].col_offset, 0)
307 self.assertEqual(t.body[1].value.values[2].col_offset, 0)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700308 # NOTE: the following lineno information and col_offset is correct for
309 # expressions within FormattedValues.
310 binop = t.body[1].value.values[1].value
311 self.assertEqual(type(binop), ast.BinOp)
312 self.assertEqual(type(binop.left), ast.Name)
313 self.assertEqual(type(binop.op), ast.Mult)
314 self.assertEqual(type(binop.right), ast.Call)
315 self.assertEqual(binop.lineno, 4)
316 self.assertEqual(binop.left.lineno, 4)
317 self.assertEqual(binop.right.lineno, 6)
Anthony Sottile995d9b92019-01-12 20:05:13 -0800318 self.assertEqual(binop.col_offset, 4)
319 self.assertEqual(binop.left.col_offset, 4)
Łukasz Langae7c566c2017-09-06 17:27:58 -0700320 self.assertEqual(binop.right.col_offset, 7)
321
Serhiy Storchaka4cc30ae2016-12-11 19:37:19 +0200322 def test_docstring(self):
323 def f():
324 f'''Not a docstring'''
325 self.assertIsNone(f.__doc__)
326 def g():
327 '''Not a docstring''' \
328 f''
329 self.assertIsNone(g.__doc__)
330
Eric V. Smith235a6f02015-09-19 14:51:32 -0400331 def test_literal_eval(self):
Eric V. Smith235a6f02015-09-19 14:51:32 -0400332 with self.assertRaisesRegex(ValueError, 'malformed node or string'):
Serhiy Storchaka4cc30ae2016-12-11 19:37:19 +0200333 ast.literal_eval("f'x'")
Eric V. Smith235a6f02015-09-19 14:51:32 -0400334
335 def test_ast_compile_time_concat(self):
336 x = ['']
337
338 expr = """x[0] = 'foo' f'{3}'"""
339 t = ast.parse(expr)
340 c = compile(t, '', 'exec')
341 exec(c)
342 self.assertEqual(x[0], 'foo3')
343
Eric V. Smith9b88fdf2016-11-07 17:54:01 -0500344 def test_compile_time_concat_errors(self):
345 self.assertAllRaise(SyntaxError,
346 'cannot mix bytes and nonbytes literals',
347 [r"""f'' b''""",
348 r"""b'' f''""",
349 ])
350
Eric V. Smith235a6f02015-09-19 14:51:32 -0400351 def test_literal(self):
352 self.assertEqual(f'', '')
353 self.assertEqual(f'a', 'a')
354 self.assertEqual(f' ', ' ')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400355
356 def test_unterminated_string(self):
357 self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
358 [r"""f'{"x'""",
359 r"""f'{"x}'""",
360 r"""f'{("x'""",
361 r"""f'{("x}'""",
362 ])
363
364 def test_mismatched_parens(self):
Serhiy Storchaka58159ef2019-01-12 09:46:50 +0200365 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
366 r"does not match opening parenthesis '\('",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400367 ["f'{((}'",
368 ])
Serhiy Storchaka58159ef2019-01-12 09:46:50 +0200369 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\)' "
370 r"does not match opening parenthesis '\['",
371 ["f'{a[4)}'",
372 ])
373 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\]' "
374 r"does not match opening parenthesis '\('",
375 ["f'{a(4]}'",
376 ])
377 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
378 r"does not match opening parenthesis '\['",
379 ["f'{a[4}'",
380 ])
381 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
382 r"does not match opening parenthesis '\('",
383 ["f'{a(4}'",
384 ])
385 self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'")
Eric V. Smith235a6f02015-09-19 14:51:32 -0400386
387 def test_double_braces(self):
388 self.assertEqual(f'{{', '{')
389 self.assertEqual(f'a{{', 'a{')
390 self.assertEqual(f'{{b', '{b')
391 self.assertEqual(f'a{{b', 'a{b')
392 self.assertEqual(f'}}', '}')
393 self.assertEqual(f'a}}', 'a}')
394 self.assertEqual(f'}}b', '}b')
395 self.assertEqual(f'a}}b', 'a}b')
Eric V. Smith451d0e32016-09-09 21:56:20 -0400396 self.assertEqual(f'{{}}', '{}')
397 self.assertEqual(f'a{{}}', 'a{}')
398 self.assertEqual(f'{{b}}', '{b}')
399 self.assertEqual(f'{{}}c', '{}c')
400 self.assertEqual(f'a{{b}}', 'a{b}')
401 self.assertEqual(f'a{{}}c', 'a{}c')
402 self.assertEqual(f'{{b}}c', '{b}c')
403 self.assertEqual(f'a{{b}}c', 'a{b}c')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400404
405 self.assertEqual(f'{{{10}', '{10')
406 self.assertEqual(f'}}{10}', '}10')
407 self.assertEqual(f'}}{{{10}', '}{10')
408 self.assertEqual(f'}}a{{{10}', '}a{10')
409
410 self.assertEqual(f'{10}{{', '10{')
411 self.assertEqual(f'{10}}}', '10}')
412 self.assertEqual(f'{10}}}{{', '10}{')
413 self.assertEqual(f'{10}}}a{{' '}', '10}a{}')
414
415 # Inside of strings, don't interpret doubled brackets.
416 self.assertEqual(f'{"{{}}"}', '{{}}')
417
418 self.assertAllRaise(TypeError, 'unhashable type',
419 ["f'{ {{}} }'", # dict in a set
420 ])
421
422 def test_compile_time_concat(self):
423 x = 'def'
424 self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
425 self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi')
426 self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ')
427 self.assertEqual('{x}' f'{x}', '{x}def')
428 self.assertEqual('{x' f'{x}', '{xdef')
429 self.assertEqual('{x}' f'{x}', '{x}def')
430 self.assertEqual('{{x}}' f'{x}', '{{x}}def')
431 self.assertEqual('{{x' f'{x}', '{{xdef')
432 self.assertEqual('x}}' f'{x}', 'x}}def')
433 self.assertEqual(f'{x}' 'x}}', 'defx}}')
434 self.assertEqual(f'{x}' '', 'def')
435 self.assertEqual('' f'{x}' '', 'def')
436 self.assertEqual('' f'{x}', 'def')
437 self.assertEqual(f'{x}' '2', 'def2')
438 self.assertEqual('1' f'{x}' '2', '1def2')
439 self.assertEqual('1' f'{x}', '1def')
440 self.assertEqual(f'{x}' f'-{x}', 'def-def')
441 self.assertEqual('' f'', '')
442 self.assertEqual('' f'' '', '')
443 self.assertEqual('' f'' '' f'', '')
444 self.assertEqual(f'', '')
445 self.assertEqual(f'' '', '')
446 self.assertEqual(f'' '' f'', '')
447 self.assertEqual(f'' '' f'' '', '')
448
449 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
450 ["f'{3' f'}'", # can't concat to get a valid f-string
451 ])
452
453 def test_comments(self):
454 # These aren't comments, since they're in strings.
455 d = {'#': 'hash'}
456 self.assertEqual(f'{"#"}', '#')
457 self.assertEqual(f'{d["#"]}', 'hash')
458
Eric V. Smith09835dc2016-09-11 18:58:20 -0400459 self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400460 ["f'{1#}'", # error because the expression becomes "(1#)"
461 "f'{3(#)}'",
Eric V. Smith09835dc2016-09-11 18:58:20 -0400462 "f'{#}'",
Serhiy Storchaka58159ef2019-01-12 09:46:50 +0200463 ])
464 self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'",
465 ["f'{)#}'", # When wrapped in parens, this becomes
Eric V. Smith35a24c52016-09-11 19:01:22 -0400466 # '()#)'. Make sure that doesn't compile.
Eric V. Smith235a6f02015-09-19 14:51:32 -0400467 ])
468
469 def test_many_expressions(self):
470 # Create a string with many expressions in it. Note that
471 # because we have a space in here as a literal, we're actually
472 # going to use twice as many ast nodes: one for each literal
473 # plus one for each expression.
474 def build_fstr(n, extra=''):
475 return "f'" + ('{x} ' * n) + extra + "'"
476
477 x = 'X'
478 width = 1
479
480 # Test around 256.
481 for i in range(250, 260):
482 self.assertEqual(eval(build_fstr(i)), (x+' ')*i)
483
484 # Test concatenating 2 largs fstrings.
485 self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256))
486
487 s = build_fstr(253, '{x:{width}} ')
488 self.assertEqual(eval(s), (x+' ')*254)
489
490 # Test lots of expressions and constants, concatenated.
491 s = "f'{1}' 'x' 'y'" * 1024
492 self.assertEqual(eval(s), '1xy' * 1024)
493
494 def test_format_specifier_expressions(self):
495 width = 10
496 precision = 4
497 value = decimal.Decimal('12.34567')
498 self.assertEqual(f'result: {value:{width}.{precision}}', 'result: 12.35')
499 self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result: 12.35')
500 self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result: 12.35')
501 self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result: 12.35')
502 self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result: 12.35')
503 self.assertEqual(f'{10:#{1}0x}', ' 0xa')
504 self.assertEqual(f'{10:{"#"}1{0}{"x"}}', ' 0xa')
505 self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa')
506 self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa')
507 self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa')
508
509 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
510 ["""f'{"s"!r{":10"}}'""",
511
512 # This looks like a nested format spec.
513 ])
514
515 self.assertAllRaise(SyntaxError, "invalid syntax",
Martin Panter263893c2016-07-28 01:25:31 +0000516 [# Invalid syntax inside a nested spec.
Eric V. Smith235a6f02015-09-19 14:51:32 -0400517 "f'{4:{/5}}'",
518 ])
519
520 self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
521 [# Can't nest format specifiers.
522 "f'result: {value:{width:{0}}.{precision:1}}'",
523 ])
524
525 self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
526 [# No expansion inside conversion or for
527 # the : or ! itself.
528 """f'{"s"!{"r"}}'""",
529 ])
530
531 def test_side_effect_order(self):
532 class X:
533 def __init__(self):
534 self.i = 0
535 def __format__(self, spec):
536 self.i += 1
537 return str(self.i)
538
539 x = X()
540 self.assertEqual(f'{x} {x}', '1 2')
541
542 def test_missing_expression(self):
543 self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
544 ["f'{}'",
545 "f'{ }'"
546 "f' {} '",
547 "f'{!r}'",
548 "f'{ !r}'",
549 "f'{10:{ }}'",
550 "f' { } '",
Eric V. Smith1d44c412015-09-23 07:49:00 -0400551
Serhiy Storchaka2e9cd582017-06-08 23:43:54 +0300552 # The Python parser ignores also the following
553 # whitespace characters in additional to a space.
554 "f'''{\t\f\r\n}'''",
555
Eric V. Smith1d44c412015-09-23 07:49:00 -0400556 # Catch the empty expression before the
557 # invalid conversion.
558 "f'{!x}'",
559 "f'{ !xr}'",
560 "f'{!x:}'",
561 "f'{!x:a}'",
562 "f'{ !xr:}'",
563 "f'{ !xr:a}'",
Eric V. Smith548c4d32015-09-23 08:00:01 -0400564
565 "f'{!}'",
566 "f'{:}'",
Eric V. Smithb2080f62015-09-23 10:24:43 -0400567
568 # We find the empty expression before the
569 # missing closing brace.
570 "f'{!'",
571 "f'{!s:'",
572 "f'{:'",
573 "f'{:x'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400574 ])
575
Serhiy Storchaka2e9cd582017-06-08 23:43:54 +0300576 # Different error message is raised for other whitespace characters.
577 self.assertAllRaise(SyntaxError, 'invalid character in identifier',
578 ["f'''{\xa0}'''",
579 "\xa0",
580 ])
581
Eric V. Smith235a6f02015-09-19 14:51:32 -0400582 def test_parens_in_expressions(self):
583 self.assertEqual(f'{3,}', '(3,)')
584
585 # Add these because when an expression is evaluated, parens
586 # are added around it. But we shouldn't go from an invalid
587 # expression to a valid one. The added parens are just
588 # supposed to allow whitespace (including newlines).
589 self.assertAllRaise(SyntaxError, 'invalid syntax',
590 ["f'{,}'",
591 "f'{,}'", # this is (,), which is an error
592 ])
593
Serhiy Storchaka58159ef2019-01-12 09:46:50 +0200594 self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400595 ["f'{3)+(4}'",
596 ])
597
598 self.assertAllRaise(SyntaxError, 'EOL while scanning string literal',
599 ["f'{\n}'",
600 ])
601
Eric V. Smith451d0e32016-09-09 21:56:20 -0400602 def test_backslashes_in_string_part(self):
603 self.assertEqual(f'\t', '\t')
604 self.assertEqual(r'\t', '\\t')
605 self.assertEqual(rf'\t', '\\t')
606 self.assertEqual(f'{2}\t', '2\t')
607 self.assertEqual(f'{2}\t{3}', '2\t3')
608 self.assertEqual(f'\t{3}', '\t3')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400609
Eric V. Smith451d0e32016-09-09 21:56:20 -0400610 self.assertEqual(f'\u0394', '\u0394')
611 self.assertEqual(r'\u0394', '\\u0394')
612 self.assertEqual(rf'\u0394', '\\u0394')
613 self.assertEqual(f'{2}\u0394', '2\u0394')
614 self.assertEqual(f'{2}\u0394{3}', '2\u03943')
615 self.assertEqual(f'\u0394{3}', '\u03943')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400616
Eric V. Smith451d0e32016-09-09 21:56:20 -0400617 self.assertEqual(f'\U00000394', '\u0394')
618 self.assertEqual(r'\U00000394', '\\U00000394')
619 self.assertEqual(rf'\U00000394', '\\U00000394')
620 self.assertEqual(f'{2}\U00000394', '2\u0394')
621 self.assertEqual(f'{2}\U00000394{3}', '2\u03943')
622 self.assertEqual(f'\U00000394{3}', '\u03943')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400623
Eric V. Smith451d0e32016-09-09 21:56:20 -0400624 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394')
625 self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
626 self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943')
627 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943')
628 self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
629 self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943')
630 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400631
Eric V. Smith451d0e32016-09-09 21:56:20 -0400632 self.assertEqual(f'\x20', ' ')
633 self.assertEqual(r'\x20', '\\x20')
634 self.assertEqual(rf'\x20', '\\x20')
635 self.assertEqual(f'{2}\x20', '2 ')
636 self.assertEqual(f'{2}\x20{3}', '2 3')
637 self.assertEqual(f'\x20{3}', ' 3')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400638
Eric V. Smith451d0e32016-09-09 21:56:20 -0400639 self.assertEqual(f'2\x20', '2 ')
640 self.assertEqual(f'2\x203', '2 3')
641 self.assertEqual(f'\x203', ' 3')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400642
Serhiy Storchaka65439122018-10-19 17:42:06 +0300643 with self.assertWarns(SyntaxWarning): # invalid escape sequence
Serhiy Storchaka0cd7a3f2017-05-25 13:33:55 +0300644 value = eval(r"f'\{6*7}'")
645 self.assertEqual(value, '\\42')
646 self.assertEqual(f'\\{6*7}', '\\42')
647 self.assertEqual(fr'\{6*7}', '\\42')
648
649 AMPERSAND = 'spam'
650 # Get the right unicode character (&), or pick up local variable
651 # depending on the number of backslashes.
652 self.assertEqual(f'\N{AMPERSAND}', '&')
653 self.assertEqual(f'\\N{AMPERSAND}', '\\Nspam')
654 self.assertEqual(fr'\N{AMPERSAND}', '\\Nspam')
655 self.assertEqual(f'\\\N{AMPERSAND}', '\\&')
656
Eric V. Smith451d0e32016-09-09 21:56:20 -0400657 def test_misformed_unicode_character_name(self):
658 # These test are needed because unicode names are parsed
659 # differently inside f-strings.
660 self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
661 [r"f'\N'",
662 r"f'\N{'",
663 r"f'\N{GREEK CAPITAL LETTER DELTA'",
664
665 # Here are the non-f-string versions,
666 # which should give the same errors.
667 r"'\N'",
668 r"'\N{'",
669 r"'\N{GREEK CAPITAL LETTER DELTA'",
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400670 ])
671
Eric V. Smith451d0e32016-09-09 21:56:20 -0400672 def test_no_backslashes_in_expression_part(self):
673 self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash',
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400674 [r"f'{\'a\'}'",
675 r"f'{\t3}'",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400676 r"f'{\}'",
677 r"rf'{\'a\'}'",
678 r"rf'{\t3}'",
679 r"rf'{\}'",
680 r"""rf'{"\N{LEFT CURLY BRACKET}"}'""",
Jason R. Coombs45cab8c2016-11-06 11:01:08 -0500681 r"f'{\n}'",
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400682 ])
683
Eric V. Smith451d0e32016-09-09 21:56:20 -0400684 def test_no_escapes_for_braces(self):
Jason R. Coombs1c92a762016-11-06 11:25:54 -0500685 """
686 Only literal curly braces begin an expression.
687 """
688 # \x7b is '{'.
689 self.assertEqual(f'\x7b1+1}}', '{1+1}')
690 self.assertEqual(f'\x7b1+1', '{1+1')
691 self.assertEqual(f'\u007b1+1', '{1+1')
692 self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}')
Eric V. Smith6a4efce2016-09-03 09:18:34 -0400693
Eric V. Smith235a6f02015-09-19 14:51:32 -0400694 def test_newlines_in_expressions(self):
695 self.assertEqual(f'{0}', '0')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400696 self.assertEqual(rf'''{3+
6974}''', '7')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400698
699 def test_lambda(self):
700 x = 5
701 self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'")
702 self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888' ")
703 self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888 ")
704
705 # lambda doesn't work without parens, because the colon
706 # makes the parser think it's a format_spec
707 self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
708 ["f'{lambda x:x}'",
709 ])
710
711 def test_yield(self):
712 # Not terribly useful, but make sure the yield turns
713 # a function into a generator
714 def fn(y):
715 f'y:{yield y*2}'
716
717 g = fn(4)
718 self.assertEqual(next(g), 8)
719
720 def test_yield_send(self):
721 def fn(x):
722 yield f'x:{yield (lambda i: x * i)}'
723
724 g = fn(10)
725 the_lambda = next(g)
726 self.assertEqual(the_lambda(4), 40)
727 self.assertEqual(g.send('string'), 'x:string')
728
729 def test_expressions_with_triple_quoted_strings(self):
730 self.assertEqual(f"{'''x'''}", 'x')
731 self.assertEqual(f"{'''eric's'''}", "eric's")
Eric V. Smith235a6f02015-09-19 14:51:32 -0400732
733 # Test concatenation within an expression
734 self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy')
735 self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s')
736 self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy')
737 self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy')
738 self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy')
739 self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy')
740
741 def test_multiple_vars(self):
742 x = 98
743 y = 'abc'
744 self.assertEqual(f'{x}{y}', '98abc')
745
746 self.assertEqual(f'X{x}{y}', 'X98abc')
747 self.assertEqual(f'{x}X{y}', '98Xabc')
748 self.assertEqual(f'{x}{y}X', '98abcX')
749
750 self.assertEqual(f'X{x}Y{y}', 'X98Yabc')
751 self.assertEqual(f'X{x}{y}Y', 'X98abcY')
752 self.assertEqual(f'{x}X{y}Y', '98XabcY')
753
754 self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ')
755
756 def test_closure(self):
757 def outer(x):
758 def inner():
759 return f'x:{x}'
760 return inner
761
762 self.assertEqual(outer('987')(), 'x:987')
763 self.assertEqual(outer(7)(), 'x:7')
764
765 def test_arguments(self):
766 y = 2
767 def f(x, width):
768 return f'x={x*y:{width}}'
769
770 self.assertEqual(f('foo', 10), 'x=foofoo ')
771 x = 'bar'
772 self.assertEqual(f(10, 10), 'x= 20')
773
774 def test_locals(self):
775 value = 123
776 self.assertEqual(f'v:{value}', 'v:123')
777
778 def test_missing_variable(self):
779 with self.assertRaises(NameError):
780 f'v:{value}'
781
782 def test_missing_format_spec(self):
783 class O:
784 def __format__(self, spec):
785 if not spec:
786 return '*'
787 return spec
788
789 self.assertEqual(f'{O():x}', 'x')
790 self.assertEqual(f'{O()}', '*')
791 self.assertEqual(f'{O():}', '*')
792
793 self.assertEqual(f'{3:}', '3')
794 self.assertEqual(f'{3!s:}', '3')
795
796 def test_global(self):
797 self.assertEqual(f'g:{a_global}', 'g:global variable')
798 self.assertEqual(f'g:{a_global!r}', "g:'global variable'")
799
800 a_local = 'local variable'
801 self.assertEqual(f'g:{a_global} l:{a_local}',
802 'g:global variable l:local variable')
803 self.assertEqual(f'g:{a_global!r}',
804 "g:'global variable'")
805 self.assertEqual(f'g:{a_global} l:{a_local!r}',
806 "g:global variable l:'local variable'")
807
808 self.assertIn("module 'unittest' from", f'{unittest}')
809
810 def test_shadowed_global(self):
811 a_global = 'really a local'
812 self.assertEqual(f'g:{a_global}', 'g:really a local')
813 self.assertEqual(f'g:{a_global!r}', "g:'really a local'")
814
815 a_local = 'local variable'
816 self.assertEqual(f'g:{a_global} l:{a_local}',
817 'g:really a local l:local variable')
818 self.assertEqual(f'g:{a_global!r}',
819 "g:'really a local'")
820 self.assertEqual(f'g:{a_global} l:{a_local!r}',
821 "g:really a local l:'local variable'")
822
823 def test_call(self):
824 def foo(x):
825 return 'x=' + str(x)
826
827 self.assertEqual(f'{foo(10)}', 'x=10')
828
829 def test_nested_fstrings(self):
830 y = 5
831 self.assertEqual(f'{f"{0}"*3}', '000')
832 self.assertEqual(f'{f"{y}"*3}', '555')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400833
834 def test_invalid_string_prefixes(self):
835 self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
836 ["fu''",
837 "uf''",
838 "Fu''",
839 "fU''",
840 "Uf''",
841 "uF''",
842 "ufr''",
843 "urf''",
844 "fur''",
845 "fru''",
846 "rfu''",
847 "ruf''",
848 "FUR''",
849 "Fur''",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400850 "fb''",
851 "fB''",
852 "Fb''",
853 "FB''",
854 "bf''",
855 "bF''",
856 "Bf''",
857 "BF''",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400858 ])
859
860 def test_leading_trailing_spaces(self):
861 self.assertEqual(f'{ 3}', '3')
862 self.assertEqual(f'{ 3}', '3')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400863 self.assertEqual(f'{3 }', '3')
864 self.assertEqual(f'{3 }', '3')
Eric V. Smith235a6f02015-09-19 14:51:32 -0400865
866 self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}',
867 'expr={1: 2}')
868 self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }',
869 'expr={1: 2}')
870
Eric V. Smith235a6f02015-09-19 14:51:32 -0400871 def test_not_equal(self):
872 # There's a special test for this because there's a special
873 # case in the f-string parser to look for != as not ending an
874 # expression. Normally it would, while looking for !s or !r.
875
876 self.assertEqual(f'{3!=4}', 'True')
877 self.assertEqual(f'{3!=4:}', 'True')
878 self.assertEqual(f'{3!=4!s}', 'True')
879 self.assertEqual(f'{3!=4!s:.3}', 'Tru')
880
881 def test_conversions(self):
882 self.assertEqual(f'{3.14:10.10}', ' 3.14')
883 self.assertEqual(f'{3.14!s:10.10}', '3.14 ')
884 self.assertEqual(f'{3.14!r:10.10}', '3.14 ')
885 self.assertEqual(f'{3.14!a:10.10}', '3.14 ')
886
887 self.assertEqual(f'{"a"}', 'a')
888 self.assertEqual(f'{"a"!r}', "'a'")
889 self.assertEqual(f'{"a"!a}', "'a'")
890
891 # Not a conversion.
892 self.assertEqual(f'{"a!r"}', "a!r")
893
894 # Not a conversion, but show that ! is allowed in a format spec.
895 self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
896
Eric V. Smith235a6f02015-09-19 14:51:32 -0400897 self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
898 ["f'{3!g}'",
899 "f'{3!A}'",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400900 "f'{3!3}'",
901 "f'{3!G}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400902 "f'{3!!}'",
903 "f'{3!:}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400904 "f'{3! s}'", # no space before conversion char
Eric V. Smith235a6f02015-09-19 14:51:32 -0400905 ])
906
907 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
908 ["f'{x!s{y}}'",
909 "f'{3!ss}'",
910 "f'{3!ss:}'",
911 "f'{3!ss:s}'",
912 ])
913
914 def test_assignment(self):
915 self.assertAllRaise(SyntaxError, 'invalid syntax',
916 ["f'' = 3",
917 "f'{0}' = x",
918 "f'{x}' = x",
919 ])
920
921 def test_del(self):
922 self.assertAllRaise(SyntaxError, 'invalid syntax',
923 ["del f''",
924 "del '' f''",
925 ])
926
927 def test_mismatched_braces(self):
928 self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
929 ["f'{{}'",
930 "f'{{}}}'",
931 "f'}'",
932 "f'x}'",
933 "f'x}x'",
Jason R. Coombsda25abf72016-11-06 11:14:48 -0500934 r"f'\u007b}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400935
936 # Can't have { or } in a format spec.
937 "f'{3:}>10}'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400938 "f'{3:}}>10}'",
939 ])
940
941 self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
942 ["f'{3:{{>10}'",
943 "f'{3'",
944 "f'{3!'",
945 "f'{3:'",
946 "f'{3!s'",
947 "f'{3!s:'",
948 "f'{3!s:3'",
949 "f'x{'",
950 "f'x{x'",
Eric V. Smith451d0e32016-09-09 21:56:20 -0400951 "f'{x'",
Eric V. Smith235a6f02015-09-19 14:51:32 -0400952 "f'{3:s'",
953 "f'{{{'",
954 "f'{{}}{'",
955 "f'{'",
956 ])
957
Eric V. Smith235a6f02015-09-19 14:51:32 -0400958 # But these are just normal strings.
959 self.assertEqual(f'{"{"}', '{')
960 self.assertEqual(f'{"}"}', '}')
961 self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3')
962 self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2')
963
964 def test_if_conditional(self):
965 # There's special logic in compile.c to test if the
966 # conditional for an if (and while) are constants. Exercise
967 # that code.
968
969 def test_fstring(x, expected):
970 flag = 0
971 if f'{x}':
972 flag = 1
973 else:
974 flag = 2
975 self.assertEqual(flag, expected)
976
977 def test_concat_empty(x, expected):
978 flag = 0
979 if '' f'{x}':
980 flag = 1
981 else:
982 flag = 2
983 self.assertEqual(flag, expected)
984
985 def test_concat_non_empty(x, expected):
986 flag = 0
987 if ' ' f'{x}':
988 flag = 1
989 else:
990 flag = 2
991 self.assertEqual(flag, expected)
992
993 test_fstring('', 2)
994 test_fstring(' ', 1)
995
996 test_concat_empty('', 2)
997 test_concat_empty(' ', 1)
998
999 test_concat_non_empty('', 1)
1000 test_concat_non_empty(' ', 1)
1001
1002 def test_empty_format_specifier(self):
1003 x = 'test'
1004 self.assertEqual(f'{x}', 'test')
1005 self.assertEqual(f'{x:}', 'test')
1006 self.assertEqual(f'{x!s:}', 'test')
1007 self.assertEqual(f'{x!r:}', "'test'")
1008
1009 def test_str_format_differences(self):
1010 d = {'a': 'string',
1011 0: 'integer',
1012 }
1013 a = 0
1014 self.assertEqual(f'{d[0]}', 'integer')
1015 self.assertEqual(f'{d["a"]}', 'string')
1016 self.assertEqual(f'{d[a]}', 'integer')
1017 self.assertEqual('{d[a]}'.format(d=d), 'string')
1018 self.assertEqual('{d[0]}'.format(d=d), 'integer')
1019
Eric V. Smith135d5f42016-02-05 18:23:08 -05001020 def test_errors(self):
1021 # see issue 26287
Serhiy Storchaka13c8f322016-10-31 08:13:00 +02001022 self.assertAllRaise(TypeError, 'unsupported',
Eric V. Smith135d5f42016-02-05 18:23:08 -05001023 [r"f'{(lambda: 0):x}'",
1024 r"f'{(0,):x}'",
1025 ])
1026 self.assertAllRaise(ValueError, 'Unknown format code',
1027 [r"f'{1000:j}'",
1028 r"f'{1000:j}'",
1029 ])
1030
Eric V. Smith235a6f02015-09-19 14:51:32 -04001031 def test_loop(self):
1032 for i in range(1000):
1033 self.assertEqual(f'i:{i}', 'i:' + str(i))
1034
1035 def test_dict(self):
1036 d = {'"': 'dquote',
1037 "'": 'squote',
1038 'foo': 'bar',
1039 }
Eric V. Smith235a6f02015-09-19 14:51:32 -04001040 self.assertEqual(f'''{d["'"]}''', 'squote')
1041 self.assertEqual(f"""{d['"']}""", 'dquote')
1042
1043 self.assertEqual(f'{d["foo"]}', 'bar')
1044 self.assertEqual(f"{d['foo']}", 'bar')
Eric V. Smith235a6f02015-09-19 14:51:32 -04001045
ericvsmith11e97f22017-06-16 06:19:32 -04001046 def test_backslash_char(self):
1047 # Check eval of a backslash followed by a control char.
1048 # See bpo-30682: this used to raise an assert in pydebug mode.
1049 self.assertEqual(eval('f"\\\n"'), '')
1050 self.assertEqual(eval('f"\\\r"'), '')
1051
Łukasz Langae7c566c2017-09-06 17:27:58 -07001052
Eric V. Smith235a6f02015-09-19 14:51:32 -04001053if __name__ == '__main__':
1054 unittest.main()