Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b5c5132

Browse files
committed
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__.
1 parent 37f7b38 commit b5c5132

4 files changed

Lines changed: 108 additions & 23 deletions

File tree

Doc/lib/libsys.tex

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,32 @@ \section{\module{sys} ---
4848
If \var{value} is not \code{None}, this function prints it to
4949
\code{sys.stdout}, and saves it in \code{__builtin__._}.
5050

51-
This function is called when an expression is entered at the prompt
52-
of an interactive Python session. It exists mainly so it can be
53-
overridden.
51+
\code{sys.displayhook} is called on the result of evaluating
52+
an expression entered in an interactive Python session.
53+
The display of these values can be customized by assigning
54+
another function to \code{sys.displayhook}.
5455
\end{funcdesc}
5556

57+
\begin{funcdesc}{excepthook}{\var{type}, \var{value}, \var{traceback}}
58+
This function prints out a given traceback and exception to
59+
\code{sys.stderr}.
60+
61+
\code{sys.excepthook} is called when an exception is raised
62+
and uncaught. In an interactive session this happens just before
63+
control is returned to the prompt; in a Python program this happens
64+
just before the program exits.
65+
The handling of such top-level exceptions can be customized by
66+
assigning another function to \code{sys.excepthook}.
67+
\end{funcdesc}
68+
69+
\begin{datadesc}{__displayhook__}
70+
\dataline{__excepthook__}
71+
These objects contain the original values of \code{displayhook}
72+
and \code{excepthook} at the start of the program. They are saved
73+
so that \code{displayhook} and \code{excepthook} can be restored
74+
in case they happen to get replaced with broken objects.
75+
\end{datadesc}
76+
5677
\begin{funcdesc}{exc_info}{}
5778
This function returns a tuple of three values that give information
5879
about the exception that is currently being handled. The information

Include/pythonrun.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ DL_IMPORT(struct symtable *) Py_SymtableString(char *, char *, int);
5959

6060
DL_IMPORT(void) PyErr_Print(void);
6161
DL_IMPORT(void) PyErr_PrintEx(int);
62+
DL_IMPORT(void) PyErr_Display(PyObject *, PyObject *, PyObject *);
6263

6364
DL_IMPORT(int) Py_AtExit(void (*func)(void));
6465

Python/pythonrun.c

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -801,8 +801,7 @@ print_error_text(PyObject *f, int offset, char *text)
801801
void
802802
PyErr_PrintEx(int set_sys_last_vars)
803803
{
804-
int err = 0;
805-
PyObject *exception, *v, *tb, *f;
804+
PyObject *exception, *v, *tb, *hook;
806805
PyErr_Fetch(&exception, &v, &tb);
807806
PyErr_NormalizeException(&exception, &v, &tb);
808807

@@ -845,14 +844,47 @@ PyErr_PrintEx(int set_sys_last_vars)
845844
PySys_SetObject("last_value", v);
846845
PySys_SetObject("last_traceback", tb);
847846
}
848-
f = PySys_GetObject("stderr");
847+
hook = PySys_GetObject("excepthook");
848+
if (hook) {
849+
PyObject *args = Py_BuildValue("(OOO)",
850+
exception, v ? v : Py_None, tb ? tb : Py_None);
851+
PyObject *result = PyEval_CallObject(hook, args);
852+
if (result == NULL) {
853+
PyObject *exception2, *v2, *tb2;
854+
PyErr_Fetch(&exception2, &v2, &tb2);
855+
PyErr_NormalizeException(&exception2, &v2, &tb2);
856+
if (Py_FlushLine())
857+
PyErr_Clear();
858+
fflush(stdout);
859+
PySys_WriteStderr("Error in sys.excepthook:\n");
860+
PyErr_Display(exception2, v2, tb2);
861+
PySys_WriteStderr("\nOriginal exception was:\n");
862+
PyErr_Display(exception, v, tb);
863+
}
864+
Py_XDECREF(result);
865+
Py_XDECREF(args);
866+
} else {
867+
PySys_WriteStderr("sys.excepthook is missing\n");
868+
PyErr_Display(exception, v, tb);
869+
}
870+
Py_XDECREF(exception);
871+
Py_XDECREF(v);
872+
Py_XDECREF(tb);
873+
}
874+
875+
void PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
876+
{
877+
int err = 0;
878+
PyObject *v = value;
879+
PyObject *f = PySys_GetObject("stderr");
849880
if (f == NULL)
850881
fprintf(stderr, "lost sys.stderr\n");
851882
else {
852883
if (Py_FlushLine())
853884
PyErr_Clear();
854885
fflush(stdout);
855-
err = PyTraceBack_Print(tb, f);
886+
if (tb && tb != Py_None)
887+
err = PyTraceBack_Print(tb, f);
856888
if (err == 0 &&
857889
PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError))
858890
{
@@ -875,8 +907,6 @@ PyErr_PrintEx(int set_sys_last_vars)
875907
PyFile_WriteString("\n", f);
876908
if (text != NULL)
877909
print_error_text(f, offset, text);
878-
Py_INCREF(message);
879-
Py_DECREF(v);
880910
v = message;
881911
/* Can't be bothered to check all those
882912
PyFile_WriteString() calls */
@@ -932,9 +962,6 @@ PyErr_PrintEx(int set_sys_last_vars)
932962
if (err == 0)
933963
err = PyFile_WriteString("\n", f);
934964
}
935-
Py_XDECREF(exception);
936-
Py_XDECREF(v);
937-
Py_XDECREF(tb);
938965
/* If an error happened here, don't show it.
939966
XXX This is wrong, but too many callers rely on this behavior. */
940967
if (err != 0)

Python/sysmodule.c

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,25 @@ sys_displayhook(PyObject *self, PyObject *args)
107107
}
108108

109109
static char displayhook_doc[] =
110-
"displayhook(o) -> None\n"
110+
"displayhook(object) -> None\n"
111111
"\n"
112-
"Print o to the stdout, and save it in __builtin__._\n";
112+
"Print an object to sys.stdout and also save it in __builtin__._\n";
113+
114+
static PyObject *
115+
sys_excepthook(PyObject* self, PyObject* args)
116+
{
117+
PyObject *exc, *value, *tb;
118+
if (!PyArg_ParseTuple(args, "OOO:excepthook", &exc, &value, &tb))
119+
return NULL;
120+
PyErr_Display(exc, value, tb);
121+
Py_INCREF(Py_None);
122+
return Py_None;
123+
}
124+
125+
static char excepthook_doc[] =
126+
"excepthook(exctype, value, traceback) -> None\n"
127+
"\n"
128+
"Handle an exception by displaying it with a traceback on sys.stderr.\n";
113129

114130
static PyObject *
115131
sys_exc_info(PyObject *self, PyObject *args)
@@ -378,6 +394,7 @@ static PyMethodDef sys_methods[] = {
378394
/* Might as well keep this in alphabetic order */
379395
{"displayhook", sys_displayhook, 1, displayhook_doc},
380396
{"exc_info", sys_exc_info, 1, exc_info_doc},
397+
{"excepthook", sys_excepthook, 1, excepthook_doc},
381398
{"exit", sys_exit, 0, exit_doc},
382399
{"getdefaultencoding", sys_getdefaultencoding, 1,
383400
getdefaultencoding_doc},
@@ -477,13 +494,20 @@ Dynamic objects:\n\
477494
argv -- command line arguments; argv[0] is the script pathname if known\n\
478495
path -- module search path; path[0] is the script directory, else ''\n\
479496
modules -- dictionary of loaded modules\n\
480-
exitfunc -- you may set this to a function to be called when Python exits\n\
497+
\n\
498+
displayhook -- called to show results in an interactive session\n\
499+
excepthook -- called to handle any uncaught exception other than SystemExit\n\
500+
To customize printing in an interactive session or to install a custom\n\
501+
top-level exception handler, assign other functions to replace these.\n\
502+
\n\
503+
exitfunc -- if sys.exitfunc exists, this routine is called when Python exits\n\
504+
Assigning to sys.exitfunc is deprecated; use the atexit module instead.\n\
481505
\n\
482506
stdin -- standard input file object; used by raw_input() and input()\n\
483507
stdout -- standard output file object; used by the print statement\n\
484508
stderr -- standard error object; used for error messages\n\
485-
By assigning another file object (or an object that behaves like a file)\n\
486-
to one of these, it is possible to redirect all of the interpreter's I/O.\n\
509+
By assigning other file objects (or objects that behave like files)\n\
510+
to these, it is possible to redirect all of the interpreter's I/O.\n\
487511
\n\
488512
last_type -- type of last uncaught exception\n\
489513
last_value -- value of last uncaught exception\n\
@@ -498,7 +522,7 @@ exc_traceback -- traceback of exception currently being handled\n\
498522
because it is thread-safe.\n\
499523
"
500524
#ifndef MS_WIN16
501-
/* Concatenating string here */
525+
/* concatenating string here */
502526
"\n\
503527
Static objects:\n\
504528
\n\
@@ -512,15 +536,23 @@ platform -- platform identifier\n\
512536
executable -- pathname of this Python interpreter\n\
513537
prefix -- prefix used to find the Python library\n\
514538
exec_prefix -- prefix used to find the machine-specific Python library\n\
515-
dllhandle -- [Windows only] integer handle of the Python DLL\n\
539+
"
540+
#ifdef MS_WINDOWS
541+
/* concatenating string here */
542+
"dllhandle -- [Windows only] integer handle of the Python DLL\n\
516543
winver -- [Windows only] version number of the Python DLL\n\
517-
__stdin__ -- the original stdin; don't use!\n\
518-
__stdout__ -- the original stdout; don't use!\n\
519-
__stderr__ -- the original stderr; don't use!\n\
544+
"
545+
#endif /* MS_WINDOWS */
546+
"__stdin__ -- the original stdin; don't touch!\n\
547+
__stdout__ -- the original stdout; don't touch!\n\
548+
__stderr__ -- the original stderr; don't touch!\n\
549+
__displayhook__ -- the original displayhook; don't touch!\n\
550+
__excepthook__ -- the original excepthook; don't touch!\n\
520551
\n\
521552
Functions:\n\
522553
\n\
523554
displayhook() -- print an object to the screen, and save it in __builtin__._\n\
555+
excepthook() -- print an exception and its traceback to sys.stderr\n\
524556
exc_info() -- return thread-safe information about the current exception\n\
525557
exit() -- exit the interpreter by raising SystemExit\n\
526558
getrefcount() -- return the reference count for an object (plus one :-)\n\
@@ -530,7 +562,7 @@ setprofile() -- set the global profiling function\n\
530562
setrecursionlimit() -- set the max recursion depth for the interpreter\n\
531563
settrace() -- set the global debug tracing function\n\
532564
"
533-
#endif
565+
#endif /* MS_WIN16 */
534566
/* end of sys_doc */ ;
535567

536568
PyObject *
@@ -555,6 +587,10 @@ _PySys_Init(void)
555587
PyDict_SetItemString(sysdict, "__stdin__", sysin);
556588
PyDict_SetItemString(sysdict, "__stdout__", sysout);
557589
PyDict_SetItemString(sysdict, "__stderr__", syserr);
590+
PyDict_SetItemString(sysdict, "__displayhook__",
591+
PyDict_GetItemString(sysdict, "displayhook"));
592+
PyDict_SetItemString(sysdict, "__excepthook__",
593+
PyDict_GetItemString(sysdict, "excepthook"));
558594
Py_XDECREF(sysin);
559595
Py_XDECREF(sysout);
560596
Py_XDECREF(syserr);

0 commit comments

Comments
 (0)