@@ -2754,6 +2754,67 @@ def test_tolerant_fstring_mismatch_keeps_delimiter_state(self):
27542754 ("f-string: unmatched ']'" , tolerant_position ),
27552755 )
27562756
2757+ def test_nested_fstring_preserves_delimiter_errors (self ):
2758+ cases = [
2759+ (
2760+ 'f\' {f"{:"])' ,
2761+ ("f-string: unmatched ']'" , (1 , 9 )),
2762+ ("f-string: unmatched ')'" , (1 , 10 )),
2763+ ),
2764+ (
2765+ 'f\' {f"{:"0a})0=' ,
2766+ ("invalid decimal literal" , (1 , 9 )),
2767+ (
2768+ "unterminated f-string literal (detected at line 1)" ,
2769+ (1 , 1 ),
2770+ ),
2771+ ),
2772+ (
2773+ 'f\' {f"{:"=\n )):' ,
2774+ ("f-string: unmatched ')'" , (2 , 1 )),
2775+ ("f-string: unmatched ')'" , (2 , 2 )),
2776+ ),
2777+ (
2778+ 'f\' {f"{x:[")=00\n !' ,
2779+ ("f-string: unmatched ')'" , (1 , 11 )),
2780+ ("unexpected EOF in multi-line statement" , (2 , 17 )),
2781+ ),
2782+ ]
2783+ for source , parser_error , tolerant_error in cases :
2784+ for extra_tokens , expected in [
2785+ (False , parser_error ),
2786+ (True , tolerant_error ),
2787+ ]:
2788+ with self .subTest (
2789+ source = source , extra_tokens = extra_tokens
2790+ ):
2791+ with self .assertRaises (tokenize .TokenError ) as caught :
2792+ self ._get_tokens (source , extra_tokens = extra_tokens )
2793+ self .assertEqual (caught .exception .args , expected )
2794+
2795+ with self .subTest (source = source , public = True ):
2796+ with self .assertRaises (tokenize .TokenError ) as caught :
2797+ list (tokenize .tokenize (
2798+ BytesIO (source .encode ()).readline
2799+ ))
2800+ self .assertEqual (caught .exception .args , tolerant_error )
2801+
2802+ def test_fstring_expression_depth_error_location (self ):
2803+ source = "f'{x:{:{:!{{:}{:"
2804+ expected = (
2805+ "f-string: expressions nested too deeply" ,
2806+ (1 , 10 ),
2807+ )
2808+ for extra_tokens in (False , True ):
2809+ with self .subTest (extra_tokens = extra_tokens ):
2810+ with self .assertRaises (tokenize .TokenError ) as caught :
2811+ self ._get_tokens (source , extra_tokens = extra_tokens )
2812+ self .assertEqual (caught .exception .args , expected )
2813+
2814+ with self .assertRaises (tokenize .TokenError ) as caught :
2815+ list (tokenize .tokenize (BytesIO (source .encode ()).readline ))
2816+ self .assertEqual (caught .exception .args , expected )
2817+
27572818 def test_int (self ):
27582819
27592820 self .check_tokenize ('0xff <= 255' , """\
0 commit comments