1# Copyright 2015 Google Inc. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import math 16import os 17import sys 18import traceback 19 20 21def PrintFormattedException(msg=None): 22 exception_class, exception, tb = sys.exc_info() 23 24 def _GetFinalFrame(tb_level): 25 while tb_level.tb_next: 26 tb_level = tb_level.tb_next 27 return tb_level.tb_frame 28 29 processed_tb = traceback.extract_tb(tb) 30 frame = _GetFinalFrame(tb) 31 exception_list = traceback.format_exception_only(exception_class, exception) 32 exception_string = '\n'.join(l.strip() for l in exception_list) 33 34 if msg: 35 print >> sys.stderr 36 print >> sys.stderr, msg 37 38 _PrintFormattedTrace(processed_tb, frame, exception_string) 39 40def PrintFormattedFrame(frame, exception_string=None): 41 _PrintFormattedTrace(traceback.extract_stack(frame), frame, exception_string) 42 43 44def _PrintFormattedTrace(processed_tb, frame, exception_string=None): 45 """Prints an Exception in a more useful format than the default. 46 """ 47 print >> sys.stderr 48 49 # Format the traceback. 50 base_dir = os.path.dirname(__file__) 51 print >> sys.stderr, 'Traceback (most recent call last):' 52 for filename, line, function, text in processed_tb: 53 filename = os.path.abspath(filename) 54 if filename.startswith(base_dir): 55 filename = filename[len(base_dir)+1:] 56 print >> sys.stderr, ' %s at %s:%d' % (function, filename, line) 57 print >> sys.stderr, ' %s' % text 58 59 # Format the exception. 60 if exception_string: 61 print >> sys.stderr, exception_string 62 63 # Format the locals. 64 local_variables = [(variable, value) for variable, value in 65 frame.f_locals.iteritems() if variable != 'self'] 66 print >> sys.stderr 67 print >> sys.stderr, 'Locals:' 68 if local_variables: 69 longest_variable = max(len(v) for v, _ in local_variables) 70 for variable, value in sorted(local_variables): 71 value = repr(value) 72 possibly_truncated_value = _AbbreviateMiddleOfString(value, ' ... ', 1024) 73 truncation_indication = '' 74 if len(possibly_truncated_value) != len(value): 75 truncation_indication = ' (truncated)' 76 print >> sys.stderr, ' %s: %s%s' % (variable.ljust(longest_variable + 1), 77 possibly_truncated_value, 78 truncation_indication) 79 else: 80 print >> sys.stderr, ' No locals!' 81 82 print >> sys.stderr 83 sys.stderr.flush() 84 85 86def _AbbreviateMiddleOfString(target, middle, max_length): 87 if max_length < 0: 88 raise ValueError('Must provide positive max_length') 89 if len(middle) > max_length: 90 raise ValueError('middle must not be greater than max_length') 91 92 if len(target) <= max_length: 93 return target 94 half_length = (max_length - len(middle)) / 2. 95 return (target[:int(math.floor(half_length))] + middle + 96 target[-int(math.ceil(half_length)):]) 97