Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Lib/test/test_fstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,11 @@ def __repr__(self):
self.assertEqual(f'{" # nooo "=}', '" # nooo "=\' # nooo \'')
self.assertEqual(f'{" \" # nooo \" "=}', '" \\" # nooo \\" "=\' " # nooo " \'')

# A real comment after a string that ends with an escaped quote must
# still be stripped (gh-154711).
self.assertEqual(f"{'\'' = # comment
}", "'\\'' = \n" + repr("'"))

self.assertEqual(f'{ # some comment goes here
"""hello"""=}', ' \n """hello"""=\'hello\'')
self.assertEqual(f'{"""# this is not a comment
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix a bug where a comment placed after a string that ends with an escaped

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This goes back to 3.12 (gh-112243) and the same code is still in 3.13 and 3.14, so we want the backport labels here, no?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed, the same escape-skip bug is present in 3.12 (tokenizer.c) and 3.13 (lexer.c) as well. Happy to have backport labels added.

quote could leak into the output of a debug f-string. Now the comment is
stripped as expected.
13 changes: 13 additions & 0 deletions Parser/lexer/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ set_fstring_expr(struct tok_state* tok, struct token *token, char c) {
while (i < expression_size) {
char ch = expression[i];

// Copy escaped characters as-is. This keeps an escaped quote from
// flipping the in_string state, which would otherwise stop a real
// comment from being detected (see the detection loop above).
if (ch == '\\') {
result[j++] = ch;
i++;
if (i < expression_size) {
result[j++] = expression[i];
i++;
}
continue;
}

// Handle string quotes
if (ch == '"' || ch == '\'') {
// See comment above to understand this part
Expand Down