This is a recipe is often use for the mainline of my Python scripts. With this recipe your Python script will:
- gracefully handle
- log an error (using the
loggingmodule) 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
lessand terminates that)
- if your script logger is enabled for
DEBUGlevel logging, a full traceback will be shown for an uncaught exception
you have a global
logvariable a la:
import logging log = logging.setLevel("scriptname")
your script's entry point is a function
def main(argv): ...
Python, 31 lines
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, "__name__"): exc_class, exc, tb = exc_info if isinstance(exc, IOError) and exc.args == 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, tb_path, tb_lineno, tb_func) else: # string exception log.error(exc_info) 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.