From afccc337ccf87f0085dce8ec8a372a55e6a8d1a7 Mon Sep 17 00:00:00 2001 From: Fabio Erculiani Date: Sun, 6 Jan 2013 16:37:11 +0000 Subject: [PATCH] [matter] add exception handler that also prints local variables in the stack --- matter/matter/main.py | 22 +++++++++++++++ matter/matter/utils.py | 62 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/matter/matter/main.py b/matter/matter/main.py index 19ca80b8f..f0f2fea14 100644 --- a/matter/matter/main.py +++ b/matter/matter/main.py @@ -22,6 +22,27 @@ from matter.lock import MatterResourceLock from matter.output import purple, darkgreen, print_info, \ print_warning, print_error, is_stdout_a_tty, nocolor from matter.spec import SpecParser, MatterSpec +from matter.utils import print_exception + + +def install_exception_handler(): + sys.excepthook = handle_exception + + +def uninstall_exception_handler(): + sys.excepthook = sys.__excepthook__ + + +def handle_exception(exc_class, exc_instance, exc_tb): + + # restore original exception handler, to avoid loops + uninstall_exception_handler() + + if exc_class is KeyboardInterrupt: + raise SystemExit(1) + + # always slap exception data (including stack content) + print_exception(tb_data = exc_tb) def matter_main(binary_pms, nsargs, cwd, specs): @@ -172,6 +193,7 @@ def main(): """ Main App. """ + install_exception_handler() # disable color if standard output is not a TTY if not is_stdout_a_tty(): diff --git a/matter/matter/utils.py b/matter/matter/utils.py index 97db06715..ca38d1df3 100644 --- a/matter/matter/utils.py +++ b/matter/matter/utils.py @@ -15,6 +15,8 @@ import sys import tempfile import traceback +from matter.output import print_generic + MATTER_TMPDIR = os.getenv("MATTER_TMPDIR", "/var/tmp/matter") _ENCODING = "UTF-8" @@ -31,6 +33,66 @@ def print_traceback(f = None): traceback.print_exc(file = f) +def print_exception(silent=False, tb_data=None, all_frame_data=False): + """ + Print last Python exception and frame variables values (if available) + to stdout. + + @keyword silent: do not print to stdout + @type silent: bool + @keyword tb_data: Python traceback object + @type tb_data: Python traceback instance + @keyword all_frame_data: print all variables in every frame + @type all_frame_data: bool + @return: exception data + @rtype: list of strings + """ + if not silent: + traceback.print_last() + data = [] + if tb_data is not None: + tb = tb_data + else: + last_type, last_value, last_traceback = sys.exc_info() + tb = last_traceback + + stack = [] + while True: + if not tb: + break + if not tb.tb_next: + break + tb = tb.tb_next + if all_frame_data: + stack.append(tb.tb_frame) + + if not all_frame_data: + stack.append(tb.tb_frame) + + #if not returndata: print + for frame in stack: + if not silent: + print_generic("") + print_generic("Frame %s in %s at line %s" % (frame.f_code.co_name, + frame.f_code.co_filename, frame.f_lineno)) + data.append("Frame %s in %s at line %s\n" % (frame.f_code.co_name, + frame.f_code.co_filename, frame.f_lineno)) + + for key, value in list(frame.f_locals.items()): + cur_str = '' + cur_str = "\t%20s = " % key + try: + cur_str += repr(value) + "\n" + except (AttributeError, NameError, TypeError): + cur_str += "\n" + + if not silent: + sys.stdout.write(cur_str) + data.append(cur_str) + + return data + + def mkstemp(prefix=None, suffix=None): """ Create temporary file into matter temporary directory.