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