Add sys.excepthook.

Update docstring and library reference section on 'sys' module.
New API PyErr_Display, just for displaying errors, called by excepthook.
Uncaught exceptions now call sys.excepthook; if that fails, we fall back
    to calling PyErr_Display directly.
Also comes with sys.__excepthook__ and sys.__displayhook__.
This commit is contained in:
Ka-Ping Yee 2001-03-23 02:46:52 +00:00
parent 37f7b38eb6
commit b5c5132d1a
4 changed files with 108 additions and 23 deletions

View file

@ -48,11 +48,32 @@ Availability: Windows.
If \var{value} is not \code{None}, this function prints it to If \var{value} is not \code{None}, this function prints it to
\code{sys.stdout}, and saves it in \code{__builtin__._}. \code{sys.stdout}, and saves it in \code{__builtin__._}.
This function is called when an expression is entered at the prompt \code{sys.displayhook} is called on the result of evaluating
of an interactive Python session. It exists mainly so it can be an expression entered in an interactive Python session.
overridden. The display of these values can be customized by assigning
another function to \code{sys.displayhook}.
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{excepthook}{\var{type}, \var{value}, \var{traceback}}
This function prints out a given traceback and exception to
\code{sys.stderr}.
\code{sys.excepthook} is called when an exception is raised
and uncaught. In an interactive session this happens just before
control is returned to the prompt; in a Python program this happens
just before the program exits.
The handling of such top-level exceptions can be customized by
assigning another function to \code{sys.excepthook}.
\end{funcdesc}
\begin{datadesc}{__displayhook__}
\dataline{__excepthook__}
These objects contain the original values of \code{displayhook}
and \code{excepthook} at the start of the program. They are saved
so that \code{displayhook} and \code{excepthook} can be restored
in case they happen to get replaced with broken objects.
\end{datadesc}
\begin{funcdesc}{exc_info}{} \begin{funcdesc}{exc_info}{}
This function returns a tuple of three values that give information This function returns a tuple of three values that give information
about the exception that is currently being handled. The information about the exception that is currently being handled. The information

View file

@ -59,6 +59,7 @@ DL_IMPORT(struct symtable *) Py_SymtableString(char *, char *, int);
DL_IMPORT(void) PyErr_Print(void); DL_IMPORT(void) PyErr_Print(void);
DL_IMPORT(void) PyErr_PrintEx(int); DL_IMPORT(void) PyErr_PrintEx(int);
DL_IMPORT(void) PyErr_Display(PyObject *, PyObject *, PyObject *);
DL_IMPORT(int) Py_AtExit(void (*func)(void)); DL_IMPORT(int) Py_AtExit(void (*func)(void));

View file

@ -801,8 +801,7 @@ print_error_text(PyObject *f, int offset, char *text)
void void
PyErr_PrintEx(int set_sys_last_vars) PyErr_PrintEx(int set_sys_last_vars)
{ {
int err = 0; PyObject *exception, *v, *tb, *hook;
PyObject *exception, *v, *tb, *f;
PyErr_Fetch(&exception, &v, &tb); PyErr_Fetch(&exception, &v, &tb);
PyErr_NormalizeException(&exception, &v, &tb); PyErr_NormalizeException(&exception, &v, &tb);
@ -845,14 +844,47 @@ PyErr_PrintEx(int set_sys_last_vars)
PySys_SetObject("last_value", v); PySys_SetObject("last_value", v);
PySys_SetObject("last_traceback", tb); PySys_SetObject("last_traceback", tb);
} }
f = PySys_GetObject("stderr"); hook = PySys_GetObject("excepthook");
if (hook) {
PyObject *args = Py_BuildValue("(OOO)",
exception, v ? v : Py_None, tb ? tb : Py_None);
PyObject *result = PyEval_CallObject(hook, args);
if (result == NULL) {
PyObject *exception2, *v2, *tb2;
PyErr_Fetch(&exception2, &v2, &tb2);
PyErr_NormalizeException(&exception2, &v2, &tb2);
if (Py_FlushLine())
PyErr_Clear();
fflush(stdout);
PySys_WriteStderr("Error in sys.excepthook:\n");
PyErr_Display(exception2, v2, tb2);
PySys_WriteStderr("\nOriginal exception was:\n");
PyErr_Display(exception, v, tb);
}
Py_XDECREF(result);
Py_XDECREF(args);
} else {
PySys_WriteStderr("sys.excepthook is missing\n");
PyErr_Display(exception, v, tb);
}
Py_XDECREF(exception);
Py_XDECREF(v);
Py_XDECREF(tb);
}
void PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
{
int err = 0;
PyObject *v = value;
PyObject *f = PySys_GetObject("stderr");
if (f == NULL) if (f == NULL)
fprintf(stderr, "lost sys.stderr\n"); fprintf(stderr, "lost sys.stderr\n");
else { else {
if (Py_FlushLine()) if (Py_FlushLine())
PyErr_Clear(); PyErr_Clear();
fflush(stdout); fflush(stdout);
err = PyTraceBack_Print(tb, f); if (tb && tb != Py_None)
err = PyTraceBack_Print(tb, f);
if (err == 0 && if (err == 0 &&
PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError)) PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError))
{ {
@ -875,8 +907,6 @@ PyErr_PrintEx(int set_sys_last_vars)
PyFile_WriteString("\n", f); PyFile_WriteString("\n", f);
if (text != NULL) if (text != NULL)
print_error_text(f, offset, text); print_error_text(f, offset, text);
Py_INCREF(message);
Py_DECREF(v);
v = message; v = message;
/* Can't be bothered to check all those /* Can't be bothered to check all those
PyFile_WriteString() calls */ PyFile_WriteString() calls */
@ -932,9 +962,6 @@ PyErr_PrintEx(int set_sys_last_vars)
if (err == 0) if (err == 0)
err = PyFile_WriteString("\n", f); err = PyFile_WriteString("\n", f);
} }
Py_XDECREF(exception);
Py_XDECREF(v);
Py_XDECREF(tb);
/* If an error happened here, don't show it. /* If an error happened here, don't show it.
XXX This is wrong, but too many callers rely on this behavior. */ XXX This is wrong, but too many callers rely on this behavior. */
if (err != 0) if (err != 0)

View file

@ -107,9 +107,25 @@ sys_displayhook(PyObject *self, PyObject *args)
} }
static char displayhook_doc[] = static char displayhook_doc[] =
"displayhook(o) -> None\n" "displayhook(object) -> None\n"
"\n" "\n"
"Print o to the stdout, and save it in __builtin__._\n"; "Print an object to sys.stdout and also save it in __builtin__._\n";
static PyObject *
sys_excepthook(PyObject* self, PyObject* args)
{
PyObject *exc, *value, *tb;
if (!PyArg_ParseTuple(args, "OOO:excepthook", &exc, &value, &tb))
return NULL;
PyErr_Display(exc, value, tb);
Py_INCREF(Py_None);
return Py_None;
}
static char excepthook_doc[] =
"excepthook(exctype, value, traceback) -> None\n"
"\n"
"Handle an exception by displaying it with a traceback on sys.stderr.\n";
static PyObject * static PyObject *
sys_exc_info(PyObject *self, PyObject *args) sys_exc_info(PyObject *self, PyObject *args)
@ -378,6 +394,7 @@ static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */ /* Might as well keep this in alphabetic order */
{"displayhook", sys_displayhook, 1, displayhook_doc}, {"displayhook", sys_displayhook, 1, displayhook_doc},
{"exc_info", sys_exc_info, 1, exc_info_doc}, {"exc_info", sys_exc_info, 1, exc_info_doc},
{"excepthook", sys_excepthook, 1, excepthook_doc},
{"exit", sys_exit, 0, exit_doc}, {"exit", sys_exit, 0, exit_doc},
{"getdefaultencoding", sys_getdefaultencoding, 1, {"getdefaultencoding", sys_getdefaultencoding, 1,
getdefaultencoding_doc}, getdefaultencoding_doc},
@ -477,13 +494,20 @@ Dynamic objects:\n\
argv -- command line arguments; argv[0] is the script pathname if known\n\ argv -- command line arguments; argv[0] is the script pathname if known\n\
path -- module search path; path[0] is the script directory, else ''\n\ path -- module search path; path[0] is the script directory, else ''\n\
modules -- dictionary of loaded modules\n\ modules -- dictionary of loaded modules\n\
exitfunc -- you may set this to a function to be called when Python exits\n\ \n\
displayhook -- called to show results in an interactive session\n\
excepthook -- called to handle any uncaught exception other than SystemExit\n\
To customize printing in an interactive session or to install a custom\n\
top-level exception handler, assign other functions to replace these.\n\
\n\
exitfunc -- if sys.exitfunc exists, this routine is called when Python exits\n\
Assigning to sys.exitfunc is deprecated; use the atexit module instead.\n\
\n\ \n\
stdin -- standard input file object; used by raw_input() and input()\n\ stdin -- standard input file object; used by raw_input() and input()\n\
stdout -- standard output file object; used by the print statement\n\ stdout -- standard output file object; used by the print statement\n\
stderr -- standard error object; used for error messages\n\ stderr -- standard error object; used for error messages\n\
By assigning another file object (or an object that behaves like a file)\n\ By assigning other file objects (or objects that behave like files)\n\
to one of these, it is possible to redirect all of the interpreter's I/O.\n\ to these, it is possible to redirect all of the interpreter's I/O.\n\
\n\ \n\
last_type -- type of last uncaught exception\n\ last_type -- type of last uncaught exception\n\
last_value -- value of last uncaught exception\n\ last_value -- value of last uncaught exception\n\
@ -498,7 +522,7 @@ exc_traceback -- traceback of exception currently being handled\n\
because it is thread-safe.\n\ because it is thread-safe.\n\
" "
#ifndef MS_WIN16 #ifndef MS_WIN16
/* Concatenating string here */ /* concatenating string here */
"\n\ "\n\
Static objects:\n\ Static objects:\n\
\n\ \n\
@ -512,15 +536,23 @@ platform -- platform identifier\n\
executable -- pathname of this Python interpreter\n\ executable -- pathname of this Python interpreter\n\
prefix -- prefix used to find the Python library\n\ prefix -- prefix used to find the Python library\n\
exec_prefix -- prefix used to find the machine-specific Python library\n\ exec_prefix -- prefix used to find the machine-specific Python library\n\
dllhandle -- [Windows only] integer handle of the Python DLL\n\ "
#ifdef MS_WINDOWS
/* concatenating string here */
"dllhandle -- [Windows only] integer handle of the Python DLL\n\
winver -- [Windows only] version number of the Python DLL\n\ winver -- [Windows only] version number of the Python DLL\n\
__stdin__ -- the original stdin; don't use!\n\ "
__stdout__ -- the original stdout; don't use!\n\ #endif /* MS_WINDOWS */
__stderr__ -- the original stderr; don't use!\n\ "__stdin__ -- the original stdin; don't touch!\n\
__stdout__ -- the original stdout; don't touch!\n\
__stderr__ -- the original stderr; don't touch!\n\
__displayhook__ -- the original displayhook; don't touch!\n\
__excepthook__ -- the original excepthook; don't touch!\n\
\n\ \n\
Functions:\n\ Functions:\n\
\n\ \n\
displayhook() -- print an object to the screen, and save it in __builtin__._\n\ displayhook() -- print an object to the screen, and save it in __builtin__._\n\
excepthook() -- print an exception and its traceback to sys.stderr\n\
exc_info() -- return thread-safe information about the current exception\n\ exc_info() -- return thread-safe information about the current exception\n\
exit() -- exit the interpreter by raising SystemExit\n\ exit() -- exit the interpreter by raising SystemExit\n\
getrefcount() -- return the reference count for an object (plus one :-)\n\ getrefcount() -- return the reference count for an object (plus one :-)\n\
@ -530,7 +562,7 @@ setprofile() -- set the global profiling function\n\
setrecursionlimit() -- set the max recursion depth for the interpreter\n\ setrecursionlimit() -- set the max recursion depth for the interpreter\n\
settrace() -- set the global debug tracing function\n\ settrace() -- set the global debug tracing function\n\
" "
#endif #endif /* MS_WIN16 */
/* end of sys_doc */ ; /* end of sys_doc */ ;
PyObject * PyObject *
@ -555,6 +587,10 @@ _PySys_Init(void)
PyDict_SetItemString(sysdict, "__stdin__", sysin); PyDict_SetItemString(sysdict, "__stdin__", sysin);
PyDict_SetItemString(sysdict, "__stdout__", sysout); PyDict_SetItemString(sysdict, "__stdout__", sysout);
PyDict_SetItemString(sysdict, "__stderr__", syserr); PyDict_SetItemString(sysdict, "__stderr__", syserr);
PyDict_SetItemString(sysdict, "__displayhook__",
PyDict_GetItemString(sysdict, "displayhook"));
PyDict_SetItemString(sysdict, "__excepthook__",
PyDict_GetItemString(sysdict, "excepthook"));
Py_XDECREF(sysin); Py_XDECREF(sysin);
Py_XDECREF(sysout); Py_XDECREF(sysout);
Py_XDECREF(syserr); Py_XDECREF(syserr);