2 from __future__ import absolute_import, print_function
3 from array import array
4 from binascii import hexlify
5 from traceback import print_exception
8 # Please see CODINGSTYLE for important exception handling guidelines
9 # and the rationale behind add_ex_tb(), add_ex_ctx(), etc.
11 py_maj = sys.version_info[0]
16 from os import environb as environ
17 from os import fsdecode, fsencode
18 from shlex import quote
25 """Return hex string (not bytes as with hexlify) representation of b."""
29 raise ex.with_traceback(sys.exc_info()[2])
32 """Do nothing (already handled by Python 3 infrastructure)."""
35 def add_ex_ctx(ex, context_ex):
36 """Do nothing (already handled by Python 3 infrastructure)."""
43 """Return the original bytes passed to main() for an argv argument."""
46 def bytes_from_uint(i):
49 def bytes_from_byte(b): # python > 2: b[3] returns ord('x'), not b'x'
52 byte_int = lambda x: x
54 def buffer(object, offset=None, size=None):
56 assert offset is not None
57 return memoryview(object)[offset:offset + size]
59 return memoryview(object)[offset:]
60 return memoryview(object)
63 return fsencode(os.getcwd())
73 from pipes import quote
74 from os import environ, getcwd
76 from bup.py2raise import reraise
81 int_types = (int, long)
86 """Add a traceback to ex if it doesn't already have one. Return ex.
89 if not getattr(ex, '__traceback__', None):
90 ex.__traceback__ = sys.exc_info()[2]
93 def add_ex_ctx(ex, context_ex):
94 """Make context_ex the __context__ of ex (unless it already has one).
99 if not getattr(ex, '__context__', None):
100 ex.__context__ = context_ex
103 def dump_traceback(ex):
105 next_ex = getattr(ex, '__context__', None)
107 stack.append(next_ex)
108 next_ex = getattr(next_ex, '__context__', None)
109 stack = reversed(stack)
111 tb = getattr(ex, '__traceback__', None)
112 print_exception(type(ex), ex, tb)
114 print('\nDuring handling of the above exception, another exception occurred:\n',
116 tb = getattr(ex, '__traceback__', None)
117 print_exception(type(ex), ex, tb)
123 """Return the original bytes passed to main() for an argv argument."""
126 bytes_from_uint = chr
128 def bytes_from_byte(b):
139 def _configure_argv():
143 if len(sys.argv) > 1:
144 if environ.get(b'BUP_ARGV_0'):
145 print('error: BUP_ARGV* set and sys.argv not empty', file=sys.stderr)
148 argvb = [argv_bytes(x) for x in argv]
152 arg = environ.get(b'BUP_ARGV_%d' % i)
153 while arg is not None:
156 arg = environ.get(b'BUP_ARGV_%d' % i)
159 del environ[b'BUP_ARGV_%d' % i]
164 argv = [x.decode(errors='surrogateescape') for x in args]
172 """Run main() and raise a SystemExit with the return value if it
173 returns, pass along any SystemExit it raises, convert
174 KeyboardInterrupts into exit(130), and print a Python 3 style
175 contextual backtrace for other exceptions in both Python 2 and
179 except KeyboardInterrupt as ex:
181 except SystemExit as ex:
183 except BaseException as ex:
191 # Excepting wrap_main() in the traceback, these should produce similar output:
192 # python2 lib/bup/compat.py
193 # python3 lib/bup/compat.py
195 # diff -u <(python2 lib/bup/compat.py 2>&1) <(python3 lib/bup/compat.py 2>&1)
197 # Though the python3 output for 'second' will include a stacktrace
198 # starting from wrap_main, rather than from outer().
200 if __name__ == '__main__':
203 raise Exception('first')
208 except Exception as ex:
211 raise Exception('second')
212 except Exception as ex2:
213 raise add_ex_ctx(add_ex_tb(ex2), ex)