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