Skip to content

Commit d59feb5

Browse files
authored
gh-112243: Don't include comments in f-string debug expressions (#112284)
1 parent 3b3ec0d commit d59feb5

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

Lib/test/test_fstring.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,9 @@ def __repr__(self):
16271627
self.assertEqual(f'X{x = }Y', 'Xx = '+repr(x)+'Y')
16281628
self.assertEqual(f"sadsd {1 + 1 = :{1 + 1:1d}f}", "sadsd 1 + 1 = 2.000000")
16291629

1630+
self.assertEqual(f"{1+2 = # my comment
1631+
}", '1+2 = \n 3')
1632+
16301633
# These next lines contains tabs. Backslash escapes don't
16311634
# work in f-strings.
16321635
# patchcheck doesn't like these tabs. So the only way to test
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Don't include comments in f-string debug expressions. Patch by Pablo Galindo

Parser/lexer/lexer.c

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,56 @@ set_fstring_expr(struct tok_state* tok, struct token *token, char c) {
116116
if (!tok_mode->f_string_debug || token->metadata) {
117117
return 0;
118118
}
119+
PyObject *res = NULL;
119120

120-
PyObject *res = PyUnicode_DecodeUTF8(
121-
tok_mode->last_expr_buffer,
122-
tok_mode->last_expr_size - tok_mode->last_expr_end,
123-
NULL
124-
);
125-
if (!res) {
121+
// Check if there is a # character in the expression
122+
int hash_detected = 0;
123+
for (Py_ssize_t i = 0; i < tok_mode->last_expr_size - tok_mode->last_expr_end; i++) {
124+
if (tok_mode->last_expr_buffer[i] == '#') {
125+
hash_detected = 1;
126+
break;
127+
}
128+
}
129+
130+
if (hash_detected) {
131+
Py_ssize_t input_length = tok_mode->last_expr_size - tok_mode->last_expr_end;
132+
char *result = (char *)PyObject_Malloc((input_length + 1) * sizeof(char));
133+
if (!result) {
134+
return -1;
135+
}
136+
137+
Py_ssize_t i = 0;
138+
Py_ssize_t j = 0;
139+
140+
for (i = 0, j = 0; i < input_length; i++) {
141+
if (tok_mode->last_expr_buffer[i] == '#') {
142+
// Skip characters until newline or end of string
143+
while (tok_mode->last_expr_buffer[i] != '\0' && i < input_length) {
144+
if (tok_mode->last_expr_buffer[i] == '\n') {
145+
result[j++] = tok_mode->last_expr_buffer[i];
146+
break;
147+
}
148+
i++;
149+
}
150+
} else {
151+
result[j++] = tok_mode->last_expr_buffer[i];
152+
}
153+
}
154+
155+
result[j] = '\0'; // Null-terminate the result string
156+
res = PyUnicode_DecodeUTF8(result, j, NULL);
157+
PyObject_Free(result);
158+
} else {
159+
res = PyUnicode_DecodeUTF8(
160+
tok_mode->last_expr_buffer,
161+
tok_mode->last_expr_size - tok_mode->last_expr_end,
162+
NULL
163+
);
164+
165+
}
166+
167+
168+
if (!res) {
126169
return -1;
127170
}
128171
token->metadata = res;

0 commit comments

Comments
 (0)