1# -*- coding: utf-8 -*- 2# There are tests here with unicode string literals and 3# identifiers. There's a code in ast.c that was added because of a 4# failure with a non-ascii-only expression. So, I have tests for 5# that. There are workarounds that would let me run tests for that 6# code without unicode identifiers and strings, but just using them 7# directly seems like the easiest and therefore safest thing to do. 8# Unicode identifiers in tests is allowed by PEP 3131. 9 10import ast 11import os 12import re 13import types 14import decimal 15import unittest 16from test.support.os_helper import temp_cwd 17from test.support.script_helper import assert_python_failure 18 19a_global = 'global variable' 20 21# You could argue that I'm too strict in looking for specific error 22# values with assertRaisesRegex, but without it it's way too easy to 23# make a syntax error in the test strings. Especially with all of the 24# triple quotes, raw strings, backslashes, etc. I think it's a 25# worthwhile tradeoff. When I switched to this method, I found many 26# examples where I wasn't testing what I thought I was. 27 28class TestCase(unittest.TestCase): 29 def assertAllRaise(self, exception_type, regex, error_strings): 30 for str in error_strings: 31 with self.subTest(str=str): 32 with self.assertRaisesRegex(exception_type, regex): 33 eval(str) 34 35 def test__format__lookup(self): 36 # Make sure __format__ is looked up on the type, not the instance. 37 class X: 38 def __format__(self, spec): 39 return 'class' 40 41 x = X() 42 43 # Add a bound __format__ method to the 'y' instance, but not 44 # the 'x' instance. 45 y = X() 46 y.__format__ = types.MethodType(lambda self, spec: 'instance', y) 47 48 self.assertEqual(f'{y}', format(y)) 49 self.assertEqual(f'{y}', 'class') 50 self.assertEqual(format(x), format(y)) 51 52 # __format__ is not called this way, but still make sure it 53 # returns what we expect (so we can make sure we're bypassing 54 # it). 55 self.assertEqual(x.__format__(''), 'class') 56 self.assertEqual(y.__format__(''), 'instance') 57 58 # This is how __format__ is actually called. 59 self.assertEqual(type(x).__format__(x, ''), 'class') 60 self.assertEqual(type(y).__format__(y, ''), 'class') 61 62 def test_ast(self): 63 # Inspired by http://bugs.python.org/issue24975 64 class X: 65 def __init__(self): 66 self.called = False 67 def __call__(self): 68 self.called = True 69 return 4 70 x = X() 71 expr = """ 72a = 10 73f'{a * x()}'""" 74 t = ast.parse(expr) 75 c = compile(t, '', 'exec') 76 77 # Make sure x was not called. 78 self.assertFalse(x.called) 79 80 # Actually run the code. 81 exec(c) 82 83 # Make sure x was called. 84 self.assertTrue(x.called) 85 86 def test_ast_line_numbers(self): 87 expr = """ 88a = 10 89f'{a * x()}'""" 90 t = ast.parse(expr) 91 self.assertEqual(type(t), ast.Module) 92 self.assertEqual(len(t.body), 2) 93 # check `a = 10` 94 self.assertEqual(type(t.body[0]), ast.Assign) 95 self.assertEqual(t.body[0].lineno, 2) 96 # check `f'...'` 97 self.assertEqual(type(t.body[1]), ast.Expr) 98 self.assertEqual(type(t.body[1].value), ast.JoinedStr) 99 self.assertEqual(len(t.body[1].value.values), 1) 100 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue) 101 self.assertEqual(t.body[1].lineno, 3) 102 self.assertEqual(t.body[1].value.lineno, 3) 103 self.assertEqual(t.body[1].value.values[0].lineno, 3) 104 # check the binop location 105 binop = t.body[1].value.values[0].value 106 self.assertEqual(type(binop), ast.BinOp) 107 self.assertEqual(type(binop.left), ast.Name) 108 self.assertEqual(type(binop.op), ast.Mult) 109 self.assertEqual(type(binop.right), ast.Call) 110 self.assertEqual(binop.lineno, 3) 111 self.assertEqual(binop.left.lineno, 3) 112 self.assertEqual(binop.right.lineno, 3) 113 self.assertEqual(binop.col_offset, 3) 114 self.assertEqual(binop.left.col_offset, 3) 115 self.assertEqual(binop.right.col_offset, 7) 116 117 def test_ast_line_numbers_multiple_formattedvalues(self): 118 expr = """ 119f'no formatted values' 120f'eggs {a * x()} spam {b + y()}'""" 121 t = ast.parse(expr) 122 self.assertEqual(type(t), ast.Module) 123 self.assertEqual(len(t.body), 2) 124 # check `f'no formatted value'` 125 self.assertEqual(type(t.body[0]), ast.Expr) 126 self.assertEqual(type(t.body[0].value), ast.JoinedStr) 127 self.assertEqual(t.body[0].lineno, 2) 128 # check `f'...'` 129 self.assertEqual(type(t.body[1]), ast.Expr) 130 self.assertEqual(type(t.body[1].value), ast.JoinedStr) 131 self.assertEqual(len(t.body[1].value.values), 4) 132 self.assertEqual(type(t.body[1].value.values[0]), ast.Constant) 133 self.assertEqual(type(t.body[1].value.values[0].value), str) 134 self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue) 135 self.assertEqual(type(t.body[1].value.values[2]), ast.Constant) 136 self.assertEqual(type(t.body[1].value.values[2].value), str) 137 self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue) 138 self.assertEqual(t.body[1].lineno, 3) 139 self.assertEqual(t.body[1].value.lineno, 3) 140 self.assertEqual(t.body[1].value.values[0].lineno, 3) 141 self.assertEqual(t.body[1].value.values[1].lineno, 3) 142 self.assertEqual(t.body[1].value.values[2].lineno, 3) 143 self.assertEqual(t.body[1].value.values[3].lineno, 3) 144 # check the first binop location 145 binop1 = t.body[1].value.values[1].value 146 self.assertEqual(type(binop1), ast.BinOp) 147 self.assertEqual(type(binop1.left), ast.Name) 148 self.assertEqual(type(binop1.op), ast.Mult) 149 self.assertEqual(type(binop1.right), ast.Call) 150 self.assertEqual(binop1.lineno, 3) 151 self.assertEqual(binop1.left.lineno, 3) 152 self.assertEqual(binop1.right.lineno, 3) 153 self.assertEqual(binop1.col_offset, 8) 154 self.assertEqual(binop1.left.col_offset, 8) 155 self.assertEqual(binop1.right.col_offset, 12) 156 # check the second binop location 157 binop2 = t.body[1].value.values[3].value 158 self.assertEqual(type(binop2), ast.BinOp) 159 self.assertEqual(type(binop2.left), ast.Name) 160 self.assertEqual(type(binop2.op), ast.Add) 161 self.assertEqual(type(binop2.right), ast.Call) 162 self.assertEqual(binop2.lineno, 3) 163 self.assertEqual(binop2.left.lineno, 3) 164 self.assertEqual(binop2.right.lineno, 3) 165 self.assertEqual(binop2.col_offset, 23) 166 self.assertEqual(binop2.left.col_offset, 23) 167 self.assertEqual(binop2.right.col_offset, 27) 168 169 def test_ast_line_numbers_nested(self): 170 expr = """ 171a = 10 172f'{a * f"-{x()}-"}'""" 173 t = ast.parse(expr) 174 self.assertEqual(type(t), ast.Module) 175 self.assertEqual(len(t.body), 2) 176 # check `a = 10` 177 self.assertEqual(type(t.body[0]), ast.Assign) 178 self.assertEqual(t.body[0].lineno, 2) 179 # check `f'...'` 180 self.assertEqual(type(t.body[1]), ast.Expr) 181 self.assertEqual(type(t.body[1].value), ast.JoinedStr) 182 self.assertEqual(len(t.body[1].value.values), 1) 183 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue) 184 self.assertEqual(t.body[1].lineno, 3) 185 self.assertEqual(t.body[1].value.lineno, 3) 186 self.assertEqual(t.body[1].value.values[0].lineno, 3) 187 # check the binop location 188 binop = t.body[1].value.values[0].value 189 self.assertEqual(type(binop), ast.BinOp) 190 self.assertEqual(type(binop.left), ast.Name) 191 self.assertEqual(type(binop.op), ast.Mult) 192 self.assertEqual(type(binop.right), ast.JoinedStr) 193 self.assertEqual(binop.lineno, 3) 194 self.assertEqual(binop.left.lineno, 3) 195 self.assertEqual(binop.right.lineno, 3) 196 self.assertEqual(binop.col_offset, 3) 197 self.assertEqual(binop.left.col_offset, 3) 198 self.assertEqual(binop.right.col_offset, 7) 199 # check the nested call location 200 self.assertEqual(len(binop.right.values), 3) 201 self.assertEqual(type(binop.right.values[0]), ast.Constant) 202 self.assertEqual(type(binop.right.values[0].value), str) 203 self.assertEqual(type(binop.right.values[1]), ast.FormattedValue) 204 self.assertEqual(type(binop.right.values[2]), ast.Constant) 205 self.assertEqual(type(binop.right.values[2].value), str) 206 self.assertEqual(binop.right.values[0].lineno, 3) 207 self.assertEqual(binop.right.values[1].lineno, 3) 208 self.assertEqual(binop.right.values[2].lineno, 3) 209 call = binop.right.values[1].value 210 self.assertEqual(type(call), ast.Call) 211 self.assertEqual(call.lineno, 3) 212 self.assertEqual(call.col_offset, 11) 213 214 def test_ast_line_numbers_duplicate_expression(self): 215 expr = """ 216a = 10 217f'{a * x()} {a * x()} {a * x()}' 218""" 219 t = ast.parse(expr) 220 self.assertEqual(type(t), ast.Module) 221 self.assertEqual(len(t.body), 2) 222 # check `a = 10` 223 self.assertEqual(type(t.body[0]), ast.Assign) 224 self.assertEqual(t.body[0].lineno, 2) 225 # check `f'...'` 226 self.assertEqual(type(t.body[1]), ast.Expr) 227 self.assertEqual(type(t.body[1].value), ast.JoinedStr) 228 self.assertEqual(len(t.body[1].value.values), 5) 229 self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue) 230 self.assertEqual(type(t.body[1].value.values[1]), ast.Constant) 231 self.assertEqual(type(t.body[1].value.values[1].value), str) 232 self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue) 233 self.assertEqual(type(t.body[1].value.values[3]), ast.Constant) 234 self.assertEqual(type(t.body[1].value.values[3].value), str) 235 self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue) 236 self.assertEqual(t.body[1].lineno, 3) 237 self.assertEqual(t.body[1].value.lineno, 3) 238 self.assertEqual(t.body[1].value.values[0].lineno, 3) 239 self.assertEqual(t.body[1].value.values[1].lineno, 3) 240 self.assertEqual(t.body[1].value.values[2].lineno, 3) 241 self.assertEqual(t.body[1].value.values[3].lineno, 3) 242 self.assertEqual(t.body[1].value.values[4].lineno, 3) 243 # check the first binop location 244 binop = t.body[1].value.values[0].value 245 self.assertEqual(type(binop), ast.BinOp) 246 self.assertEqual(type(binop.left), ast.Name) 247 self.assertEqual(type(binop.op), ast.Mult) 248 self.assertEqual(type(binop.right), ast.Call) 249 self.assertEqual(binop.lineno, 3) 250 self.assertEqual(binop.left.lineno, 3) 251 self.assertEqual(binop.right.lineno, 3) 252 self.assertEqual(binop.col_offset, 3) 253 self.assertEqual(binop.left.col_offset, 3) 254 self.assertEqual(binop.right.col_offset, 7) 255 # check the second binop location 256 binop = t.body[1].value.values[2].value 257 self.assertEqual(type(binop), ast.BinOp) 258 self.assertEqual(type(binop.left), ast.Name) 259 self.assertEqual(type(binop.op), ast.Mult) 260 self.assertEqual(type(binop.right), ast.Call) 261 self.assertEqual(binop.lineno, 3) 262 self.assertEqual(binop.left.lineno, 3) 263 self.assertEqual(binop.right.lineno, 3) 264 self.assertEqual(binop.col_offset, 13) 265 self.assertEqual(binop.left.col_offset, 13) 266 self.assertEqual(binop.right.col_offset, 17) 267 # check the third binop location 268 binop = t.body[1].value.values[4].value 269 self.assertEqual(type(binop), ast.BinOp) 270 self.assertEqual(type(binop.left), ast.Name) 271 self.assertEqual(type(binop.op), ast.Mult) 272 self.assertEqual(type(binop.right), ast.Call) 273 self.assertEqual(binop.lineno, 3) 274 self.assertEqual(binop.left.lineno, 3) 275 self.assertEqual(binop.right.lineno, 3) 276 self.assertEqual(binop.col_offset, 23) 277 self.assertEqual(binop.left.col_offset, 23) 278 self.assertEqual(binop.right.col_offset, 27) 279 280 def test_ast_numbers_fstring_with_formatting(self): 281 282 t = ast.parse('f"Here is that pesky {xxx:.3f} again"') 283 self.assertEqual(len(t.body), 1) 284 self.assertEqual(t.body[0].lineno, 1) 285 286 self.assertEqual(type(t.body[0]), ast.Expr) 287 self.assertEqual(type(t.body[0].value), ast.JoinedStr) 288 self.assertEqual(len(t.body[0].value.values), 3) 289 290 self.assertEqual(type(t.body[0].value.values[0]), ast.Constant) 291 self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue) 292 self.assertEqual(type(t.body[0].value.values[2]), ast.Constant) 293 294 _, expr, _ = t.body[0].value.values 295 296 name = expr.value 297 self.assertEqual(type(name), ast.Name) 298 self.assertEqual(name.lineno, 1) 299 self.assertEqual(name.end_lineno, 1) 300 self.assertEqual(name.col_offset, 22) 301 self.assertEqual(name.end_col_offset, 25) 302 303 def test_ast_line_numbers_multiline_fstring(self): 304 # See bpo-30465 for details. 305 expr = """ 306a = 10 307f''' 308 {a 309 * 310 x()} 311non-important content 312''' 313""" 314 t = ast.parse(expr) 315 self.assertEqual(type(t), ast.Module) 316 self.assertEqual(len(t.body), 2) 317 # check `a = 10` 318 self.assertEqual(type(t.body[0]), ast.Assign) 319 self.assertEqual(t.body[0].lineno, 2) 320 # check `f'...'` 321 self.assertEqual(type(t.body[1]), ast.Expr) 322 self.assertEqual(type(t.body[1].value), ast.JoinedStr) 323 self.assertEqual(len(t.body[1].value.values), 3) 324 self.assertEqual(type(t.body[1].value.values[0]), ast.Constant) 325 self.assertEqual(type(t.body[1].value.values[0].value), str) 326 self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue) 327 self.assertEqual(type(t.body[1].value.values[2]), ast.Constant) 328 self.assertEqual(type(t.body[1].value.values[2].value), str) 329 self.assertEqual(t.body[1].lineno, 3) 330 self.assertEqual(t.body[1].value.lineno, 3) 331 self.assertEqual(t.body[1].value.values[0].lineno, 3) 332 self.assertEqual(t.body[1].value.values[1].lineno, 3) 333 self.assertEqual(t.body[1].value.values[2].lineno, 3) 334 self.assertEqual(t.body[1].col_offset, 0) 335 self.assertEqual(t.body[1].value.col_offset, 0) 336 self.assertEqual(t.body[1].value.values[0].col_offset, 0) 337 self.assertEqual(t.body[1].value.values[1].col_offset, 0) 338 self.assertEqual(t.body[1].value.values[2].col_offset, 0) 339 # NOTE: the following lineno information and col_offset is correct for 340 # expressions within FormattedValues. 341 binop = t.body[1].value.values[1].value 342 self.assertEqual(type(binop), ast.BinOp) 343 self.assertEqual(type(binop.left), ast.Name) 344 self.assertEqual(type(binop.op), ast.Mult) 345 self.assertEqual(type(binop.right), ast.Call) 346 self.assertEqual(binop.lineno, 4) 347 self.assertEqual(binop.left.lineno, 4) 348 self.assertEqual(binop.right.lineno, 6) 349 self.assertEqual(binop.col_offset, 4) 350 self.assertEqual(binop.left.col_offset, 4) 351 self.assertEqual(binop.right.col_offset, 7) 352 353 def test_ast_line_numbers_with_parentheses(self): 354 expr = """ 355x = ( 356 f" {test(t)}" 357)""" 358 t = ast.parse(expr) 359 self.assertEqual(type(t), ast.Module) 360 self.assertEqual(len(t.body), 1) 361 # check the test(t) location 362 call = t.body[0].value.values[1].value 363 self.assertEqual(type(call), ast.Call) 364 self.assertEqual(call.lineno, 3) 365 self.assertEqual(call.end_lineno, 3) 366 self.assertEqual(call.col_offset, 8) 367 self.assertEqual(call.end_col_offset, 15) 368 369 expr = """ 370x = ( 371 'PERL_MM_OPT', ( 372 f'wat' 373 f'some_string={f(x)} ' 374 f'wat' 375 ), 376) 377""" 378 t = ast.parse(expr) 379 self.assertEqual(type(t), ast.Module) 380 self.assertEqual(len(t.body), 1) 381 # check the fstring 382 fstring = t.body[0].value.elts[1] 383 self.assertEqual(type(fstring), ast.JoinedStr) 384 self.assertEqual(len(fstring.values), 3) 385 wat1, middle, wat2 = fstring.values 386 # check the first wat 387 self.assertEqual(type(wat1), ast.Constant) 388 self.assertEqual(wat1.lineno, 4) 389 self.assertEqual(wat1.end_lineno, 6) 390 self.assertEqual(wat1.col_offset, 12) 391 self.assertEqual(wat1.end_col_offset, 18) 392 # check the call 393 call = middle.value 394 self.assertEqual(type(call), ast.Call) 395 self.assertEqual(call.lineno, 5) 396 self.assertEqual(call.end_lineno, 5) 397 self.assertEqual(call.col_offset, 27) 398 self.assertEqual(call.end_col_offset, 31) 399 # check the second wat 400 self.assertEqual(type(wat2), ast.Constant) 401 self.assertEqual(wat2.lineno, 4) 402 self.assertEqual(wat2.end_lineno, 6) 403 self.assertEqual(wat2.col_offset, 12) 404 self.assertEqual(wat2.end_col_offset, 18) 405 406 def test_docstring(self): 407 def f(): 408 f'''Not a docstring''' 409 self.assertIsNone(f.__doc__) 410 def g(): 411 '''Not a docstring''' \ 412 f'' 413 self.assertIsNone(g.__doc__) 414 415 def test_literal_eval(self): 416 with self.assertRaisesRegex(ValueError, 'malformed node or string'): 417 ast.literal_eval("f'x'") 418 419 def test_ast_compile_time_concat(self): 420 x = [''] 421 422 expr = """x[0] = 'foo' f'{3}'""" 423 t = ast.parse(expr) 424 c = compile(t, '', 'exec') 425 exec(c) 426 self.assertEqual(x[0], 'foo3') 427 428 def test_compile_time_concat_errors(self): 429 self.assertAllRaise(SyntaxError, 430 'cannot mix bytes and nonbytes literals', 431 [r"""f'' b''""", 432 r"""b'' f''""", 433 ]) 434 435 def test_literal(self): 436 self.assertEqual(f'', '') 437 self.assertEqual(f'a', 'a') 438 self.assertEqual(f' ', ' ') 439 440 def test_unterminated_string(self): 441 self.assertAllRaise(SyntaxError, 'f-string: unterminated string', 442 [r"""f'{"x'""", 443 r"""f'{"x}'""", 444 r"""f'{("x'""", 445 r"""f'{("x}'""", 446 ]) 447 448 def test_mismatched_parens(self): 449 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' " 450 r"does not match opening parenthesis '\('", 451 ["f'{((}'", 452 ]) 453 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\)' " 454 r"does not match opening parenthesis '\['", 455 ["f'{a[4)}'", 456 ]) 457 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\]' " 458 r"does not match opening parenthesis '\('", 459 ["f'{a(4]}'", 460 ]) 461 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' " 462 r"does not match opening parenthesis '\['", 463 ["f'{a[4}'", 464 ]) 465 self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' " 466 r"does not match opening parenthesis '\('", 467 ["f'{a(4}'", 468 ]) 469 self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'") 470 471 def test_double_braces(self): 472 self.assertEqual(f'{{', '{') 473 self.assertEqual(f'a{{', 'a{') 474 self.assertEqual(f'{{b', '{b') 475 self.assertEqual(f'a{{b', 'a{b') 476 self.assertEqual(f'}}', '}') 477 self.assertEqual(f'a}}', 'a}') 478 self.assertEqual(f'}}b', '}b') 479 self.assertEqual(f'a}}b', 'a}b') 480 self.assertEqual(f'{{}}', '{}') 481 self.assertEqual(f'a{{}}', 'a{}') 482 self.assertEqual(f'{{b}}', '{b}') 483 self.assertEqual(f'{{}}c', '{}c') 484 self.assertEqual(f'a{{b}}', 'a{b}') 485 self.assertEqual(f'a{{}}c', 'a{}c') 486 self.assertEqual(f'{{b}}c', '{b}c') 487 self.assertEqual(f'a{{b}}c', 'a{b}c') 488 489 self.assertEqual(f'{{{10}', '{10') 490 self.assertEqual(f'}}{10}', '}10') 491 self.assertEqual(f'}}{{{10}', '}{10') 492 self.assertEqual(f'}}a{{{10}', '}a{10') 493 494 self.assertEqual(f'{10}{{', '10{') 495 self.assertEqual(f'{10}}}', '10}') 496 self.assertEqual(f'{10}}}{{', '10}{') 497 self.assertEqual(f'{10}}}a{{' '}', '10}a{}') 498 499 # Inside of strings, don't interpret doubled brackets. 500 self.assertEqual(f'{"{{}}"}', '{{}}') 501 502 self.assertAllRaise(TypeError, 'unhashable type', 503 ["f'{ {{}} }'", # dict in a set 504 ]) 505 506 def test_compile_time_concat(self): 507 x = 'def' 508 self.assertEqual('abc' f'## {x}ghi', 'abc## defghi') 509 self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi') 510 self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ') 511 self.assertEqual('{x}' f'{x}', '{x}def') 512 self.assertEqual('{x' f'{x}', '{xdef') 513 self.assertEqual('{x}' f'{x}', '{x}def') 514 self.assertEqual('{{x}}' f'{x}', '{{x}}def') 515 self.assertEqual('{{x' f'{x}', '{{xdef') 516 self.assertEqual('x}}' f'{x}', 'x}}def') 517 self.assertEqual(f'{x}' 'x}}', 'defx}}') 518 self.assertEqual(f'{x}' '', 'def') 519 self.assertEqual('' f'{x}' '', 'def') 520 self.assertEqual('' f'{x}', 'def') 521 self.assertEqual(f'{x}' '2', 'def2') 522 self.assertEqual('1' f'{x}' '2', '1def2') 523 self.assertEqual('1' f'{x}', '1def') 524 self.assertEqual(f'{x}' f'-{x}', 'def-def') 525 self.assertEqual('' f'', '') 526 self.assertEqual('' f'' '', '') 527 self.assertEqual('' f'' '' f'', '') 528 self.assertEqual(f'', '') 529 self.assertEqual(f'' '', '') 530 self.assertEqual(f'' '' f'', '') 531 self.assertEqual(f'' '' f'' '', '') 532 533 self.assertAllRaise(SyntaxError, "f-string: expecting '}'", 534 ["f'{3' f'}'", # can't concat to get a valid f-string 535 ]) 536 537 def test_comments(self): 538 # These aren't comments, since they're in strings. 539 d = {'#': 'hash'} 540 self.assertEqual(f'{"#"}', '#') 541 self.assertEqual(f'{d["#"]}', 'hash') 542 543 self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'", 544 ["f'{1#}'", # error because the expression becomes "(1#)" 545 "f'{3(#)}'", 546 "f'{#}'", 547 ]) 548 self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'", 549 ["f'{)#}'", # When wrapped in parens, this becomes 550 # '()#)'. Make sure that doesn't compile. 551 ]) 552 553 def test_many_expressions(self): 554 # Create a string with many expressions in it. Note that 555 # because we have a space in here as a literal, we're actually 556 # going to use twice as many ast nodes: one for each literal 557 # plus one for each expression. 558 def build_fstr(n, extra=''): 559 return "f'" + ('{x} ' * n) + extra + "'" 560 561 x = 'X' 562 width = 1 563 564 # Test around 256. 565 for i in range(250, 260): 566 self.assertEqual(eval(build_fstr(i)), (x+' ')*i) 567 568 # Test concatenating 2 largs fstrings. 569 self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256)) 570 571 s = build_fstr(253, '{x:{width}} ') 572 self.assertEqual(eval(s), (x+' ')*254) 573 574 # Test lots of expressions and constants, concatenated. 575 s = "f'{1}' 'x' 'y'" * 1024 576 self.assertEqual(eval(s), '1xy' * 1024) 577 578 def test_format_specifier_expressions(self): 579 width = 10 580 precision = 4 581 value = decimal.Decimal('12.34567') 582 self.assertEqual(f'result: {value:{width}.{precision}}', 'result: 12.35') 583 self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result: 12.35') 584 self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result: 12.35') 585 self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result: 12.35') 586 self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result: 12.35') 587 self.assertEqual(f'{10:#{1}0x}', ' 0xa') 588 self.assertEqual(f'{10:{"#"}1{0}{"x"}}', ' 0xa') 589 self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa') 590 self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa') 591 self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa') 592 593 self.assertAllRaise(SyntaxError, "f-string: expecting '}'", 594 ["""f'{"s"!r{":10"}}'""", 595 596 # This looks like a nested format spec. 597 ]) 598 599 self.assertAllRaise(SyntaxError, "f-string: invalid syntax", 600 [# Invalid syntax inside a nested spec. 601 "f'{4:{/5}}'", 602 ]) 603 604 self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply", 605 [# Can't nest format specifiers. 606 "f'result: {value:{width:{0}}.{precision:1}}'", 607 ]) 608 609 self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character', 610 [# No expansion inside conversion or for 611 # the : or ! itself. 612 """f'{"s"!{"r"}}'""", 613 ]) 614 615 def test_side_effect_order(self): 616 class X: 617 def __init__(self): 618 self.i = 0 619 def __format__(self, spec): 620 self.i += 1 621 return str(self.i) 622 623 x = X() 624 self.assertEqual(f'{x} {x}', '1 2') 625 626 def test_missing_expression(self): 627 self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed', 628 ["f'{}'", 629 "f'{ }'" 630 "f' {} '", 631 "f'{!r}'", 632 "f'{ !r}'", 633 "f'{10:{ }}'", 634 "f' { } '", 635 636 # The Python parser ignores also the following 637 # whitespace characters in additional to a space. 638 "f'''{\t\f\r\n}'''", 639 640 # Catch the empty expression before the 641 # invalid conversion. 642 "f'{!x}'", 643 "f'{ !xr}'", 644 "f'{!x:}'", 645 "f'{!x:a}'", 646 "f'{ !xr:}'", 647 "f'{ !xr:a}'", 648 649 "f'{!}'", 650 "f'{:}'", 651 652 # We find the empty expression before the 653 # missing closing brace. 654 "f'{!'", 655 "f'{!s:'", 656 "f'{:'", 657 "f'{:x'", 658 ]) 659 660 # Different error message is raised for other whitespace characters. 661 self.assertAllRaise(SyntaxError, r"invalid non-printable character U\+00A0", 662 ["f'''{\xa0}'''", 663 "\xa0", 664 ]) 665 666 def test_parens_in_expressions(self): 667 self.assertEqual(f'{3,}', '(3,)') 668 669 # Add these because when an expression is evaluated, parens 670 # are added around it. But we shouldn't go from an invalid 671 # expression to a valid one. The added parens are just 672 # supposed to allow whitespace (including newlines). 673 self.assertAllRaise(SyntaxError, 'f-string: invalid syntax', 674 ["f'{,}'", 675 "f'{,}'", # this is (,), which is an error 676 ]) 677 678 self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'", 679 ["f'{3)+(4}'", 680 ]) 681 682 self.assertAllRaise(SyntaxError, 'unterminated string literal', 683 ["f'{\n}'", 684 ]) 685 def test_newlines_before_syntax_error(self): 686 self.assertAllRaise(SyntaxError, "invalid syntax", 687 ["f'{.}'", "\nf'{.}'", "\n\nf'{.}'"]) 688 689 def test_backslashes_in_string_part(self): 690 self.assertEqual(f'\t', '\t') 691 self.assertEqual(r'\t', '\\t') 692 self.assertEqual(rf'\t', '\\t') 693 self.assertEqual(f'{2}\t', '2\t') 694 self.assertEqual(f'{2}\t{3}', '2\t3') 695 self.assertEqual(f'\t{3}', '\t3') 696 697 self.assertEqual(f'\u0394', '\u0394') 698 self.assertEqual(r'\u0394', '\\u0394') 699 self.assertEqual(rf'\u0394', '\\u0394') 700 self.assertEqual(f'{2}\u0394', '2\u0394') 701 self.assertEqual(f'{2}\u0394{3}', '2\u03943') 702 self.assertEqual(f'\u0394{3}', '\u03943') 703 704 self.assertEqual(f'\U00000394', '\u0394') 705 self.assertEqual(r'\U00000394', '\\U00000394') 706 self.assertEqual(rf'\U00000394', '\\U00000394') 707 self.assertEqual(f'{2}\U00000394', '2\u0394') 708 self.assertEqual(f'{2}\U00000394{3}', '2\u03943') 709 self.assertEqual(f'\U00000394{3}', '\u03943') 710 711 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394') 712 self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394') 713 self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943') 714 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943') 715 self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394') 716 self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943') 717 self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943') 718 719 self.assertEqual(f'\x20', ' ') 720 self.assertEqual(r'\x20', '\\x20') 721 self.assertEqual(rf'\x20', '\\x20') 722 self.assertEqual(f'{2}\x20', '2 ') 723 self.assertEqual(f'{2}\x20{3}', '2 3') 724 self.assertEqual(f'\x20{3}', ' 3') 725 726 self.assertEqual(f'2\x20', '2 ') 727 self.assertEqual(f'2\x203', '2 3') 728 self.assertEqual(f'\x203', ' 3') 729 730 with self.assertWarns(DeprecationWarning): # invalid escape sequence 731 value = eval(r"f'\{6*7}'") 732 self.assertEqual(value, '\\42') 733 self.assertEqual(f'\\{6*7}', '\\42') 734 self.assertEqual(fr'\{6*7}', '\\42') 735 736 AMPERSAND = 'spam' 737 # Get the right unicode character (&), or pick up local variable 738 # depending on the number of backslashes. 739 self.assertEqual(f'\N{AMPERSAND}', '&') 740 self.assertEqual(f'\\N{AMPERSAND}', '\\Nspam') 741 self.assertEqual(fr'\N{AMPERSAND}', '\\Nspam') 742 self.assertEqual(f'\\\N{AMPERSAND}', '\\&') 743 744 def test_misformed_unicode_character_name(self): 745 # These test are needed because unicode names are parsed 746 # differently inside f-strings. 747 self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape", 748 [r"f'\N'", 749 r"f'\N{'", 750 r"f'\N{GREEK CAPITAL LETTER DELTA'", 751 752 # Here are the non-f-string versions, 753 # which should give the same errors. 754 r"'\N'", 755 r"'\N{'", 756 r"'\N{GREEK CAPITAL LETTER DELTA'", 757 ]) 758 759 def test_no_backslashes_in_expression_part(self): 760 self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash', 761 [r"f'{\'a\'}'", 762 r"f'{\t3}'", 763 r"f'{\}'", 764 r"rf'{\'a\'}'", 765 r"rf'{\t3}'", 766 r"rf'{\}'", 767 r"""rf'{"\N{LEFT CURLY BRACKET}"}'""", 768 r"f'{\n}'", 769 ]) 770 771 def test_no_escapes_for_braces(self): 772 """ 773 Only literal curly braces begin an expression. 774 """ 775 # \x7b is '{'. 776 self.assertEqual(f'\x7b1+1}}', '{1+1}') 777 self.assertEqual(f'\x7b1+1', '{1+1') 778 self.assertEqual(f'\u007b1+1', '{1+1') 779 self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}') 780 781 def test_newlines_in_expressions(self): 782 self.assertEqual(f'{0}', '0') 783 self.assertEqual(rf'''{3+ 7844}''', '7') 785 786 def test_lambda(self): 787 x = 5 788 self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'") 789 self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888' ") 790 self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888 ") 791 792 # lambda doesn't work without parens, because the colon 793 # makes the parser think it's a format_spec 794 self.assertAllRaise(SyntaxError, 'f-string: invalid syntax', 795 ["f'{lambda x:x}'", 796 ]) 797 798 def test_yield(self): 799 # Not terribly useful, but make sure the yield turns 800 # a function into a generator 801 def fn(y): 802 f'y:{yield y*2}' 803 f'{yield}' 804 805 g = fn(4) 806 self.assertEqual(next(g), 8) 807 self.assertEqual(next(g), None) 808 809 def test_yield_send(self): 810 def fn(x): 811 yield f'x:{yield (lambda i: x * i)}' 812 813 g = fn(10) 814 the_lambda = next(g) 815 self.assertEqual(the_lambda(4), 40) 816 self.assertEqual(g.send('string'), 'x:string') 817 818 def test_expressions_with_triple_quoted_strings(self): 819 self.assertEqual(f"{'''x'''}", 'x') 820 self.assertEqual(f"{'''eric's'''}", "eric's") 821 822 # Test concatenation within an expression 823 self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy') 824 self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s') 825 self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy') 826 self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy') 827 self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy') 828 self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy') 829 830 def test_multiple_vars(self): 831 x = 98 832 y = 'abc' 833 self.assertEqual(f'{x}{y}', '98abc') 834 835 self.assertEqual(f'X{x}{y}', 'X98abc') 836 self.assertEqual(f'{x}X{y}', '98Xabc') 837 self.assertEqual(f'{x}{y}X', '98abcX') 838 839 self.assertEqual(f'X{x}Y{y}', 'X98Yabc') 840 self.assertEqual(f'X{x}{y}Y', 'X98abcY') 841 self.assertEqual(f'{x}X{y}Y', '98XabcY') 842 843 self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ') 844 845 def test_closure(self): 846 def outer(x): 847 def inner(): 848 return f'x:{x}' 849 return inner 850 851 self.assertEqual(outer('987')(), 'x:987') 852 self.assertEqual(outer(7)(), 'x:7') 853 854 def test_arguments(self): 855 y = 2 856 def f(x, width): 857 return f'x={x*y:{width}}' 858 859 self.assertEqual(f('foo', 10), 'x=foofoo ') 860 x = 'bar' 861 self.assertEqual(f(10, 10), 'x= 20') 862 863 def test_locals(self): 864 value = 123 865 self.assertEqual(f'v:{value}', 'v:123') 866 867 def test_missing_variable(self): 868 with self.assertRaises(NameError): 869 f'v:{value}' 870 871 def test_missing_format_spec(self): 872 class O: 873 def __format__(self, spec): 874 if not spec: 875 return '*' 876 return spec 877 878 self.assertEqual(f'{O():x}', 'x') 879 self.assertEqual(f'{O()}', '*') 880 self.assertEqual(f'{O():}', '*') 881 882 self.assertEqual(f'{3:}', '3') 883 self.assertEqual(f'{3!s:}', '3') 884 885 def test_global(self): 886 self.assertEqual(f'g:{a_global}', 'g:global variable') 887 self.assertEqual(f'g:{a_global!r}', "g:'global variable'") 888 889 a_local = 'local variable' 890 self.assertEqual(f'g:{a_global} l:{a_local}', 891 'g:global variable l:local variable') 892 self.assertEqual(f'g:{a_global!r}', 893 "g:'global variable'") 894 self.assertEqual(f'g:{a_global} l:{a_local!r}', 895 "g:global variable l:'local variable'") 896 897 self.assertIn("module 'unittest' from", f'{unittest}') 898 899 def test_shadowed_global(self): 900 a_global = 'really a local' 901 self.assertEqual(f'g:{a_global}', 'g:really a local') 902 self.assertEqual(f'g:{a_global!r}', "g:'really a local'") 903 904 a_local = 'local variable' 905 self.assertEqual(f'g:{a_global} l:{a_local}', 906 'g:really a local l:local variable') 907 self.assertEqual(f'g:{a_global!r}', 908 "g:'really a local'") 909 self.assertEqual(f'g:{a_global} l:{a_local!r}', 910 "g:really a local l:'local variable'") 911 912 def test_call(self): 913 def foo(x): 914 return 'x=' + str(x) 915 916 self.assertEqual(f'{foo(10)}', 'x=10') 917 918 def test_nested_fstrings(self): 919 y = 5 920 self.assertEqual(f'{f"{0}"*3}', '000') 921 self.assertEqual(f'{f"{y}"*3}', '555') 922 923 def test_invalid_string_prefixes(self): 924 single_quote_cases = ["fu''", 925 "uf''", 926 "Fu''", 927 "fU''", 928 "Uf''", 929 "uF''", 930 "ufr''", 931 "urf''", 932 "fur''", 933 "fru''", 934 "rfu''", 935 "ruf''", 936 "FUR''", 937 "Fur''", 938 "fb''", 939 "fB''", 940 "Fb''", 941 "FB''", 942 "bf''", 943 "bF''", 944 "Bf''", 945 "BF''",] 946 double_quote_cases = [case.replace("'", '"') for case in single_quote_cases] 947 self.assertAllRaise(SyntaxError, 'invalid syntax', 948 single_quote_cases + double_quote_cases) 949 950 def test_leading_trailing_spaces(self): 951 self.assertEqual(f'{ 3}', '3') 952 self.assertEqual(f'{ 3}', '3') 953 self.assertEqual(f'{3 }', '3') 954 self.assertEqual(f'{3 }', '3') 955 956 self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}', 957 'expr={1: 2}') 958 self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }', 959 'expr={1: 2}') 960 961 def test_not_equal(self): 962 # There's a special test for this because there's a special 963 # case in the f-string parser to look for != as not ending an 964 # expression. Normally it would, while looking for !s or !r. 965 966 self.assertEqual(f'{3!=4}', 'True') 967 self.assertEqual(f'{3!=4:}', 'True') 968 self.assertEqual(f'{3!=4!s}', 'True') 969 self.assertEqual(f'{3!=4!s:.3}', 'Tru') 970 971 def test_equal_equal(self): 972 # Because an expression ending in = has special meaning, 973 # there's a special test for ==. Make sure it works. 974 975 self.assertEqual(f'{0==1}', 'False') 976 977 def test_conversions(self): 978 self.assertEqual(f'{3.14:10.10}', ' 3.14') 979 self.assertEqual(f'{3.14!s:10.10}', '3.14 ') 980 self.assertEqual(f'{3.14!r:10.10}', '3.14 ') 981 self.assertEqual(f'{3.14!a:10.10}', '3.14 ') 982 983 self.assertEqual(f'{"a"}', 'a') 984 self.assertEqual(f'{"a"!r}', "'a'") 985 self.assertEqual(f'{"a"!a}', "'a'") 986 987 # Not a conversion. 988 self.assertEqual(f'{"a!r"}', "a!r") 989 990 # Not a conversion, but show that ! is allowed in a format spec. 991 self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!') 992 993 self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character', 994 ["f'{3!g}'", 995 "f'{3!A}'", 996 "f'{3!3}'", 997 "f'{3!G}'", 998 "f'{3!!}'", 999 "f'{3!:}'", 1000 "f'{3! s}'", # no space before conversion char 1001 ]) 1002 1003 self.assertAllRaise(SyntaxError, "f-string: expecting '}'", 1004 ["f'{x!s{y}}'", 1005 "f'{3!ss}'", 1006 "f'{3!ss:}'", 1007 "f'{3!ss:s}'", 1008 ]) 1009 1010 def test_assignment(self): 1011 self.assertAllRaise(SyntaxError, r'invalid syntax', 1012 ["f'' = 3", 1013 "f'{0}' = x", 1014 "f'{x}' = x", 1015 ]) 1016 1017 def test_del(self): 1018 self.assertAllRaise(SyntaxError, 'invalid syntax', 1019 ["del f''", 1020 "del '' f''", 1021 ]) 1022 1023 def test_mismatched_braces(self): 1024 self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed", 1025 ["f'{{}'", 1026 "f'{{}}}'", 1027 "f'}'", 1028 "f'x}'", 1029 "f'x}x'", 1030 r"f'\u007b}'", 1031 1032 # Can't have { or } in a format spec. 1033 "f'{3:}>10}'", 1034 "f'{3:}}>10}'", 1035 ]) 1036 1037 self.assertAllRaise(SyntaxError, "f-string: expecting '}'", 1038 ["f'{3:{{>10}'", 1039 "f'{3'", 1040 "f'{3!'", 1041 "f'{3:'", 1042 "f'{3!s'", 1043 "f'{3!s:'", 1044 "f'{3!s:3'", 1045 "f'x{'", 1046 "f'x{x'", 1047 "f'{x'", 1048 "f'{3:s'", 1049 "f'{{{'", 1050 "f'{{}}{'", 1051 "f'{'", 1052 ]) 1053 1054 # But these are just normal strings. 1055 self.assertEqual(f'{"{"}', '{') 1056 self.assertEqual(f'{"}"}', '}') 1057 self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3') 1058 self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2') 1059 1060 def test_if_conditional(self): 1061 # There's special logic in compile.c to test if the 1062 # conditional for an if (and while) are constants. Exercise 1063 # that code. 1064 1065 def test_fstring(x, expected): 1066 flag = 0 1067 if f'{x}': 1068 flag = 1 1069 else: 1070 flag = 2 1071 self.assertEqual(flag, expected) 1072 1073 def test_concat_empty(x, expected): 1074 flag = 0 1075 if '' f'{x}': 1076 flag = 1 1077 else: 1078 flag = 2 1079 self.assertEqual(flag, expected) 1080 1081 def test_concat_non_empty(x, expected): 1082 flag = 0 1083 if ' ' f'{x}': 1084 flag = 1 1085 else: 1086 flag = 2 1087 self.assertEqual(flag, expected) 1088 1089 test_fstring('', 2) 1090 test_fstring(' ', 1) 1091 1092 test_concat_empty('', 2) 1093 test_concat_empty(' ', 1) 1094 1095 test_concat_non_empty('', 1) 1096 test_concat_non_empty(' ', 1) 1097 1098 def test_empty_format_specifier(self): 1099 x = 'test' 1100 self.assertEqual(f'{x}', 'test') 1101 self.assertEqual(f'{x:}', 'test') 1102 self.assertEqual(f'{x!s:}', 'test') 1103 self.assertEqual(f'{x!r:}', "'test'") 1104 1105 def test_str_format_differences(self): 1106 d = {'a': 'string', 1107 0: 'integer', 1108 } 1109 a = 0 1110 self.assertEqual(f'{d[0]}', 'integer') 1111 self.assertEqual(f'{d["a"]}', 'string') 1112 self.assertEqual(f'{d[a]}', 'integer') 1113 self.assertEqual('{d[a]}'.format(d=d), 'string') 1114 self.assertEqual('{d[0]}'.format(d=d), 'integer') 1115 1116 def test_errors(self): 1117 # see issue 26287 1118 self.assertAllRaise(TypeError, 'unsupported', 1119 [r"f'{(lambda: 0):x}'", 1120 r"f'{(0,):x}'", 1121 ]) 1122 self.assertAllRaise(ValueError, 'Unknown format code', 1123 [r"f'{1000:j}'", 1124 r"f'{1000:j}'", 1125 ]) 1126 1127 def test_filename_in_syntaxerror(self): 1128 # see issue 38964 1129 with temp_cwd() as cwd: 1130 file_path = os.path.join(cwd, 't.py') 1131 with open(file_path, 'w', encoding="utf-8") as f: 1132 f.write('f"{a b}"') # This generates a SyntaxError 1133 _, _, stderr = assert_python_failure(file_path, 1134 PYTHONIOENCODING='ascii') 1135 self.assertIn(file_path.encode('ascii', 'backslashreplace'), stderr) 1136 1137 def test_loop(self): 1138 for i in range(1000): 1139 self.assertEqual(f'i:{i}', 'i:' + str(i)) 1140 1141 def test_dict(self): 1142 d = {'"': 'dquote', 1143 "'": 'squote', 1144 'foo': 'bar', 1145 } 1146 self.assertEqual(f'''{d["'"]}''', 'squote') 1147 self.assertEqual(f"""{d['"']}""", 'dquote') 1148 1149 self.assertEqual(f'{d["foo"]}', 'bar') 1150 self.assertEqual(f"{d['foo']}", 'bar') 1151 1152 def test_backslash_char(self): 1153 # Check eval of a backslash followed by a control char. 1154 # See bpo-30682: this used to raise an assert in pydebug mode. 1155 self.assertEqual(eval('f"\\\n"'), '') 1156 self.assertEqual(eval('f"\\\r"'), '') 1157 1158 def test_debug_conversion(self): 1159 x = 'A string' 1160 self.assertEqual(f'{x=}', 'x=' + repr(x)) 1161 self.assertEqual(f'{x =}', 'x =' + repr(x)) 1162 self.assertEqual(f'{x=!s}', 'x=' + str(x)) 1163 self.assertEqual(f'{x=!r}', 'x=' + repr(x)) 1164 self.assertEqual(f'{x=!a}', 'x=' + ascii(x)) 1165 1166 x = 2.71828 1167 self.assertEqual(f'{x=:.2f}', 'x=' + format(x, '.2f')) 1168 self.assertEqual(f'{x=:}', 'x=' + format(x, '')) 1169 self.assertEqual(f'{x=!r:^20}', 'x=' + format(repr(x), '^20')) 1170 self.assertEqual(f'{x=!s:^20}', 'x=' + format(str(x), '^20')) 1171 self.assertEqual(f'{x=!a:^20}', 'x=' + format(ascii(x), '^20')) 1172 1173 x = 9 1174 self.assertEqual(f'{3*x+15=}', '3*x+15=42') 1175 1176 # There is code in ast.c that deals with non-ascii expression values. So, 1177 # use a unicode identifier to trigger that. 1178 tenπ = 31.4 1179 self.assertEqual(f'{tenπ=:.2f}', 'tenπ=31.40') 1180 1181 # Also test with Unicode in non-identifiers. 1182 self.assertEqual(f'{"Σ"=}', '"Σ"=\'Σ\'') 1183 1184 # Make sure nested fstrings still work. 1185 self.assertEqual(f'{f"{3.1415=:.1f}":*^20}', '*****3.1415=3.1*****') 1186 1187 # Make sure text before and after an expression with = works 1188 # correctly. 1189 pi = 'π' 1190 self.assertEqual(f'alpha α {pi=} ω omega', "alpha α pi='π' ω omega") 1191 1192 # Check multi-line expressions. 1193 self.assertEqual(f'''{ 11943 1195=}''', '\n3\n=3') 1196 1197 # Since = is handled specially, make sure all existing uses of 1198 # it still work. 1199 1200 self.assertEqual(f'{0==1}', 'False') 1201 self.assertEqual(f'{0!=1}', 'True') 1202 self.assertEqual(f'{0<=1}', 'True') 1203 self.assertEqual(f'{0>=1}', 'False') 1204 self.assertEqual(f'{(x:="5")}', '5') 1205 self.assertEqual(x, '5') 1206 self.assertEqual(f'{(x:=5)}', '5') 1207 self.assertEqual(x, 5) 1208 self.assertEqual(f'{"="}', '=') 1209 1210 x = 20 1211 # This isn't an assignment expression, it's 'x', with a format 1212 # spec of '=10'. See test_walrus: you need to use parens. 1213 self.assertEqual(f'{x:=10}', ' 20') 1214 1215 # Test named function parameters, to make sure '=' parsing works 1216 # there. 1217 def f(a): 1218 nonlocal x 1219 oldx = x 1220 x = a 1221 return oldx 1222 x = 0 1223 self.assertEqual(f'{f(a="3=")}', '0') 1224 self.assertEqual(x, '3=') 1225 self.assertEqual(f'{f(a=4)}', '3=') 1226 self.assertEqual(x, 4) 1227 1228 # Make sure __format__ is being called. 1229 class C: 1230 def __format__(self, s): 1231 return f'FORMAT-{s}' 1232 def __repr__(self): 1233 return 'REPR' 1234 1235 self.assertEqual(f'{C()=}', 'C()=REPR') 1236 self.assertEqual(f'{C()=!r}', 'C()=REPR') 1237 self.assertEqual(f'{C()=:}', 'C()=FORMAT-') 1238 self.assertEqual(f'{C()=: }', 'C()=FORMAT- ') 1239 self.assertEqual(f'{C()=:x}', 'C()=FORMAT-x') 1240 self.assertEqual(f'{C()=!r:*^20}', 'C()=********REPR********') 1241 1242 self.assertRaises(SyntaxError, eval, "f'{C=]'") 1243 1244 # Make sure leading and following text works. 1245 x = 'foo' 1246 self.assertEqual(f'X{x=}Y', 'Xx='+repr(x)+'Y') 1247 1248 # Make sure whitespace around the = works. 1249 self.assertEqual(f'X{x =}Y', 'Xx ='+repr(x)+'Y') 1250 self.assertEqual(f'X{x= }Y', 'Xx= '+repr(x)+'Y') 1251 self.assertEqual(f'X{x = }Y', 'Xx = '+repr(x)+'Y') 1252 1253 # These next lines contains tabs. Backslash escapes don't 1254 # work in f-strings. 1255 # patchcheck doesn't like these tabs. So the only way to test 1256 # this will be to dynamically created and exec the f-strings. But 1257 # that's such a hassle I'll save it for another day. For now, convert 1258 # the tabs to spaces just to shut up patchcheck. 1259 #self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y') 1260 #self.assertEqual(f'X{x = }Y', 'Xx\t=\t'+repr(x)+'Y') 1261 1262 def test_walrus(self): 1263 x = 20 1264 # This isn't an assignment expression, it's 'x', with a format 1265 # spec of '=10'. 1266 self.assertEqual(f'{x:=10}', ' 20') 1267 1268 # This is an assignment expression, which requires parens. 1269 self.assertEqual(f'{(x:=10)}', '10') 1270 self.assertEqual(x, 10) 1271 1272 def test_invalid_syntax_error_message(self): 1273 with self.assertRaisesRegex(SyntaxError, "f-string: invalid syntax"): 1274 compile("f'{a $ b}'", "?", "exec") 1275 1276 def test_with_two_commas_in_format_specifier(self): 1277 error_msg = re.escape("Cannot specify ',' with ','.") 1278 with self.assertRaisesRegex(ValueError, error_msg): 1279 f'{1:,,}' 1280 1281 def test_with_two_underscore_in_format_specifier(self): 1282 error_msg = re.escape("Cannot specify '_' with '_'.") 1283 with self.assertRaisesRegex(ValueError, error_msg): 1284 f'{1:__}' 1285 1286 def test_with_a_commas_and_an_underscore_in_format_specifier(self): 1287 error_msg = re.escape("Cannot specify both ',' and '_'.") 1288 with self.assertRaisesRegex(ValueError, error_msg): 1289 f'{1:,_}' 1290 1291 def test_with_an_underscore_and_a_comma_in_format_specifier(self): 1292 error_msg = re.escape("Cannot specify both ',' and '_'.") 1293 with self.assertRaisesRegex(ValueError, error_msg): 1294 f'{1:_,}' 1295 1296 def test_syntax_error_for_starred_expressions(self): 1297 error_msg = re.escape("cannot use starred expression here") 1298 with self.assertRaisesRegex(SyntaxError, error_msg): 1299 compile("f'{*a}'", "?", "exec") 1300 1301 error_msg = re.escape("cannot use double starred expression here") 1302 with self.assertRaisesRegex(SyntaxError, error_msg): 1303 compile("f'{**a}'", "?", "exec") 1304 1305if __name__ == '__main__': 1306 unittest.main() 1307