@@ -329,13 +329,13 @@ def test_ast_line_numbers_multiline_fstring(self):
329329 self .assertEqual (t .body [1 ].lineno , 3 )
330330 self .assertEqual (t .body [1 ].value .lineno , 3 )
331331 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 )
332+ self .assertEqual (t .body [1 ].value .values [1 ].lineno , 4 )
333+ self .assertEqual (t .body [1 ].value .values [2 ].lineno , 6 )
334334 self .assertEqual (t .body [1 ].col_offset , 0 )
335335 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 )
336+ self .assertEqual (t .body [1 ].value .values [0 ].col_offset , 4 )
337+ self .assertEqual (t .body [1 ].value .values [1 ].col_offset , 2 )
338+ self .assertEqual (t .body [1 ].value .values [2 ].col_offset , 11 )
339339 # NOTE: the following lineno information and col_offset is correct for
340340 # expressions within FormattedValues.
341341 binop = t .body [1 ].value .values [1 ].value
@@ -366,13 +366,13 @@ def test_ast_line_numbers_multiline_fstring(self):
366366 self .assertEqual (t .body [0 ].lineno , 2 )
367367 self .assertEqual (t .body [0 ].value .lineno , 2 )
368368 self .assertEqual (t .body [0 ].value .values [0 ].lineno , 2 )
369- self .assertEqual (t .body [0 ].value .values [1 ].lineno , 2 )
370- self .assertEqual (t .body [0 ].value .values [2 ].lineno , 2 )
369+ self .assertEqual (t .body [0 ].value .values [1 ].lineno , 3 )
370+ self .assertEqual (t .body [0 ].value .values [2 ].lineno , 3 )
371371 self .assertEqual (t .body [0 ].col_offset , 0 )
372372 self .assertEqual (t .body [0 ].value .col_offset , 4 )
373- self .assertEqual (t .body [0 ].value .values [0 ].col_offset , 4 )
374- self .assertEqual (t .body [0 ].value .values [1 ].col_offset , 4 )
375- self .assertEqual (t .body [0 ].value .values [2 ].col_offset , 4 )
373+ self .assertEqual (t .body [0 ].value .values [0 ].col_offset , 8 )
374+ self .assertEqual (t .body [0 ].value .values [1 ].col_offset , 10 )
375+ self .assertEqual (t .body [0 ].value .values [2 ].col_offset , 17 )
376376 # Check {blech}
377377 self .assertEqual (t .body [0 ].value .values [1 ].value .lineno , 3 )
378378 self .assertEqual (t .body [0 ].value .values [1 ].value .end_lineno , 3 )
@@ -387,6 +387,20 @@ def test_ast_line_numbers_with_parentheses(self):
387387 t = ast .parse (expr )
388388 self .assertEqual (type (t ), ast .Module )
389389 self .assertEqual (len (t .body ), 1 )
390+ # check the joinedstr location
391+ joinedstr = t .body [0 ].value
392+ self .assertEqual (type (joinedstr ), ast .JoinedStr )
393+ self .assertEqual (joinedstr .lineno , 3 )
394+ self .assertEqual (joinedstr .end_lineno , 3 )
395+ self .assertEqual (joinedstr .col_offset , 4 )
396+ self .assertEqual (joinedstr .end_col_offset , 17 )
397+ # check the formatted value location
398+ fv = t .body [0 ].value .values [1 ]
399+ self .assertEqual (type (fv ), ast .FormattedValue )
400+ self .assertEqual (fv .lineno , 3 )
401+ self .assertEqual (fv .end_lineno , 3 )
402+ self .assertEqual (fv .col_offset , 7 )
403+ self .assertEqual (fv .end_col_offset , 16 )
390404 # check the test(t) location
391405 call = t .body [0 ].value .values [1 ].value
392406 self .assertEqual (type (call ), ast .Call )
@@ -415,9 +429,9 @@ def test_ast_line_numbers_with_parentheses(self):
415429 # check the first wat
416430 self .assertEqual (type (wat1 ), ast .Constant )
417431 self .assertEqual (wat1 .lineno , 4 )
418- self .assertEqual (wat1 .end_lineno , 6 )
419- self .assertEqual (wat1 .col_offset , 12 )
420- self .assertEqual (wat1 .end_col_offset , 18 )
432+ self .assertEqual (wat1 .end_lineno , 5 )
433+ self .assertEqual (wat1 .col_offset , 14 )
434+ self .assertEqual (wat1 .end_col_offset , 26 )
421435 # check the call
422436 call = middle .value
423437 self .assertEqual (type (call ), ast .Call )
@@ -427,9 +441,9 @@ def test_ast_line_numbers_with_parentheses(self):
427441 self .assertEqual (call .end_col_offset , 31 )
428442 # check the second wat
429443 self .assertEqual (type (wat2 ), ast .Constant )
430- self .assertEqual (wat2 .lineno , 4 )
444+ self .assertEqual (wat2 .lineno , 5 )
431445 self .assertEqual (wat2 .end_lineno , 6 )
432- self .assertEqual (wat2 .col_offset , 12 )
446+ self .assertEqual (wat2 .col_offset , 32 )
433447 self .assertEqual (wat2 .end_col_offset , 18 )
434448
435449 def test_docstring (self ):
@@ -618,6 +632,7 @@ def test_format_specifier_expressions(self):
618632 self .assertEqual (f'{ - 10 :-{"#" }1{0 }x} ' , ' -0xa' )
619633 self .assertEqual (f'{ - 10 :{"-" }#{1 }0{"x" }} ' , ' -0xa' )
620634 self .assertEqual (f'{ 10 :#{3 != {4 :5 } and width }x} ' , ' 0xa' )
635+ self .assertEqual (f'result: { value :{width :{0 }}.{precision :1}} ' , 'result: 12.35' )
621636
622637 self .assertAllRaise (SyntaxError ,
623638 """f-string: invalid conversion character 'r{"': """
@@ -632,11 +647,6 @@ def test_format_specifier_expressions(self):
632647 "f'{4:{/5}}'" ,
633648 ])
634649
635- self .assertAllRaise (SyntaxError , "f-string: expressions nested too deeply" ,
636- [# Can't nest format specifiers.
637- "f'result: {value:{width:{0}}.{precision:1}}'" ,
638- ])
639-
640650 self .assertAllRaise (SyntaxError , 'f-string: invalid conversion character' ,
641651 [# No expansion inside conversion or for
642652 # the : or ! itself.
@@ -848,6 +858,50 @@ def test_lambda(self):
848858 ["f'{lambda x:x}'" ,
849859 ])
850860
861+ def test_valid_prefixes (self ):
862+ self .assertEqual (F'{ 1 } ' , "1" )
863+ self .assertEqual (FR'{ 2 } ' , "2" )
864+ self .assertEqual (fR'{ 3 } ' , "3" )
865+
866+ def test_roundtrip_raw_quotes (self ):
867+ self .assertEqual (fr"\'" , "\\ '" )
868+ self .assertEqual (fr'\"' , '\\ "' )
869+ self .assertEqual (fr'\"\'' , '\\ "\\ \' ' )
870+ self .assertEqual (fr'\'\"' , '\\ \' \\ "' )
871+ self .assertEqual (fr'\"\'\"' , '\\ "\\ \' \\ "' )
872+ self .assertEqual (fr'\'\"\'' , '\\ \' \\ "\\ \' ' )
873+ self .assertEqual (fr'\"\'\"\'' , '\\ "\\ \' \\ "\\ \' ' )
874+
875+ def test_fstring_backslash_before_double_bracket (self ):
876+ self .assertEqual (f'\{{\}}' , '\\ {\\ }' )
877+ self .assertEqual (f'\{{' , '\\ {' )
878+ self .assertEqual (f'\{{{ 1 + 1 } ' , '\\ {2' )
879+ self .assertEqual (f'\}}{ 1 + 1 } ' , '\\ }2' )
880+ self .assertEqual (f'{ 1 + 1 } \}}' , '2\\ }' )
881+ self .assertEqual (fr'\{{\}}' , '\\ {\\ }' )
882+ self .assertEqual (fr'\{{' , '\\ {' )
883+ self .assertEqual (fr'\{{{ 1 + 1 } ' , '\\ {2' )
884+ self .assertEqual (fr'\}}{ 1 + 1 } ' , '\\ }2' )
885+ self .assertEqual (fr'{ 1 + 1 } \}}' , '2\\ }' )
886+
887+ def test_fstring_backslash_prefix_raw (self ):
888+ self .assertEqual (f'\\ ' , '\\ ' )
889+ self .assertEqual (f'\\ \\ ' , '\\ \\ ' )
890+ self .assertEqual (fr'\\' , r'\\' )
891+ self .assertEqual (fr'\\\\' , r'\\\\' )
892+ self .assertEqual (rf'\\' , r'\\' )
893+ self .assertEqual (rf'\\\\' , r'\\\\' )
894+ self .assertEqual (Rf'\\' , R'\\' )
895+ self .assertEqual (Rf'\\\\' , R'\\\\' )
896+ self .assertEqual (fR'\\' , R'\\' )
897+ self .assertEqual (fR'\\\\' , R'\\\\' )
898+ self .assertEqual (FR'\\' , R'\\' )
899+ self .assertEqual (FR'\\\\' , R'\\\\' )
900+
901+ def test_fstring_format_spec_greedy_matching (self ):
902+ self .assertEqual (f"{ 1 :} }}" , "1}" )
903+ self .assertEqual (f"{ 1 :>3{5 }} }}" , " 1}" )
904+
851905 def test_yield (self ):
852906 # Not terribly useful, but make sure the yield turns
853907 # a function into a generator
@@ -1314,6 +1368,7 @@ def __repr__(self):
13141368 self .assertEqual (f'X{ x = } Y' , 'Xx =' + repr (x )+ 'Y' )
13151369 self .assertEqual (f'X{ x = } Y' , 'Xx= ' + repr (x )+ 'Y' )
13161370 self .assertEqual (f'X{ x = } Y' , 'Xx = ' + repr (x )+ 'Y' )
1371+ self .assertEqual (f"sadsd { 1 + 1 = :{1 + 1 :1d}f} " , "sadsd 1 + 1 = 2.000000" )
13171372
13181373 # These next lines contains tabs. Backslash escapes don't
13191374 # work in f-strings.
@@ -1324,6 +1379,7 @@ def __repr__(self):
13241379 #self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y')
13251380 #self.assertEqual(f'X{x = }Y', 'Xx\t=\t'+repr(x)+'Y')
13261381
1382+
13271383 def test_walrus (self ):
13281384 x = 20
13291385 # This isn't an assignment expression, it's 'x', with a format
0 commit comments