]> arthur.barton.de Git - bup.git/blob - lib/bup/compat.py
Update base_version to 0.34~ for 0.34 development
[bup.git] / lib / bup / compat.py
1
2 # pylint: disable=unused-import
3 from contextlib import ExitStack, nullcontext
4 from os import environb as environ
5 from os import fsdecode, fsencode
6 from shlex import quote
7 import os, sys
8
9 def hexstr(b):
10     """Return hex string (not bytes as with hexlify) representation of b."""
11     return b.hex()
12
13 def reraise(ex):
14     raise ex.with_traceback(sys.exc_info()[2])
15
16 # These three functions (add_ex_tb, add_ex_ctx, and pending_raise) are
17 # vestigial, and code that uses them can probably be rewritten more
18 # simply now that we require Python versions that automatically
19 # populate the tracebacks and automatically chain pending exceptions.
20
21 def add_ex_tb(ex):
22     """Do nothing (already handled by Python 3 infrastructure)."""
23     return ex
24
25 def add_ex_ctx(ex, context_ex):
26     """Do nothing (already handled by Python 3 infrastructure)."""
27     return ex
28
29 class pending_raise:
30     """If rethrow is true, rethrow ex (if any), unless the body throws.
31
32     (Supports Python 2 compatibility.)
33
34     """
35     # This is completely vestigial, and should be removed
36     def __init__(self, ex, rethrow=True):
37         self.closed = False
38         self.ex = ex
39         self.rethrow = rethrow
40     def __enter__(self):
41         return None
42     def __exit__(self, exc_type, exc_value, traceback):
43         self.closed = True
44         if not exc_type and self.ex and self.rethrow:
45             raise self.ex
46     def __del__(self):
47         assert self.closed
48
49 def argv_bytes(x):
50     """Return the original bytes passed to main() for an argv argument."""
51     return fsencode(x)
52
53 def bytes_from_uint(i):
54     return bytes((i,))
55
56 def bytes_from_byte(b):  # python > 2: b[3] returns ord('x'), not b'x'
57     return bytes((b,))
58
59 byte_int = lambda x: x
60
61 def buffer(object, offset=None, size=None):
62     if size:
63         assert offset is not None
64         return memoryview(object)[offset:offset + size]
65     if offset:
66         return memoryview(object)[offset:]
67     return memoryview(object)
68
69 def getcwd():
70     return fsencode(os.getcwd())
71
72
73 try:
74     import bup_main
75 except ModuleNotFoundError:
76     bup_main = None
77
78 if bup_main:
79     def get_argvb():
80         "Return a new list containing the current process argv bytes."
81         return bup_main.argv()
82     def get_argv():
83         "Return a new list containing the current process argv strings."
84         return [x.decode(errors='surrogateescape') for x in bup_main.argv()]
85 else:
86     def get_argvb():
87         raise Exception('get_argvb requires the bup_main module');
88     def get_argv():
89         raise Exception('get_argv requires the bup_main module');
90
91 def wrap_main(main):
92     """Run main() and raise a SystemExit with the return value if it
93     returns, pass along any SystemExit it raises, convert
94     KeyboardInterrupts into exit(130), and print a Python 3 style
95     contextual backtrace for other exceptions in both Python 2 and
96     3)."""
97     try:
98         sys.exit(main())
99     except KeyboardInterrupt as ex:
100         sys.exit(130)