]> arthur.barton.de Git - bup.git/commit
Support exception chaining and tracebacks
authorRob Browning <rlb@defaultvalue.org>
Fri, 7 Apr 2017 00:32:50 +0000 (19:32 -0500)
committerRob Browning <rlb@defaultvalue.org>
Sat, 20 May 2017 19:27:53 +0000 (14:27 -0500)
commit7a339a74732eb8e12add7c5af01e5bdc2135dc08
treeec8a7407de7e33fd0abc11f5303003ca0b8c21e7
parent642316519154df7abbd75f346cd386f17feca5bb
Support exception chaining and tracebacks

Python 3 has added support for exception chaining
https://www.python.org/dev/peps/pep-3134/

Which makes it possible to avoid losing information when an exception
is thrown from within an exception handler:

  try:
      ...
      raise lp0_on_fire()
  except Exception as ex:
    # Imagine the disk is also full and close() throws too
    some_output_file.close()

In this situation, you'll never find out the printer's on fire.  With
chaining, the first exception will be attached to the second as its
__context__.  (Note that "finally" blocks suffer from the same issue.)

The PEP also describes adding a __traceback__ attribute to exceptions
so that they're more self-contained.

Python 3 handles all of this automatically, and includes any chained
exceptions in its tracebacks.  For this:

  def inner():
      raise Exception('first')

  def outer():
      try:
          inner()
      except Exception as ex:
          raise chain_ex(Exception('second'), ex)

  wrap_main(outer)

Python 3 produces:

  $ python3 lib/bup/compat.py
  Traceback (most recent call last):
    File "lib/bup/compat.py", line 74, in outer
      inner()
    File "lib/bup/compat.py", line 70, in inner
      raise Exception('first')
  Exception: first

  During handling of the above exception, another exception occurred:

  Traceback (most recent call last):
    File "lib/bup/compat.py", line 78, in <module>
      wrap_main(outer)
    File "lib/bup/compat.py", line 50, in wrap_main
      sys.exit(main())
    File "lib/bup/compat.py", line 76, in outer
      raise chain_ex(Exception('second'), ex)
  Exception: second

Add a compat.py supporting something similar for Python 2, and use it
in main.py.

Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
lib/bup/compat.py [new file with mode: 0644]
main.py