Skip to main content

Python/traceback.c

Source:

cpython 3.14 @ ab2d84fe1023/Python/traceback.c

traceback.c formats and prints tracebacks to sys.stderr. It is called by sys.excepthook and by the REPL on unhandled exceptions.

Map

LinesSymbolRole
1-100PyTraceBack_HereCreate a new traceback entry from the current frame
101-300PyTraceBack_PrintPrint full traceback chain to a file
301-500tb_print_linePrint one frame's filename/lineno/code context
501-700tb_print_exceptionFormat ExceptionType: message line
701-900Exception groupsPrint ExceptionGroup trees (3.11+)
901-1000PyTraceBack_Limitsys.tracebacklimit enforcement

Reading

PyTraceBack_Here

// CPython: Python/traceback.c:55 PyTraceBack_Here
int
PyTraceBack_Here(PyFrameObject *frame)
{
PyObject *exc = tstate->exc_info->exc_value;
PyTracebackObject *newtb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
newtb->tb_next = (PyTracebackObject *)PyException_GetTraceback(exc);
newtb->tb_frame = (PyFrameObject *)Py_NewRef(frame);
newtb->tb_lasti = frame->f_lasti;
newtb->tb_lineno = PyFrame_GetLineNumber(frame);
PyException_SetTraceback(exc, (PyObject *)newtb);
return 0;
}

Called every time an exception propagates through a frame boundary. Builds a linked list of PyTracebackObject.

PyTraceBack_Print

// CPython: Python/traceback.c:155 PyTraceBack_Print
int
PyTraceBack_Print(PyObject *v, PyObject *f)
{
if (v == NULL) return 0;
/* Limit depth */
int limit = -1;
PyObject *limitv = PySys_GetObject("tracebacklimit");
if (limitv && PyLong_Check(limitv))
limit = PyLong_AsLong(limitv);
/* Count depth first, then print from limit backwards */
int depth = 0;
PyObject *tb = v;
while (tb != Py_None && tb != NULL) {
depth++;
tb = ((PyTracebackObject *)tb)->tb_next;
}
/* Print "Traceback (most recent call last):" */
PyFile_WriteString("Traceback (most recent call last):\n", f);
tb_printinternal(v, f, limit, depth);
return 0;
}

Frame line printing

// CPython: Python/traceback.c:320 tb_print_line
static int
tb_print_line(PyObject *f, PyObject *filename, int lineno, PyObject *name)
{
/* Print: ' File "path", line N, in name\n' */
PyFile_WriteString(" File \"", f);
PyFile_WriteObject(filename, f, Py_PRINT_RAW);
PyFile_WriteString("\", line ", f);
PyObject *lineno_obj = PyLong_FromLong(lineno);
PyFile_WriteObject(lineno_obj, f, Py_PRINT_RAW);
PyFile_WriteString(", in ", f);
PyFile_WriteObject(name, f, Py_PRINT_RAW);
PyFile_WriteString("\n", f);
/* Try to print the source line */
PyObject *line = _Py_DisplaySourceLine(f, filename, lineno, 4);
...
}

Exception group printing (3.11+)

// CPython: Python/traceback.c:740 print_exception_group
static int
print_exception_group(PyObject *f, PyObject *value, int indent, int limit)
{
/* Print the group header, then each sub-exception with indentation */
/* Format:
* + Exception Group Traceback (most recent call last):
* | File "...", line N, in ...
* | ExceptionGroup: message (N sub-exceptions)
* +-+---------------- 1 ----------------
* | Traceback ...
* | SubError: message
* +------------------------------------
*/
...
}

gopy notes

PyTraceBack_Here is called by vm.Frame.propagateException as the exception unwinds. PyTracebackObject maps to objects.Traceback with Next, Frame, Lineno fields. PyTraceBack_Print calls module/sys/module.go's stderr writer. _Py_DisplaySourceLine reads source via linecache.