Reputation: 293
Consider the following verysimple.py
:
if '__main__' == __name__:
prnt('Line1')
Now, if I execute it with > python verysimple.py
, I am, of course, greeted by:
Traceback (most recent call last):
File "verysimple.py", line 2, in <module>
prnt('Line1')
NameError: name 'prnt' is not defined`
I'd like to know where in the python-c-api Python is pulling the traceback information from (especially the erroneous command).
I've already tried to find my way inside PyEval_FrameEx
, but can't figure it out...
Upvotes: 0
Views: 140
Reputation:
You were on the right track. When parsing the code tree, it just runs through PyEval_FrameEx
multiple times.
In the end, it will call format_exc_check_arg()
to format the error, which for me happens at line 2100 in the ceval.c
of the Python version 3.3.2 source.
format_exc_check_arg()
deduces the offensive 'object' (prnt
) and calls PyErr_Format
in errors.c
to properly format the exception string (the exception type and its corresponding string, NAME_ERROR_MSG
, were already passed to format_exc_check_arg()
from this line 2100.
I used simply this code for testing:
prnt('Line1')
and then run it through a debug build of Python 3.3 I had around.
The surrounding code in PyEval_FrameEx
is
TARGET(LOAD_NAME)
w = GETITEM(names, oparg);
if ((v = f->f_locals) == NULL) {
PyErr_Format(PyExc_SystemError,
"no locals when loading %R", w);
why = WHY_EXCEPTION;
break;
}
if (PyDict_CheckExact(v)) {
x = PyDict_GetItem(v, w);
Py_XINCREF(x);
}
else {
x = PyObject_GetItem(v, w);
if (x == NULL && PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(
PyExc_KeyError))
break;
PyErr_Clear();
}
}
if (x == NULL) {
x = PyDict_GetItem(f->f_globals, w);
Py_XINCREF(x);
if (x == NULL) {
if (PyDict_CheckExact(f->f_builtins)) {
x = PyDict_GetItem(f->f_builtins, w);
if (x == NULL) {
// below is the line where the PyExc_NameError will be properly formatted.
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, w);
break;
}
Py_INCREF(x);
}
else {
x = PyObject_GetItem(f->f_builtins, w);
if (x == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError))
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, w);
break;
}
}
}
}
PUSH(x);
DISPATCH();
Note that two lines above it, PyDict_GetItem(...)
will be the line trying to find prnt
inside the builtin statements & functions (I deduce that from f->builtins
, to which w
is applied, w
itself gotten from the second statement in the above code.
Since that dictionary lookup will fail, x == NULL
and the NameError
is set and formatted.
Hope this helps you further.
Upvotes: 1