mirror of
https://github.com/python/cpython.git
synced 2025-07-08 03:45:36 +00:00
bpo-40612: Fix SyntaxError edge cases in traceback formatting (GH-20072)
This fixes both the traceback.py module and the C code for formatting syntax errors (in Python/pythonrun.c). They now both consistently do the following: - Suppress caret if it points left of text - Allow caret pointing just past end of line - If caret points past end of line, clip to *just* past end of line The syntax error formatting code in traceback.py was mostly rewritten; small, subtle changes were applied to the C code in pythonrun.c. There's still a difference when the text contains embedded newlines. Neither handles these very well, and I don't think the case occurs in practice. Automerge-Triggered-By: @gvanrossum
This commit is contained in:
parent
1aa8767baf
commit
15bc9ab301
5 changed files with 96 additions and 41 deletions
|
@ -554,37 +554,65 @@ finally:
|
|||
static void
|
||||
print_error_text(PyObject *f, int offset, PyObject *text_obj)
|
||||
{
|
||||
const char *text;
|
||||
const char *nl;
|
||||
|
||||
text = PyUnicode_AsUTF8(text_obj);
|
||||
/* Convert text to a char pointer; return if error */
|
||||
const char *text = PyUnicode_AsUTF8(text_obj);
|
||||
if (text == NULL)
|
||||
return;
|
||||
|
||||
if (offset >= 0) {
|
||||
if (offset > 0 && (size_t)offset == strlen(text) && text[offset - 1] == '\n')
|
||||
offset--;
|
||||
for (;;) {
|
||||
nl = strchr(text, '\n');
|
||||
if (nl == NULL || nl-text >= offset)
|
||||
break;
|
||||
offset -= (int)(nl+1-text);
|
||||
text = nl+1;
|
||||
}
|
||||
while (*text == ' ' || *text == '\t' || *text == '\f') {
|
||||
text++;
|
||||
offset--;
|
||||
}
|
||||
/* Convert offset from 1-based to 0-based */
|
||||
offset--;
|
||||
|
||||
/* Strip leading whitespace from text, adjusting offset as we go */
|
||||
while (*text == ' ' || *text == '\t' || *text == '\f') {
|
||||
text++;
|
||||
offset--;
|
||||
}
|
||||
|
||||
/* Calculate text length excluding trailing newline */
|
||||
Py_ssize_t len = strlen(text);
|
||||
if (len > 0 && text[len-1] == '\n') {
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Clip offset to at most len */
|
||||
if (offset > len) {
|
||||
offset = len;
|
||||
}
|
||||
|
||||
/* Skip past newlines embedded in text */
|
||||
for (;;) {
|
||||
const char *nl = strchr(text, '\n');
|
||||
if (nl == NULL) {
|
||||
break;
|
||||
}
|
||||
Py_ssize_t inl = nl - text;
|
||||
if (inl >= (Py_ssize_t)offset) {
|
||||
break;
|
||||
}
|
||||
inl += 1;
|
||||
text += inl;
|
||||
len -= inl;
|
||||
offset -= (int)inl;
|
||||
}
|
||||
|
||||
/* Print text */
|
||||
PyFile_WriteString(" ", f);
|
||||
PyFile_WriteString(text, f);
|
||||
if (*text == '\0' || text[strlen(text)-1] != '\n')
|
||||
|
||||
/* Make sure there's a newline at the end */
|
||||
if (text[len] != '\n') {
|
||||
PyFile_WriteString("\n", f);
|
||||
if (offset == -1)
|
||||
}
|
||||
|
||||
/* Don't print caret if it points to the left of the text */
|
||||
if (offset < 0)
|
||||
return;
|
||||
|
||||
/* Write caret line */
|
||||
PyFile_WriteString(" ", f);
|
||||
while (--offset > 0)
|
||||
while (--offset >= 0) {
|
||||
PyFile_WriteString(" ", f);
|
||||
}
|
||||
PyFile_WriteString("^\n", f);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue