@@ -383,7 +383,7 @@ def test_ast_line_numbers_multiline_fstring(self):
383383 self .assertEqual (t .body [0 ].value .values [1 ].value .col_offset , 11 )
384384 self .assertEqual (t .body [0 ].value .values [1 ].value .end_col_offset , 16 )
385385
386- @unittest .expectedFailure # TODO: RUSTPYTHON
386+ @unittest .expectedFailure # TODO: RUSTPYTHON; AssertionError: 4 != 5
387387 def test_ast_line_numbers_with_parentheses (self ):
388388 expr = """
389389x = (
@@ -587,7 +587,6 @@ def test_ast_compile_time_concat(self):
587587 exec (c )
588588 self .assertEqual (x [0 ], 'foo3' )
589589
590- @unittest .expectedFailure # TODO: RUSTPYTHON
591590 def test_compile_time_concat_errors (self ):
592591 self .assertAllRaise (SyntaxError ,
593592 'cannot mix bytes and nonbytes literals' ,
@@ -600,7 +599,6 @@ def test_literal(self):
600599 self .assertEqual (f'a' , 'a' )
601600 self .assertEqual (f' ' , ' ' )
602601
603- @unittest .expectedFailure # TODO: RUSTPYTHON
604602 def test_unterminated_string (self ):
605603 self .assertAllRaise (SyntaxError , 'unterminated string' ,
606604 [r"""f'{"x'""" ,
@@ -609,7 +607,7 @@ def test_unterminated_string(self):
609607 r"""f'{("x}'""" ,
610608 ])
611609
612- @unittest .expectedFailure # TODO: RUSTPYTHON
610+ @unittest .expectedFailure # TODO: RUSTPYTHON
613611 @unittest .skipIf (support .is_wasi , "exhausts limited stack on WASI" )
614612 def test_mismatched_parens (self ):
615613 self .assertAllRaise (SyntaxError , r"closing parenthesis '\}' "
@@ -632,24 +630,35 @@ def test_mismatched_parens(self):
632630 r"does not match opening parenthesis '\('" ,
633631 ["f'{a(4}'" ,
634632 ])
635- self .assertRaises (SyntaxError , eval , "f'{" + "(" * 500 + "}'" )
633+ self .assertRaises (SyntaxError , eval , "f'{" + "(" * 20 + "}'" )
636634
637- @unittest .expectedFailure # TODO: RUSTPYTHON
635+ @unittest .expectedFailure # TODO: RUSTPYTHON; AssertionError: No exception raised
638636 @unittest .skipIf (support .is_wasi , "exhausts limited stack on WASI" )
639637 def test_fstring_nested_too_deeply (self ):
640- self .assertAllRaise (SyntaxError ,
641- "f-string: expressions nested too deeply" ,
642- ['f"{1+2:{1+2:{1+1:{1}}}}"' ])
638+ def raises_syntax_or_memory_error (txt ):
639+ try :
640+ eval (txt )
641+ except SyntaxError :
642+ pass
643+ except MemoryError :
644+ pass
645+ except Exception as ex :
646+ self .fail (f"Should raise SyntaxError or MemoryError, not { type (ex )} " )
647+ else :
648+ self .fail ("No exception raised" )
649+
650+ raises_syntax_or_memory_error ('f"{1+2:{1+2:{1+1:{1}}}}"' )
643651
644652 def create_nested_fstring (n ):
645653 if n == 0 :
646654 return "1+1"
647655 prev = create_nested_fstring (n - 1 )
648656 return f'f"{{{ prev } }}"'
649657
650- self .assertAllRaise (SyntaxError ,
651- "too many nested f-strings" ,
652- [create_nested_fstring (160 )])
658+ raises_syntax_or_memory_error (create_nested_fstring (160 ))
659+ raises_syntax_or_memory_error ("f'{" + "(" * 100 + "}'" )
660+ raises_syntax_or_memory_error ("f'{" + "(" * 1000 + "}'" )
661+ raises_syntax_or_memory_error ("f'{" + "(" * 10_000 + "}'" )
653662
654663 def test_syntax_error_in_nested_fstring (self ):
655664 # See gh-104016 for more information on this crash
@@ -692,7 +701,7 @@ def test_double_braces(self):
692701 ["f'{ {{}} }'" , # dict in a set
693702 ])
694703
695- @unittest .expectedFailure # TODO: RUSTPYTHON
704+ @unittest .expectedFailure # TODO: RUSTPYTHON
696705 def test_compile_time_concat (self ):
697706 x = 'def'
698707 self .assertEqual ('abc' f'## { x } ghi' , 'abc## defghi' )
@@ -730,7 +739,7 @@ def test_compile_time_concat(self):
730739 ['''f'{3' f"}"''' , # can't concat to get a valid f-string
731740 ])
732741
733- @unittest .expectedFailure # TODO: RUSTPYTHON
742+ @unittest .expectedFailure # TODO: RUSTPYTHON
734743 def test_comments (self ):
735744 # These aren't comments, since they're in strings.
736745 d = {'#' : 'hash' }
@@ -807,7 +816,7 @@ def build_fstr(n, extra=''):
807816 s = "f'{1}' 'x' 'y'" * 1024
808817 self .assertEqual (eval (s ), '1xy' * 1024 )
809818
810- @unittest .expectedFailure # TODO: RUSTPYTHON
819+ @unittest .expectedFailure # TODO: RUSTPYTHON
811820 def test_format_specifier_expressions (self ):
812821 width = 10
813822 precision = 4
@@ -841,7 +850,6 @@ def test_format_specifier_expressions(self):
841850 """f'{"s"!{"r"}}'""" ,
842851 ])
843852
844- @unittest .expectedFailure # TODO: RUSTPYTHON
845853 def test_custom_format_specifier (self ):
846854 class CustomFormat :
847855 def __format__ (self , format_spec ):
@@ -863,7 +871,7 @@ def __format__(self, spec):
863871 x = X ()
864872 self .assertEqual (f'{ x } { x } ' , '1 2' )
865873
866- @unittest .expectedFailure # TODO: RUSTPYTHON
874+ @unittest .expectedFailure # TODO: RUSTPYTHON
867875 def test_missing_expression (self ):
868876 self .assertAllRaise (SyntaxError ,
869877 "f-string: valid expression required before '}'" ,
@@ -926,7 +934,7 @@ def test_missing_expression(self):
926934 "\xa0 " ,
927935 ])
928936
929- @unittest .expectedFailure # TODO: RUSTPYTHON
937+ @unittest .expectedFailure # TODO: RUSTPYTHON
930938 def test_parens_in_expressions (self ):
931939 self .assertEqual (f'{ 3 ,} ' , '(3,)' )
932940
@@ -939,13 +947,12 @@ def test_parens_in_expressions(self):
939947 ["f'{3)+(4}'" ,
940948 ])
941949
942- @unittest .expectedFailure # TODO: RUSTPYTHON
950+ @unittest .expectedFailure # TODO: RUSTPYTHON
943951 def test_newlines_before_syntax_error (self ):
944952 self .assertAllRaise (SyntaxError ,
945953 "f-string: expecting a valid expression after '{'" ,
946954 ["f'{.}'" , "\n f'{.}'" , "\n \n f'{.}'" ])
947955
948- @unittest .expectedFailure # TODO: RUSTPYTHON
949956 def test_backslashes_in_string_part (self ):
950957 self .assertEqual (f'\t ' , '\t ' )
951958 self .assertEqual (r'\t' , '\\ t' )
@@ -1004,7 +1011,7 @@ def test_backslashes_in_string_part(self):
10041011 self .assertEqual (fr'\N{ AMPERSAND } ' , '\\ Nspam' )
10051012 self .assertEqual (f'\\ \N{AMPERSAND} ' , '\\ &' )
10061013
1007- @unittest .expectedFailure # TODO: RUSTPYTHON
1014+ @unittest .expectedFailure # TODO: RUSTPYTHON
10081015 def test_misformed_unicode_character_name (self ):
10091016 # These test are needed because unicode names are parsed
10101017 # differently inside f-strings.
@@ -1024,7 +1031,7 @@ def test_misformed_unicode_character_name(self):
10241031 r"'\N{GREEK CAPITAL LETTER DELTA'" ,
10251032 ])
10261033
1027- @unittest .expectedFailure # TODO: RUSTPYTHON
1034+ @unittest .expectedFailure # TODO: RUSTPYTHON
10281035 def test_backslashes_in_expression_part (self ):
10291036 self .assertEqual (f"{ (
10301037 1 +
@@ -1040,7 +1047,6 @@ def test_backslashes_in_expression_part(self):
10401047 ["f'{\n }'" ,
10411048 ])
10421049
1043- @unittest .expectedFailure # TODO: RUSTPYTHON
10441050 def test_invalid_backslashes_inside_fstring_context (self ):
10451051 # All of these variations are invalid python syntax,
10461052 # so they are also invalid in f-strings as well.
@@ -1075,7 +1081,7 @@ def test_newlines_in_expressions(self):
10751081 self .assertEqual (rf'''{ 3 +
107610824 } ''' , '7' )
10771083
1078- @unittest .expectedFailure # TODO: RUSTPYTHON
1084+ @unittest .expectedFailure # TODO: RUSTPYTHON; AssertionError: "f-string: expecting a valid expression after '{'" does not match "invalid syntax (<string>, line 1)"
10791085 def test_lambda (self ):
10801086 x = 5
10811087 self .assertEqual (f'{ (lambda y :x * y )("8" )!r} ' , "'88888'" )
@@ -1118,7 +1124,6 @@ def test_roundtrip_raw_quotes(self):
11181124 self .assertEqual (fr'\'\"\'' , '\\ \' \\ "\\ \' ' )
11191125 self .assertEqual (fr'\"\'\"\'' , '\\ "\\ \' \\ "\\ \' ' )
11201126
1121- @unittest .expectedFailure # TODO: RUSTPYTHON
11221127 def test_fstring_backslash_before_double_bracket (self ):
11231128 deprecated_cases = [
11241129 (r"f'\{{\}}'" , '\\ {\\ }' ),
@@ -1138,7 +1143,6 @@ def test_fstring_backslash_before_double_bracket(self):
11381143 self .assertEqual (fr'\}}{ 1 + 1 } ' , '\\ }2' )
11391144 self .assertEqual (fr'{ 1 + 1 } \}}' , '2\\ }' )
11401145
1141- @unittest .expectedFailure # TODO: RUSTPYTHON
11421146 def test_fstring_backslash_before_double_bracket_warns_once (self ):
11431147 with self .assertWarns (SyntaxWarning ) as w :
11441148 eval (r"f'\{{'" )
@@ -1288,6 +1292,7 @@ def test_nested_fstrings(self):
12881292 self .assertEqual (f'{ f"{ 0 } " * 3 } ' , '000' )
12891293 self .assertEqual (f'{ f"{ y } " * 3 } ' , '555' )
12901294
1295+ @unittest .expectedFailure # TODO: RUSTPYTHON
12911296 def test_invalid_string_prefixes (self ):
12921297 single_quote_cases = ["fu''" ,
12931298 "uf''" ,
@@ -1312,7 +1317,7 @@ def test_invalid_string_prefixes(self):
13121317 "Bf''" ,
13131318 "BF''" ,]
13141319 double_quote_cases = [case .replace ("'" , '"' ) for case in single_quote_cases ]
1315- self .assertAllRaise (SyntaxError , 'invalid syntax ' ,
1320+ self .assertAllRaise (SyntaxError , 'prefixes are incompatible ' ,
13161321 single_quote_cases + double_quote_cases )
13171322
13181323 def test_leading_trailing_spaces (self ):
@@ -1342,7 +1347,7 @@ def test_equal_equal(self):
13421347
13431348 self .assertEqual (f'{ 0 == 1 } ' , 'False' )
13441349
1345- @unittest .expectedFailure # TODO: RUSTPYTHON
1350+ @unittest .expectedFailure # TODO: RUSTPYTHON
13461351 def test_conversions (self ):
13471352 self .assertEqual (f'{ 3.14 :10.10} ' , ' 3.14' )
13481353 self .assertEqual (f'{ 1.25 !s:10.10} ' , '1.25 ' )
@@ -1367,7 +1372,6 @@ def test_conversions(self):
13671372 self .assertAllRaise (SyntaxError , "f-string: expecting '}'" ,
13681373 ["f'{3!'" ,
13691374 "f'{3!s'" ,
1370- "f'{3!g'" ,
13711375 ])
13721376
13731377 self .assertAllRaise (SyntaxError , 'f-string: missing conversion character' ,
@@ -1408,14 +1412,13 @@ def test_assignment(self):
14081412 "f'{x}' = x" ,
14091413 ])
14101414
1411- @unittest .expectedFailure # TODO: RUSTPYTHON
14121415 def test_del (self ):
14131416 self .assertAllRaise (SyntaxError , 'invalid syntax' ,
14141417 ["del f''" ,
14151418 "del '' f''" ,
14161419 ])
14171420
1418- @unittest .expectedFailure # TODO: RUSTPYTHON
1421+ @unittest .expectedFailure # TODO: RUSTPYTHON
14191422 def test_mismatched_braces (self ):
14201423 self .assertAllRaise (SyntaxError , "f-string: single '}' is not allowed" ,
14211424 ["f'{{}'" ,
@@ -1514,7 +1517,6 @@ def test_str_format_differences(self):
15141517 self .assertEqual ('{d[a]}' .format (d = d ), 'string' )
15151518 self .assertEqual ('{d[0]}' .format (d = d ), 'integer' )
15161519
1517- @unittest .expectedFailure # TODO: RUSTPYTHON
15181520 def test_errors (self ):
15191521 # see issue 26287
15201522 self .assertAllRaise (TypeError , 'unsupported' ,
@@ -1557,7 +1559,6 @@ def test_backslash_char(self):
15571559 self .assertEqual (eval ('f"\\ \n "' ), '' )
15581560 self .assertEqual (eval ('f"\\ \r "' ), '' )
15591561
1560- @unittest .expectedFailure # TODO: RUSTPYTHON; AssertionError: '1+2 = # my comment\n 3' != '1+2 = \n 3'
15611562 def test_debug_conversion (self ):
15621563 x = 'A string'
15631564 self .assertEqual (f'{ x = } ' , 'x=' + repr (x ))
@@ -1705,7 +1706,7 @@ def test_walrus(self):
17051706 self .assertEqual (f'{ (x := 10 )} ' , '10' )
17061707 self .assertEqual (x , 10 )
17071708
1708- @unittest .expectedFailure # TODO: RUSTPYTHON
1709+ @unittest .expectedFailure # TODO: RUSTPYTHON; AssertionError: "f-string: expecting '=', or '!', or ':', or '}'" does not match "invalid syntax (?, line 1)"
17091710 def test_invalid_syntax_error_message (self ):
17101711 with self .assertRaisesRegex (SyntaxError ,
17111712 "f-string: expecting '=', or '!', or ':', or '}'" ):
@@ -1731,7 +1732,7 @@ def test_with_an_underscore_and_a_comma_in_format_specifier(self):
17311732 with self .assertRaisesRegex (ValueError , error_msg ):
17321733 f'{ 1 :_,} '
17331734
1734- @unittest .expectedFailure # TODO: RUSTPYTHON
1735+ @unittest .expectedFailure # TODO: RUSTPYTHON; AssertionError: "f-string: expecting a valid expression after '{'" does not match "invalid syntax (?, line 1)"
17351736 def test_syntax_error_for_starred_expressions (self ):
17361737 with self .assertRaisesRegex (SyntaxError , "can't use starred expression here" ):
17371738 compile ("f'{*a}'" , "?" , "exec" )
@@ -1740,7 +1741,7 @@ def test_syntax_error_for_starred_expressions(self):
17401741 "f-string: expecting a valid expression after '{'" ):
17411742 compile ("f'{**a}'" , "?" , "exec" )
17421743
1743- @unittest .expectedFailure # TODO: RUSTPYTHON
1744+ @unittest .expectedFailure # TODO: RUSTPYTHON; -
17441745 def test_not_closing_quotes (self ):
17451746 self .assertAllRaise (SyntaxError , "unterminated f-string literal" , ['f"' , "f'" ])
17461747 self .assertAllRaise (SyntaxError , "unterminated triple-quoted f-string literal" ,
@@ -1760,7 +1761,7 @@ def test_not_closing_quotes(self):
17601761 except SyntaxError as e :
17611762 self .assertEqual (e .text , 'z = f"""' )
17621763 self .assertEqual (e .lineno , 3 )
1763- @unittest .expectedFailure # TODO: RUSTPYTHON
1764+ @unittest .expectedFailure # TODO: RUSTPYTHON
17641765 def test_syntax_error_after_debug (self ):
17651766 self .assertAllRaise (SyntaxError , "f-string: expecting a valid expression after '{'" ,
17661767 [
@@ -1788,7 +1789,6 @@ def test_debug_in_file(self):
17881789 self .assertEqual (stdout .decode ('utf-8' ).strip ().replace ('\r \n ' , '\n ' ).replace ('\r ' , '\n ' ),
17891790 "3\n =3" )
17901791
1791- @unittest .expectedFailure # TODO: RUSTPYTHON
17921792 def test_syntax_warning_infinite_recursion_in_file (self ):
17931793 with temp_cwd ():
17941794 script = 'script.py'
@@ -1878,6 +1878,13 @@ def __format__(self, format):
18781878 # Test multiple format specs in same raw f-string
18791879 self .assertEqual (rf"{ UnchangedFormat ():\xFF} { UnchangedFormat ():\n} " , '\\ xFF \\ n' )
18801880
1881+ def test_gh139516 (self ):
1882+ with temp_cwd ():
1883+ script = 'script.py'
1884+ with open (script , 'wb' ) as f :
1885+ f .write ('''def f(a): pass\n f"{f(a=lambda: 'à'\n )}"''' .encode ())
1886+ assert_python_ok (script )
1887+
18811888
18821889if __name__ == '__main__' :
18831890 unittest .main ()
0 commit comments