@@ -329,13 +329,13 @@ def test_ast_line_numbers_multiline_fstring(self):
329
329
self .assertEqual (t .body [1 ].lineno , 3 )
330
330
self .assertEqual (t .body [1 ].value .lineno , 3 )
331
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 )
332
+ self .assertEqual (t .body [1 ].value .values [1 ].lineno , 4 )
333
+ self .assertEqual (t .body [1 ].value .values [2 ].lineno , 6 )
334
334
self .assertEqual (t .body [1 ].col_offset , 0 )
335
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 )
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 )
339
339
# NOTE: the following lineno information and col_offset is correct for
340
340
# expressions within FormattedValues.
341
341
binop = t .body [1 ].value .values [1 ].value
@@ -366,13 +366,13 @@ def test_ast_line_numbers_multiline_fstring(self):
366
366
self .assertEqual (t .body [0 ].lineno , 2 )
367
367
self .assertEqual (t .body [0 ].value .lineno , 2 )
368
368
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 )
371
371
self .assertEqual (t .body [0 ].col_offset , 0 )
372
372
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 )
376
376
# Check {blech}
377
377
self .assertEqual (t .body [0 ].value .values [1 ].value .lineno , 3 )
378
378
self .assertEqual (t .body [0 ].value .values [1 ].value .end_lineno , 3 )
@@ -387,6 +387,20 @@ def test_ast_line_numbers_with_parentheses(self):
387
387
t = ast .parse (expr )
388
388
self .assertEqual (type (t ), ast .Module )
389
389
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 )
390
404
# check the test(t) location
391
405
call = t .body [0 ].value .values [1 ].value
392
406
self .assertEqual (type (call ), ast .Call )
@@ -415,9 +429,9 @@ def test_ast_line_numbers_with_parentheses(self):
415
429
# check the first wat
416
430
self .assertEqual (type (wat1 ), ast .Constant )
417
431
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 )
421
435
# check the call
422
436
call = middle .value
423
437
self .assertEqual (type (call ), ast .Call )
@@ -427,9 +441,9 @@ def test_ast_line_numbers_with_parentheses(self):
427
441
self .assertEqual (call .end_col_offset , 31 )
428
442
# check the second wat
429
443
self .assertEqual (type (wat2 ), ast .Constant )
430
- self .assertEqual (wat2 .lineno , 4 )
444
+ self .assertEqual (wat2 .lineno , 5 )
431
445
self .assertEqual (wat2 .end_lineno , 6 )
432
- self .assertEqual (wat2 .col_offset , 12 )
446
+ self .assertEqual (wat2 .col_offset , 32 )
433
447
self .assertEqual (wat2 .end_col_offset , 18 )
434
448
435
449
def test_docstring (self ):
@@ -618,6 +632,7 @@ def test_format_specifier_expressions(self):
618
632
self .assertEqual (f'{ - 10 :-{"#" }1{0 }x} ' , ' -0xa' )
619
633
self .assertEqual (f'{ - 10 :{"-" }#{1 }0{"x" }} ' , ' -0xa' )
620
634
self .assertEqual (f'{ 10 :#{3 != {4 :5 } and width }x} ' , ' 0xa' )
635
+ self .assertEqual (f'result: { value :{width :{0 }}.{precision :1}} ' , 'result: 12.35' )
621
636
622
637
self .assertAllRaise (SyntaxError ,
623
638
"""f-string: invalid conversion character 'r{"': """
@@ -632,11 +647,6 @@ def test_format_specifier_expressions(self):
632
647
"f'{4:{/5}}'" ,
633
648
])
634
649
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
-
640
650
self .assertAllRaise (SyntaxError , 'f-string: invalid conversion character' ,
641
651
[# No expansion inside conversion or for
642
652
# the : or ! itself.
@@ -848,6 +858,50 @@ def test_lambda(self):
848
858
["f'{lambda x:x}'" ,
849
859
])
850
860
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
+
851
905
def test_yield (self ):
852
906
# Not terribly useful, but make sure the yield turns
853
907
# a function into a generator
@@ -1314,6 +1368,7 @@ def __repr__(self):
1314
1368
self .assertEqual (f'X{ x = } Y' , 'Xx =' + repr (x )+ 'Y' )
1315
1369
self .assertEqual (f'X{ x = } Y' , 'Xx= ' + repr (x )+ 'Y' )
1316
1370
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" )
1317
1372
1318
1373
# These next lines contains tabs. Backslash escapes don't
1319
1374
# work in f-strings.
@@ -1324,6 +1379,7 @@ def __repr__(self):
1324
1379
#self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y')
1325
1380
#self.assertEqual(f'X{x = }Y', 'Xx\t=\t'+repr(x)+'Y')
1326
1381
1382
+
1327
1383
def test_walrus (self ):
1328
1384
x = 20
1329
1385
# This isn't an assignment expression, it's 'x', with a format
0 commit comments