]> arthur.barton.de Git - bup.git/blob - lib/bup/compat.py
add_ex_tb: return the exception
[bup.git] / lib / bup / compat.py
1
2 from __future__ import print_function
3 from traceback import print_exception
4 import sys
5
6 py_maj = sys.version_info[0]
7 py3 = py_maj >= 3
8
9 if py3:
10
11     str_type = str
12
13     def add_ex_tb(ex):
14         """Do nothing (already handled by Python 3 infrastructure)."""
15         return ex
16
17     def chain_ex(ex, context_ex):
18         return ex
19
20 else:  # Python 2
21
22     str_type = basestring
23
24     def add_ex_tb(ex):
25         """Add a traceback to ex if it doesn't already have one.  Return ex.
26
27         """
28         if not getattr(ex, '__traceback__', None):
29             ex.__traceback__ = sys.exc_info()[2]
30         return ex
31
32     def chain_ex(ex, context_ex):
33         if context_ex:
34             add_ex_tb(context_ex)
35             if not getattr(ex, '__context__', None):
36                 ex.__context__ = context_ex
37         return ex
38
39     def dump_traceback(ex):
40         stack = [ex]
41         next_ex = getattr(ex, '__context__', None)
42         while next_ex:
43             stack.append(next_ex)
44             next_ex = getattr(next_ex, '__context__', None)
45         stack = reversed(stack)
46         ex = next(stack)
47         tb = getattr(ex, '__traceback__', None)
48         print_exception(type(ex), ex, tb)
49         for ex in stack:
50             print('\nDuring handling of the above exception, another exception occurred:\n',
51                   file=sys.stderr)
52             tb = getattr(ex, '__traceback__', None)
53             print_exception(type(ex), ex, tb)
54
55 def wrap_main(main):
56     """Run main() and raise a SystemExit with the return value if it
57     returns, pass along any SystemExit it raises, convert
58     KeyboardInterrupts into exit(130), and print a Python 3 style
59     contextual backtrace for other exceptions in both Python 2 and
60     3)."""
61     try:
62         sys.exit(main())
63     except KeyboardInterrupt as ex:
64         sys.exit(130)
65     except SystemExit as ex:
66         raise
67     except BaseException as ex:
68         if py3:
69             raise
70         add_ex_tb(ex)
71         dump_traceback(ex)
72         sys.exit(1)
73
74
75 # Excepting wrap_main() in the traceback, these should produce the same output:
76 #   python2 lib/bup/compat.py
77 #   python3 lib/bup/compat.py
78 # i.e.:
79 #   diff -u <(python2 lib/bup/compat.py 2>&1) <(python3 lib/bup/compat.py 2>&1)
80
81 if __name__ == '__main__':
82
83     def inner():
84         raise Exception('first')
85
86     def outer():
87         try:
88             inner()
89         except Exception as ex:
90             raise chain_ex(Exception('second'), ex)
91
92     wrap_main(outer)