Project

General

Profile

« Previous | Next » 

Revision 1371

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.

View differences:

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