3

I need to have a file deleted if not all the operations that must be done on it were successful (that is, if an exception is raised). It could have been as simple as using except:, deleting the file and then re-raising the exception, but in that case the original exception would be lost if the file cannot be deleted in the except clause for whatever arcane reason.

The best that I have been able to come up with is this:

try:
    file_path = "whatever.jpg"
    # do stuff with file
except:
    exception_raised = True
    raise
finally:
    try:
        if exception_raised:
            os.unlink(file_path)
    except:
        pass

return file_path   # everything OK

Does anybody know of a better, more Pythonic approach?

plok
  • 705
  • 7
  • 30

1 Answers1

5

Another option is to simply store the exception if you don't want to lose it:

Python 3.x version:

try:
    file_path = "whatever.jpg"
    # do stuff with file
except BaseException as e:
    try:
        os.unlink(file_path)
    except Exception:
        traceback.print_exc()
    raise e

The Python 2.x version is slightly more complex since you need to store the complete exception information manually (otherwise you'd lose the traceback):

try:
    file_path = "whatever.jpg"
    # do stuff with file
except:
    e = sys.exc_info()
    try:
        os.unlink(file_path)
    except Exception:
        traceback.print_exc()
    raise e[0], e[1], e[2]

Edit: Only catch subclasses of Exception in the inner try block, since you don't want do catch SystemExit or KeyboardInterrupt here. Also report any excpetion that occurred during unlinking instead of just dropping it.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • Of course, this will not work for exceptions that are not derived from `BaseException`. – Mankarse Oct 07 '11 at 12:34
  • @Mankarse: In Python 3, all exceptions must be derived from BaseException. In Python 2, an exception class must either be derived from `BaseExcpetion` or be an old-style class. Old-style classes are phasing out for ten years now, so the above code should be pretty safe if you aren't using *very* old libraries using strange exception classes. – Sven Marnach Oct 07 '11 at 13:32
  • @Mankarse: There was a different problem with the code for Python 2.x -- the traceback of the exception was lost. Fixing this problem also removed the (minor) restriction to `BaseException`. – Sven Marnach Oct 07 '11 at 14:34
  • That's what I had overlooked and precisely what I was looking for: sys.exc_info(). Perfect. Thanks, Sven. – plok Oct 07 '11 at 15:55