1 |
1 |
# Exception handling
|
2 |
2 |
|
|
3 |
import copy
|
3 |
4 |
import atexit
|
4 |
5 |
import sys
|
5 |
6 |
import traceback
|
... | ... | |
11 |
12 |
|
12 |
13 |
def raise_(e): raise e
|
13 |
14 |
|
14 |
|
def add_exc_info(e):
|
15 |
|
'''Note that this will create a circular reference in the traceback
|
16 |
|
(See <http://docs.python.org/library/sys.html#sys.exc_info>)'''
|
17 |
|
e.exc_info = sys.exc_info()
|
|
15 |
def sys_traceback():
|
|
16 |
'''Note that Python tracebacks seems to have a bug that truncates them to
|
|
17 |
only a few stack frames. See <http://bugs.python.org/issue7378>.'''
|
|
18 |
return sys.exc_info()[2]
|
|
19 |
# can't just return pointer to traceback because it will change :-(
|
18 |
20 |
|
19 |
|
def get_exc_info(e):
|
20 |
|
try: exc_info = e.exc_info
|
21 |
|
except AttributeError: exc_info = sys.exc_info()
|
22 |
|
assert exc_info[1] is e
|
23 |
|
return exc_info
|
|
21 |
def has_traceback(e): return hasattr(e, 'traceback_')
|
24 |
22 |
|
|
23 |
def add_traceback(e):
|
|
24 |
'''Adds current traceback to an exception if it doesn't already have one'''
|
|
25 |
traceback_ = sys_traceback() # get first in case later code throws exception
|
|
26 |
if not has_traceback(e): e.traceback_ = traceback_
|
|
27 |
|
|
28 |
def get_traceback_str(e):
|
|
29 |
try: traceback_ = e.traceback_
|
|
30 |
except AttributeError: return ''
|
|
31 |
return ''.join(traceback.format_exception(None, None, traceback_)[:-1])
|
|
32 |
# remove final "None" line ("exception name")
|
|
33 |
|
25 |
34 |
def add_msg(e, msg): e.args = (strings.ensure_newl(str(e))+msg,)
|
26 |
35 |
|
27 |
36 |
def repl_msg(e, **repls): e.args = (str(e) % repls,)
|
... | ... | |
31 |
40 |
class ExceptionWithCause(Exception):
|
32 |
41 |
def __init__(self, msg, cause=None):
|
33 |
42 |
Exception.__init__(self, msg)
|
|
43 |
add_traceback(self)
|
34 |
44 |
if cause != None: add_msg(self, 'cause: '+str_(cause))
|
35 |
45 |
|
36 |
|
def str_(e, with_traceback=True):
|
37 |
|
lines = traceback.format_exception_only(type(e), e)
|
38 |
|
if with_traceback: lines += traceback.format_tb(get_exc_info(e)[2])
|
39 |
|
return ''.join(lines)
|
|
46 |
def str_(e): return ''.join(traceback.format_exception_only(type(e), e))
|
40 |
47 |
|
41 |
|
def print_ex(e, emph=True, **format):
|
42 |
|
msg = str_(e, **format)
|
|
48 |
def print_ex(e, emph=True):
|
|
49 |
msg = strings.ensure_newl(str_(e))+get_traceback_str(e)
|
43 |
50 |
if emph:
|
44 |
51 |
first_line, nl, rest = msg.partition('\n')
|
45 |
52 |
msg = term.error(first_line)+nl+rest
|
exc.py: Fixed bug in traceback-saving mechanism that didn't deal with nested Exceptions (such as Exceptions with causes in ExceptionWithCause). Renamed add_exc_info() to add_traceback() since we really only need to store the traceback.