Revision 1371
Added by Aaron Marcuse-Kubitza almost 13 years ago
exc.py | ||
---|---|---|
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 |
Also available in: Unified diff
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.