]> arthur.barton.de Git - bup.git/blobdiff - lib/bup/compat.py
Drop vestigial compat.input
[bup.git] / lib / bup / compat.py
index 8a142822f4f84d7f00441d7224864b5f478a1958..3b460ededde4a1cde1fb65398d7a776082cfe3de 100644 (file)
 
-from __future__ import absolute_import, print_function
-from traceback import print_exception
-import sys
-
-# Please see CODINGSTYLE for important exception handling guidelines
-# and the rationale behind add_ex_tb(), chain_ex(), etc.
-
-py_maj = sys.version_info[0]
-py3 = py_maj >= 3
-
-if py3:
-
-    str_type = str
-
-    def add_ex_tb(ex):
-        """Do nothing (already handled by Python 3 infrastructure)."""
-        return ex
-
-    def chain_ex(ex, context_ex):
-        """Do nothing (already handled by Python 3 infrastructure)."""
-        return ex
-
-    def items(x):
-        return x.items()
-
-else:  # Python 2
-
-    str_type = basestring
-
-    def add_ex_tb(ex):
-        """Add a traceback to ex if it doesn't already have one.  Return ex.
-
-        """
-        if not getattr(ex, '__traceback__', None):
-            ex.__traceback__ = sys.exc_info()[2]
-        return ex
-
-    def chain_ex(ex, context_ex):
-        """Chain context_ex to ex as the __context__ (unless it already has
-        one).  Return ex.
-
-        """
-        if context_ex:
-            if not getattr(ex, '__context__', None):
-                ex.__context__ = context_ex
-        return ex
-
-    def dump_traceback(ex):
-        stack = [ex]
-        next_ex = getattr(ex, '__context__', None)
-        while next_ex:
-            stack.append(next_ex)
-            next_ex = getattr(next_ex, '__context__', None)
-        stack = reversed(stack)
-        ex = next(stack)
-        tb = getattr(ex, '__traceback__', None)
-        print_exception(type(ex), ex, tb)
-        for ex in stack:
-            print('\nDuring handling of the above exception, another exception occurred:\n',
-                  file=sys.stderr)
-            tb = getattr(ex, '__traceback__', None)
-            print_exception(type(ex), ex, tb)
-
-    def items(x):
-        return x.iteritems()
-
+import os, sys
+
+py_maj = sys.version_info.major
+assert py_maj >= 3
+
+# pylint: disable=unused-import
+from contextlib import ExitStack, nullcontext
+from os import environb as environ
+from os import fsdecode, fsencode
+from shlex import quote
+
+range = range
+str_type = str
+int_types = (int,)
+
+def hexstr(b):
+    """Return hex string (not bytes as with hexlify) representation of b."""
+    return b.hex()
+
+def reraise(ex):
+    raise ex.with_traceback(sys.exc_info()[2])
+
+# These three functions (add_ex_tb, add_ex_ctx, and pending_raise) are
+# vestigial, and code that uses them can probably be rewritten more
+# simply now that we require Python versions that automatically
+# populate the tracebacks and automatically chain pending exceptions.
+
+def add_ex_tb(ex):
+    """Do nothing (already handled by Python 3 infrastructure)."""
+    return ex
+
+def add_ex_ctx(ex, context_ex):
+    """Do nothing (already handled by Python 3 infrastructure)."""
+    return ex
+
+class pending_raise:
+    """If rethrow is true, rethrow ex (if any), unless the body throws.
+
+    (Supports Python 2 compatibility.)
+
+    """
+    # This is completely vestigial, and should be removed
+    def __init__(self, ex, rethrow=True):
+        self.closed = False
+        self.ex = ex
+        self.rethrow = rethrow
+    def __enter__(self):
+        return None
+    def __exit__(self, exc_type, exc_value, traceback):
+        self.closed = True
+        if not exc_type and self.ex and self.rethrow:
+            raise self.ex
+    def __del__(self):
+        assert self.closed
+
+def items(x):
+    return x.items()
+
+def argv_bytes(x):
+    """Return the original bytes passed to main() for an argv argument."""
+    return fsencode(x)
+
+def bytes_from_uint(i):
+    return bytes((i,))
+
+def bytes_from_byte(b):  # python > 2: b[3] returns ord('x'), not b'x'
+    return bytes((b,))
+
+byte_int = lambda x: x
+
+def buffer(object, offset=None, size=None):
+    if size:
+        assert offset is not None
+        return memoryview(object)[offset:offset + size]
+    if offset:
+        return memoryview(object)[offset:]
+    return memoryview(object)
+
+def getcwd():
+    return fsencode(os.getcwd())
+
+
+try:
+    import bup_main
+except ModuleNotFoundError:
+    bup_main = None
+
+if bup_main:
+    def get_argvb():
+        "Return a new list containing the current process argv bytes."
+        return bup_main.argv()
+    def get_argv():
+        "Return a new list containing the current process argv strings."
+        return [x.decode(errors='surrogateescape') for x in bup_main.argv()]
+else:
+    def get_argvb():
+        raise Exception('get_argvb requires the bup_main module');
+    def get_argv():
+        raise Exception('get_argv requires the bup_main module');
 
 def wrap_main(main):
     """Run main() and raise a SystemExit with the return value if it
@@ -76,38 +109,3 @@ def wrap_main(main):
         sys.exit(main())
     except KeyboardInterrupt as ex:
         sys.exit(130)
-    except SystemExit as ex:
-        raise
-    except BaseException as ex:
-        if py3:
-            raise
-        add_ex_tb(ex)
-        dump_traceback(ex)
-        sys.exit(1)
-
-
-# Excepting wrap_main() in the traceback, these should produce similar output:
-#   python2 lib/bup/compat.py
-#   python3 lib/bup/compat.py
-# i.e.:
-#   diff -u <(python2 lib/bup/compat.py 2>&1) <(python3 lib/bup/compat.py 2>&1)
-#
-# Though the python3 output for 'second' will include a stacktrace
-# starting from wrap_main, rather than from outer().
-
-if __name__ == '__main__':
-
-    def inner():
-        raise Exception('first')
-
-    def outer():
-        try:
-            inner()
-        except Exception as ex:
-            add_ex_tb(ex)
-            try:
-                raise Exception('second')
-            except Exception as ex2:
-                raise chain_ex(add_ex_tb(ex2), ex)
-
-    wrap_main(outer)