1+ """
2+ Test for raw f-string with backslash escape sequences.
3+
4+ This test covers the fix for issue where raw f-strings containing backslash
5+ escape sequences in format specs would fail with "Unable to create representation
6+ for f-string" error.
7+ """
8+
9+ import ast
10+ import sys
11+
12+ import pytest
13+
14+ from python_minifier import unparse
15+ from python_minifier .ast_compare import compare_ast
16+
17+
18+ def test_raw_fstring_backslash_format_spec ():
19+ """Test that raw f-strings with backslash escapes in format specs can be unparsed correctly."""
20+
21+ if sys .version_info < (3 , 6 ):
22+ pytest .skip ('F-strings not supported in Python < 3.6' )
23+
24+ # This is the minimal case that was failing before the fix
25+ source = 'rf"{x:\\ xFF}"'
26+
27+ # This should round-trip correctly without "Unable to create representation for f-string"
28+ expected_ast = ast .parse (source )
29+ actual_code = unparse (expected_ast )
30+ compare_ast (expected_ast , ast .parse (actual_code ))
31+
32+
33+ def test_raw_fstring_backslash_outer_str ():
34+ """Test that raw f-strings with backslashes in the outer string parts can be unparsed correctly."""
35+
36+ if sys .version_info < (3 , 6 ):
37+ pytest .skip ('F-strings not supported in Python < 3.6' )
38+
39+ # Test backslashes in the literal parts of raw f-strings
40+ source = r'rf"\\n{x}\\t"'
41+
42+ expected_ast = ast .parse (source )
43+ actual_code = unparse (expected_ast )
44+ compare_ast (expected_ast , ast .parse (actual_code ))
45+
46+
47+ def test_raw_fstring_mixed_backslashes ():
48+ """Test raw f-strings with backslashes in both literal parts and format specs."""
49+
50+ if sys .version_info < (3 , 6 ):
51+ pytest .skip ('F-strings not supported in Python < 3.6' )
52+
53+ # Test combination of backslashes in literal parts and format specs
54+ source = r'rf"\\n{x:\\xFF}\\t"'
55+
56+ expected_ast = ast .parse (source )
57+ actual_code = unparse (expected_ast )
58+ compare_ast (expected_ast , ast .parse (actual_code ))
59+
60+
61+ def test_nested_fstring_backslashes ():
62+ """Test nested f-strings with backslashes (Python 3.12+ only)."""
63+
64+ if sys .version_info < (3 , 12 ):
65+ pytest .skip ('Nested f-strings not supported in Python < 3.12' )
66+
67+ # Test nested f-strings with backslashes in inner string parts
68+ source = r'f"{f"\\n{x}\\t"}"'
69+
70+ expected_ast = ast .parse (source )
71+ actual_code = unparse (expected_ast )
72+ compare_ast (expected_ast , ast .parse (actual_code ))
73+
74+
75+ def test_nested_raw_fstring_backslashes ():
76+ """Test nested raw f-strings with backslashes (Python 3.12+ only)."""
77+
78+ if sys .version_info < (3 , 12 ):
79+ pytest .skip ('Nested f-strings not supported in Python < 3.12' )
80+
81+ # Test nested raw f-strings with backslashes
82+ source = r'f"{rf"\\xFF{y}\\n"}"'
83+
84+ expected_ast = ast .parse (source )
85+ actual_code = unparse (expected_ast )
86+ compare_ast (expected_ast , ast .parse (actual_code ))
87+
88+
89+ def test_nested_fstring_format_spec_backslashes ():
90+ """Test nested f-strings with backslashes in format specs (Python 3.12+ only)."""
91+
92+ if sys .version_info < (3 , 12 ):
93+ pytest .skip ('Nested f-strings not supported in Python < 3.12' )
94+
95+ # Test nested f-strings with backslashes in format specifications
96+ source = r'f"{f"{x:\\xFF}"}"'
97+
98+ expected_ast = ast .parse (source )
99+ actual_code = unparse (expected_ast )
100+ compare_ast (expected_ast , ast .parse (actual_code ))
101+
102+
103+ def test_raw_fstring_literal_single_backslash ():
104+ """Test raw f-string with single backslash in literal part only."""
105+
106+ if sys .version_info < (3 , 6 ):
107+ pytest .skip ('F-strings not supported in Python < 3.6' )
108+
109+ source = r'rf"\n"'
110+
111+ expected_ast = ast .parse (source )
112+ actual_code = unparse (expected_ast )
113+ compare_ast (expected_ast , ast .parse (actual_code ))
114+
115+
116+ def test_raw_fstring_literal_double_backslash ():
117+ """Test raw f-string with double backslash in literal part only."""
118+
119+ if sys .version_info < (3 , 6 ):
120+ pytest .skip ('F-strings not supported in Python < 3.6' )
121+
122+ source = r'rf"\\n"'
123+
124+ expected_ast = ast .parse (source )
125+ actual_code = unparse (expected_ast )
126+ compare_ast (expected_ast , ast .parse (actual_code ))
127+
128+
129+ def test_raw_fstring_formatspec_single_backslash ():
130+ """Test raw f-string with single backslash in format spec only."""
131+
132+ if sys .version_info < (3 , 6 ):
133+ pytest .skip ('F-strings not supported in Python < 3.6' )
134+
135+ source = r'rf"{x:\xFF}"'
136+
137+ expected_ast = ast .parse (source )
138+ actual_code = unparse (expected_ast )
139+ compare_ast (expected_ast , ast .parse (actual_code ))
140+
141+
142+ def test_raw_fstring_formatspec_double_backslash ():
143+ """Test raw f-string with double backslash in format spec only."""
144+
145+ if sys .version_info < (3 , 6 ):
146+ pytest .skip ('F-strings not supported in Python < 3.6' )
147+
148+ source = r'rf"{x:\\xFF}"'
149+
150+ expected_ast = ast .parse (source )
151+ actual_code = unparse (expected_ast )
152+ compare_ast (expected_ast , ast .parse (actual_code ))
153+
154+
155+ def test_raw_fstring_mixed_single_backslashes ():
156+ """Test raw f-string with single backslashes in both literal and format spec parts."""
157+
158+ if sys .version_info < (3 , 6 ):
159+ pytest .skip ('F-strings not supported in Python < 3.6' )
160+
161+ source = r'rf"\n{x:\xFF}\t"'
162+
163+ expected_ast = ast .parse (source )
164+ actual_code = unparse (expected_ast )
165+ compare_ast (expected_ast , ast .parse (actual_code ))
0 commit comments