Created
July 16, 2009 03:04
-
-
Save bstpierre/148135 to your computer and use it in GitHub Desktop.
Python Exception Handling: Cleanup and Reraise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# | |
# This code sample shows (what I hope to be) the right way to reraise an exception in the | |
# situation where you have to perform some cleanup before reraising. | |
# | |
cleaned_up = False | |
def raiser(): | |
raise RuntimeError("this should be reported at line 10") | |
def cleanup_raises(): | |
global cleaned_up | |
cleaned_up = True | |
raise RuntimeError("you should not see this!") | |
def reraiser1(): | |
try: | |
raiser() | |
except RuntimeError, e: | |
try: | |
cleanup_raises() | |
except RuntimeError: | |
pass | |
# Wrong: stack trace reports this as the original scene of the | |
# crime. Location information should say line 10 but it doesn't | |
raise e | |
def reraiser2(): | |
try: | |
raiser() | |
except RuntimeError, e: | |
try: | |
cleanup_raises() | |
except RuntimeError: | |
pass | |
# Wrong: stack trace reports cleanup_raises as the culprit. We | |
# want to know about raiser. | |
raise | |
def reraiser3(): | |
try: | |
raiser() | |
except RuntimeError, e: | |
def cleanup(): | |
try: | |
cleanup_raises() | |
except RuntimeError: | |
pass | |
cleanup() | |
# Right: Need to make sure that exceptions from cleanup_raises | |
# are handled in a separate scope. This reports the original | |
# exception location of raiser at line 10. | |
raise | |
def reraiser4(): | |
try: | |
raiser() | |
except RuntimeError, e: | |
(_, _, traceback) = sys.exc_info() | |
try: | |
cleanup_raises() | |
except RuntimeError: | |
pass | |
# Right: Raise exception but provide original traceback | |
# info. (Note: must call sys.exc_info() before calling any | |
# other possible raiser.) This also reports raiser at line 10. | |
raise e, None, traceback | |
def reraiser5(): | |
try: | |
raiser() | |
finally: | |
try: | |
cleanup_raises() | |
except RuntimeError: | |
pass | |
# Right: Don't even catch the original exception -- just clean | |
# up on the way out. | |
assert(cleaned_up) | |
import sys | |
variant = sys.argv[1] | |
if variant == '1': | |
reraiser1() | |
elif variant == '2': | |
reraiser2() | |
elif variant == '3': | |
reraiser3() | |
elif variant == '4': | |
reraiser4() | |
elif variant == '5': | |
reraiser5() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment