mirror of
https://github.com/python/cpython.git
synced 2025-07-14 14:55:17 +00:00
parent
9bab65c259
commit
e65282114e
10 changed files with 449 additions and 133 deletions
|
@ -1242,18 +1242,19 @@ PyErr_PrintEx(int set_sys_last_vars)
|
|||
if (exception == NULL)
|
||||
return;
|
||||
PyErr_NormalizeException(&exception, &v, &tb);
|
||||
tb = tb ? tb : Py_None;
|
||||
PyException_SetTraceback(v, tb);
|
||||
if (exception == NULL)
|
||||
return;
|
||||
/* Now we know v != NULL too */
|
||||
if (set_sys_last_vars) {
|
||||
PySys_SetObject("last_type", exception);
|
||||
PySys_SetObject("last_value", v);
|
||||
PySys_SetObject("last_traceback", tb ? tb : Py_None);
|
||||
PySys_SetObject("last_traceback", tb);
|
||||
}
|
||||
hook = PySys_GetObject("excepthook");
|
||||
if (hook) {
|
||||
PyObject *args = PyTuple_Pack(3,
|
||||
exception, v, tb ? tb : Py_None);
|
||||
PyObject *args = PyTuple_Pack(3, exception, v, tb);
|
||||
PyObject *result = PyEval_CallObject(hook, args);
|
||||
if (result == NULL) {
|
||||
PyObject *exception2, *v2, *tb2;
|
||||
|
@ -1293,12 +1294,164 @@ PyErr_PrintEx(int set_sys_last_vars)
|
|||
Py_XDECREF(tb);
|
||||
}
|
||||
|
||||
static void
|
||||
print_exception(PyObject *f, PyObject *value)
|
||||
{
|
||||
int err = 0;
|
||||
PyObject *type, *tb;
|
||||
|
||||
Py_INCREF(value);
|
||||
fflush(stdout);
|
||||
type = (PyObject *) Py_TYPE(value);
|
||||
tb = PyException_GetTraceback(value);
|
||||
if (tb && tb != Py_None)
|
||||
err = PyTraceBack_Print(tb, f);
|
||||
if (err == 0 &&
|
||||
PyObject_HasAttrString(value, "print_file_and_line"))
|
||||
{
|
||||
PyObject *message;
|
||||
const char *filename, *text;
|
||||
int lineno, offset;
|
||||
if (!parse_syntax_error(value, &message, &filename,
|
||||
&lineno, &offset, &text))
|
||||
PyErr_Clear();
|
||||
else {
|
||||
char buf[10];
|
||||
PyFile_WriteString(" File \"", f);
|
||||
if (filename == NULL)
|
||||
PyFile_WriteString("<string>", f);
|
||||
else
|
||||
PyFile_WriteString(filename, f);
|
||||
PyFile_WriteString("\", line ", f);
|
||||
PyOS_snprintf(buf, sizeof(buf), "%d", lineno);
|
||||
PyFile_WriteString(buf, f);
|
||||
PyFile_WriteString("\n", f);
|
||||
if (text != NULL)
|
||||
print_error_text(f, offset, text);
|
||||
Py_DECREF(value);
|
||||
value = message;
|
||||
/* Can't be bothered to check all those
|
||||
PyFile_WriteString() calls */
|
||||
if (PyErr_Occurred())
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
if (err) {
|
||||
/* Don't do anything else */
|
||||
}
|
||||
else {
|
||||
assert(PyExceptionClass_Check(type));
|
||||
PyObject* moduleName;
|
||||
char* className = PyExceptionClass_Name(type);
|
||||
if (className != NULL) {
|
||||
char *dot = strrchr(className, '.');
|
||||
if (dot != NULL)
|
||||
className = dot+1;
|
||||
}
|
||||
|
||||
moduleName = PyObject_GetAttrString(type, "__module__");
|
||||
if (moduleName == NULL || !PyUnicode_Check(moduleName))
|
||||
{
|
||||
Py_DECREF(moduleName);
|
||||
err = PyFile_WriteString("<unknown>", f);
|
||||
}
|
||||
else {
|
||||
char* modstr = PyUnicode_AsString(moduleName);
|
||||
if (modstr && strcmp(modstr, "builtins"))
|
||||
{
|
||||
err = PyFile_WriteString(modstr, f);
|
||||
err += PyFile_WriteString(".", f);
|
||||
}
|
||||
Py_DECREF(moduleName);
|
||||
}
|
||||
if (err == 0) {
|
||||
if (className == NULL)
|
||||
err = PyFile_WriteString("<unknown>", f);
|
||||
else
|
||||
err = PyFile_WriteString(className, f);
|
||||
}
|
||||
}
|
||||
if (err == 0 && (value != Py_None)) {
|
||||
PyObject *s = PyObject_Str(value);
|
||||
/* only print colon if the str() of the
|
||||
object is not the empty string
|
||||
*/
|
||||
if (s == NULL)
|
||||
err = -1;
|
||||
else if (!PyUnicode_Check(s) ||
|
||||
PyUnicode_GetSize(s) != 0)
|
||||
err = PyFile_WriteString(": ", f);
|
||||
if (err == 0)
|
||||
err = PyFile_WriteObject(s, f, Py_PRINT_RAW);
|
||||
Py_XDECREF(s);
|
||||
}
|
||||
/* try to write a newline in any case */
|
||||
err += PyFile_WriteString("\n", f);
|
||||
Py_XDECREF(tb);
|
||||
Py_DECREF(value);
|
||||
/* If an error happened here, don't show it.
|
||||
XXX This is wrong, but too many callers rely on this behavior. */
|
||||
if (err != 0)
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
static const char *cause_message =
|
||||
"\nThe above exception was the direct cause "
|
||||
"of the following exception:\n\n";
|
||||
|
||||
static const char *context_message =
|
||||
"\nDuring handling of the above exception, "
|
||||
"another exception occurred:\n\n";
|
||||
|
||||
static void
|
||||
print_exception_recursive(PyObject *f, PyObject *value, PyObject *seen)
|
||||
{
|
||||
int err = 0, res;
|
||||
PyObject *cause, *context;
|
||||
|
||||
if (seen != NULL) {
|
||||
/* Exception chaining */
|
||||
if (PySet_Add(seen, value) == -1)
|
||||
PyErr_Clear();
|
||||
else if (PyExceptionInstance_Check(value)) {
|
||||
cause = PyException_GetCause(value);
|
||||
context = PyException_GetContext(value);
|
||||
if (cause) {
|
||||
res = PySet_Contains(seen, cause);
|
||||
if (res == -1)
|
||||
PyErr_Clear();
|
||||
if (res == 0) {
|
||||
print_exception_recursive(
|
||||
f, cause, seen);
|
||||
err |= PyFile_WriteString(
|
||||
cause_message, f);
|
||||
}
|
||||
}
|
||||
if (context) {
|
||||
res = PySet_Contains(seen, context);
|
||||
if (res == -1)
|
||||
PyErr_Clear();
|
||||
if (res == 0) {
|
||||
print_exception_recursive(
|
||||
f, context, seen);
|
||||
err |= PyFile_WriteString(
|
||||
context_message, f);
|
||||
}
|
||||
}
|
||||
Py_XDECREF(context);
|
||||
Py_XDECREF(cause);
|
||||
}
|
||||
}
|
||||
print_exception(f, value);
|
||||
if (err != 0)
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
void
|
||||
PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
|
||||
{
|
||||
int err = 0;
|
||||
PyObject *seen;
|
||||
PyObject *f = PySys_GetObject("stderr");
|
||||
Py_INCREF(value);
|
||||
if (f == Py_None) {
|
||||
/* pass */
|
||||
}
|
||||
|
@ -1307,97 +1460,15 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
|
|||
fprintf(stderr, "lost sys.stderr\n");
|
||||
}
|
||||
else {
|
||||
fflush(stdout);
|
||||
if (tb && tb != Py_None)
|
||||
err = PyTraceBack_Print(tb, f);
|
||||
if (err == 0 &&
|
||||
PyObject_HasAttrString(value, "print_file_and_line"))
|
||||
{
|
||||
PyObject *message;
|
||||
const char *filename, *text;
|
||||
int lineno, offset;
|
||||
if (!parse_syntax_error(value, &message, &filename,
|
||||
&lineno, &offset, &text))
|
||||
PyErr_Clear();
|
||||
else {
|
||||
char buf[10];
|
||||
PyFile_WriteString(" File \"", f);
|
||||
if (filename == NULL)
|
||||
PyFile_WriteString("<string>", f);
|
||||
else
|
||||
PyFile_WriteString(filename, f);
|
||||
PyFile_WriteString("\", line ", f);
|
||||
PyOS_snprintf(buf, sizeof(buf), "%d", lineno);
|
||||
PyFile_WriteString(buf, f);
|
||||
PyFile_WriteString("\n", f);
|
||||
if (text != NULL)
|
||||
print_error_text(f, offset, text);
|
||||
Py_DECREF(value);
|
||||
value = message;
|
||||
/* Can't be bothered to check all those
|
||||
PyFile_WriteString() calls */
|
||||
if (PyErr_Occurred())
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
if (err) {
|
||||
/* Don't do anything else */
|
||||
}
|
||||
else if (PyExceptionClass_Check(exception)) {
|
||||
PyObject* moduleName;
|
||||
char* className = PyExceptionClass_Name(exception);
|
||||
if (className != NULL) {
|
||||
char *dot = strrchr(className, '.');
|
||||
if (dot != NULL)
|
||||
className = dot+1;
|
||||
}
|
||||
|
||||
moduleName = PyObject_GetAttrString(exception, "__module__");
|
||||
if (moduleName == NULL || !PyUnicode_Check(moduleName))
|
||||
{
|
||||
Py_DECREF(moduleName);
|
||||
err = PyFile_WriteString("<unknown>", f);
|
||||
}
|
||||
else {
|
||||
char* modstr = PyUnicode_AsString(moduleName);
|
||||
if (modstr && strcmp(modstr, "builtins"))
|
||||
{
|
||||
err = PyFile_WriteString(modstr, f);
|
||||
err += PyFile_WriteString(".", f);
|
||||
}
|
||||
Py_DECREF(moduleName);
|
||||
}
|
||||
if (err == 0) {
|
||||
if (className == NULL)
|
||||
err = PyFile_WriteString("<unknown>", f);
|
||||
else
|
||||
err = PyFile_WriteString(className, f);
|
||||
}
|
||||
}
|
||||
else
|
||||
err = PyFile_WriteObject(exception, f, Py_PRINT_RAW);
|
||||
if (err == 0 && (value != Py_None)) {
|
||||
PyObject *s = PyObject_Str(value);
|
||||
/* only print colon if the str() of the
|
||||
object is not the empty string
|
||||
*/
|
||||
if (s == NULL)
|
||||
err = -1;
|
||||
else if (!PyUnicode_Check(s) ||
|
||||
PyUnicode_GetSize(s) != 0)
|
||||
err = PyFile_WriteString(": ", f);
|
||||
if (err == 0)
|
||||
err = PyFile_WriteObject(s, f, Py_PRINT_RAW);
|
||||
Py_XDECREF(s);
|
||||
}
|
||||
/* try to write a newline in any case */
|
||||
err += PyFile_WriteString("\n", f);
|
||||
/* We choose to ignore seen being possibly NULL, and report
|
||||
at least the main exception (it could be a MemoryError).
|
||||
*/
|
||||
seen = PySet_New(NULL);
|
||||
if (seen == NULL)
|
||||
PyErr_Clear();
|
||||
print_exception_recursive(f, value, seen);
|
||||
Py_XDECREF(seen);
|
||||
}
|
||||
Py_DECREF(value);
|
||||
/* If an error happened here, don't show it.
|
||||
XXX This is wrong, but too many callers rely on this behavior. */
|
||||
if (err != 0)
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
PyObject *
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue