1import 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 73 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 320 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 329 def test_literal_eval(self): 330 with self.assertRaisesRegex(ValueError, 'malformed node or string'): 331 ast.literal_eval("f'x'") 332 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 342 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 349 def test_literal(self): 350 self.assertEqual(f'', '') 351 self.assertEqual(f'a', 'a') 352 self.assertEqual(f' ', ' ') 353 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') 376 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') 384 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 439 self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'", 440 ["f'{1#}'", # error because the expression becomes "(1#)" 441 "f'{3(#)}'", 442 "f'{#}'", 443 "f'{)#}'", # When wrapped in parens, this becomes 444 # '()#)'. Make sure that doesn't compile. 445 ]) 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", 494 [# Invalid syntax inside a nested spec. 495 "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' { } '", 529 530 # The Python parser ignores also the following 531 # whitespace characters in additional to a space. 532 "f'''{\t\f\r\n}'''", 533 534 # 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}'", 542 543 "f'{!}'", 544 "f'{:}'", 545 546 # We find the empty expression before the 547 # missing closing brace. 548 "f'{!'", 549 "f'{!s:'", 550 "f'{:'", 551 "f'{:x'", 552 ]) 553 554 # Different error message is raised for other whitespace characters. 555 self.assertAllRaise(SyntaxError, 'invalid character in identifier', 556 ["f'''{\xa0}'''", 557 "\xa0", 558 ]) 559 560 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 580 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') 587 588 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') 594 595 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') 601 602 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') 609 610 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') 616 617 self.assertEqual(f'2\x20', '2 ') 618 self.assertEqual(f'2\x203', '2 3') 619 self.assertEqual(f'\x203', ' 3') 620 621 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 635 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'", 648 ]) 649 650 def test_no_backslashes_in_expression_part(self): 651 self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash', 652 [r"f'{\'a\'}'", 653 r"f'{\t3}'", 654 r"f'{\}'", 655 r"rf'{\'a\'}'", 656 r"rf'{\t3}'", 657 r"rf'{\}'", 658 r"""rf'{"\N{LEFT CURLY BRACKET}"}'""", 659 r"f'{\n}'", 660 ]) 661 662 def test_no_escapes_for_braces(self): 663 """ 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}') 671 672 def test_newlines_in_expressions(self): 673 self.assertEqual(f'{0}', '0') 674 self.assertEqual(rf'''{3+ 6754}''', '7') 676 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") 710 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') 811 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''", 828 "fb''", 829 "fB''", 830 "Fb''", 831 "FB''", 832 "bf''", 833 "bF''", 834 "Bf''", 835 "BF''", 836 ]) 837 838 def test_leading_trailing_spaces(self): 839 self.assertEqual(f'{ 3}', '3') 840 self.assertEqual(f'{ 3}', '3') 841 self.assertEqual(f'{3 }', '3') 842 self.assertEqual(f'{3 }', '3') 843 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 849 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 875 self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character', 876 ["f'{3!g}'", 877 "f'{3!A}'", 878 "f'{3!3}'", 879 "f'{3!G}'", 880 "f'{3!!}'", 881 "f'{3!:}'", 882 "f'{3! s}'", # no space before conversion char 883 ]) 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'", 912 r"f'\u007b}'", 913 914 # Can't have { or } in a format spec. 915 "f'{3:}>10}'", 916 "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'", 929 "f'{x'", 930 "f'{3:s'", 931 "f'{{{'", 932 "f'{{}}{'", 933 "f'{'", 934 ]) 935 936 # 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 1004 def test_errors(self): 1005 # see issue 26287 1006 self.assertAllRaise(TypeError, 'unsupported', 1007 [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 1015 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 } 1024 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') 1029 1030 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 1036 1037if __name__ == '__main__': 1038 unittest.main() 1039