Skip to main content

Python/errors.c (part 5)

Source:

cpython 3.14 @ ab2d84fe1023/Python/errors.c

This annotation covers syntax error location, internal call errors, and miscellaneous helpers. See python_errors4_detail for PyErr_Format, chaining, and _PyErr_StackItem.

Map

LinesSymbolRole
1-80PyErr_SyntaxLocationObjectSet filename/lineno/offset on a SyntaxError
81-180PyErr_BadInternalCallRaise SystemError for internal programming errors
181-280_PyErr_TrySetFromCauseSet an error only if no error is already set
281-380PyErr_WarnExIssue a warning via warnings.warn
381-500_PyErr_ChainExceptionsChain two exceptions manually

Reading

PyErr_SyntaxLocationObject

// CPython: Python/errors.c:1680 PyErr_SyntaxLocationObject
void
PyErr_SyntaxLocationObject(PyObject *filename, int lineno, int col_offset)
{
/* Set the location fields on the current SyntaxError exception. */
PyObject *exc = tstate->current_exception;
if (exc == NULL || !PyErr_GivenExceptionMatches(exc, PyExc_SyntaxError))
return;
/* Set filename */
if (filename != NULL)
PyObject_SetAttr(exc, &_Py_ID(filename), filename);
/* Set lineno */
PyObject_SetAttr(exc, &_Py_ID(lineno), PyLong_FromLong(lineno));
/* Set offset */
if (col_offset != -1)
PyObject_SetAttr(exc, &_Py_ID(offset), PyLong_FromLong(col_offset));
/* Try to fill in the source text from the file */
if (filename != NULL) {
PyObject *source = _PyErr_GetSourceLine(filename, lineno);
if (source) PyObject_SetAttr(exc, &_Py_ID(text), source);
}
}

Called by the compiler and tokenizer to annotate SyntaxError with the exact source location. _PyErr_GetSourceLine opens the source file and reads line lineno for SyntaxError.text.

PyErr_BadInternalCall

// CPython: Python/errors.c:1780 PyErr_BadInternalCall
void
PyErr_BadInternalCall(void)
{
/* Raise SystemError: bad argument to internal function */
assert(0 && "bad argument to internal function");
PyErr_SetString(PyExc_SystemError,
"bad argument to internal function");
}

PyErr_BadInternalCall is called when a C extension passes NULL to a function that requires a valid Python object. The assert(0) fires in debug builds to catch the bug at the source.

PyErr_WarnEx

// CPython: Python/errors.c:1860 PyErr_WarnEx
int
PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
{
/* Invoke warnings.warn(text, category, stacklevel=stack_level) */
PyObject *warnings = PyImport_ImportModuleNoBlock("warnings");
if (warnings == NULL) return -1;
PyObject *warn = PyObject_GetAttr(warnings, &_Py_ID(warn));
PyObject *res = PyObject_CallFunction(warn, "sOn",
text, category, stack_level);
Py_XDECREF(res);
Py_DECREF(warn);
Py_DECREF(warnings);
return res == NULL ? -1 : 0;
}

PyErr_WarnEx(PyExc_DeprecationWarning, "use foo instead", 2) issues a DeprecationWarning pointing 2 frames up the call stack (the caller of the caller). Used by functools.wraps compatibility shims, deprecated API wrappers, etc.

_PyErr_ChainExceptions

// CPython: Python/errors.c:1940 _PyErr_ChainExceptions
void
_PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb)
{
/* Set the current exception, chaining the existing one as __context__. */
if (val == NULL) {
Py_XDECREF(typ);
Py_XDECREF(tb);
return;
}
if (!PyExceptionInstance_Check(val)) {
...
}
PyObject *exc2 = tstate->current_exception;
if (exc2 != NULL) {
/* Chain: new exception's __context__ = old exception */
Py_INCREF(exc2);
PyException_SetContext(val, exc2);
}
_PyErr_Restore(tstate, typ, val, tb);
}

Used in C code that catches an exception (via PyErr_Fetch) and wants to raise a different exception while preserving the original as __context__.

gopy notes

PyErr_SyntaxLocationObject is errors.SyntaxLocationObject in vm/errors.go. PyErr_BadInternalCall is errors.BadInternalCall which calls panic in debug mode. PyErr_WarnEx is errors.WarnEx which dispatches to module/warnings. _PyErr_ChainExceptions is errors.ChainExceptions.