| OLD | NEW |
| (Empty) |
| 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 | |
| 15 import math | |
| 16 import os | |
| 17 import sys | |
| 18 import traceback | |
| 19 | |
| 20 | |
| 21 def 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 | |
| 40 def PrintFormattedFrame(frame, exception_string=None): | |
| 41 _PrintFormattedTrace(traceback.extract_stack(frame), frame, exception_string) | |
| 42 | |
| 43 | |
| 44 def _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 | |
| 86 def _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)):]) | |
| OLD | NEW |