Why can't I CTRL-C out of this script? Oh:
while True: try: x = do_the_thing() return x except: log('An error occurred, retry')
This Code Kills article gives a few good suggestions on how to avoid this.
One case that I've encountered a few times is this: I need to call some function that might fail. I don't particularly care how or why it failed, but I want to raise a new exception type, because higher level code only cares about what operation was attempted, not how it failed.
So I write something like this:
def print_document(doc, printer): try: conn = open_connection_to_printer(printer) conn.send_print_job(doc) except Exception: raise PrintError
Exception is significant. This filters out things like
SystemExit, which prevents my original complaint about CTRL-C not working.
Because network connections can raise a lot of different error types, I don't really feel like trying to enumerate all the possible errors (plus, the next version of that module might add new ones).
But then a day comes when I'm sure that the network connection is okay, and I really need to diagnose why this code is failing. I wish I could see what happened at the moment I raised
My improved code looks like this:
def print_document(doc, printer): try: conn = open_connection_to_printer(printer) conn.send_print_job(doc) except Exception as e: raise PrintError(err=e), None, sys.exc_info()
That last line contains a bit too much opaque cleverness, but it does two important things:
- It captures the original exception, so even though we propagate
PrintErrorupwards, we can always dig into the inner
erras needed (for example,
__repr__might print out
- It preserves the original stacktrace. I didn't know I needed this until my code started failing with an unexpected
PrintError, with the inner
KeyError. By itself that's not enough information to tell what happened; I want to see where the
KeyErrorwas raised, but in my earlier code the stacktrace ends at
print_document(). Using the long form of
raise(reference) allows me to pass the original stacktrace instead.