This is a recipe is often use for the mainline of my Python scripts. With this recipe your Python script will:
- gracefully handle
Ctrl+C
(i.e.KeyboardInterrupt
) - log an error (using the
logging
module) for uncaught exceptions, importantly with the file and line number in your Python code where the exception was raised - gracefully ignore a closed output pipe (common when the user pipes your script through
less
and terminates that) - if your script logger is enabled for
DEBUG
level logging, a full traceback will be shown for an uncaught exception
Presumptions:
you have a global
log
variable a la:import logging log = logging.setLevel("scriptname")
your script's entry point is a function
def main(argv): ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | if __name__ == "__main__":
try:
retval = main(sys.argv)
except KeyboardInterrupt:
sys.exit(1)
except SystemExit:
raise
except:
import traceback, logging
if not log.handlers and not logging.root.handlers:
logging.basicConfig()
skip_it = False
exc_info = sys.exc_info()
if hasattr(exc_info[0], "__name__"):
exc_class, exc, tb = exc_info
if isinstance(exc, IOError) and exc.args[0] == 32:
# Skip 'IOError: [Errno 32] Broken pipe': often a cancelling of `less`.
skip_it = True
if not skip_it:
tb_path, tb_lineno, tb_func = traceback.extract_tb(tb)[-1][:3]
log.error("%s (%s:%s in %s)", exc_info[1], tb_path,
tb_lineno, tb_func)
else: # string exception
log.error(exc_info[0])
if not skip_it:
if log.isEnabledFor(logging.DEBUG):
print()
traceback.print_exception(*exc_info)
sys.exit(1)
else:
sys.exit(retval)
|
You have 1/0 which always produces an exception, by definition. What is the point of this?
Nine years old recipe looks more solid and prints stack trace along with variables values: http://code.activestate.com/recipes/52215/
@chris: stupidity. I had put that in for testing. I'll remove it.
@denis: thanks for the link. I'll probably try to incorporate that for a future rev.