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