[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / test / gpu / gpu_tests / exception_formatter.py
blob912c006877f6e70c618129dafa0b1a120c5df4a3
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Print prettier and more detailed exceptions. Copied from Telemetry."""
7 import math
8 import os
9 import sys
10 import traceback
12 from telemetry.core import exceptions
13 from telemetry.core import util
16 def PrintFormattedException(exception_class=None, exception=None, tb=None,
17 msg=None):
18 assert bool(exception_class) == bool(exception) == bool(tb), (
19 'Must specify all or none of exception_class, exception, and tb')
21 if not exception_class:
22 exception_class, exception, tb = sys.exc_info()
24 if exception_class == exceptions.IntentionalException:
25 return
27 def _GetFinalFrame(tb_level):
28 while tb_level.tb_next:
29 tb_level = tb_level.tb_next
30 return tb_level.tb_frame
32 processed_tb = traceback.extract_tb(tb)
33 frame = _GetFinalFrame(tb)
34 exception_list = traceback.format_exception_only(exception_class, exception)
35 exception_string = '\n'.join(l.strip() for l in exception_list)
37 if msg:
38 print >> sys.stderr
39 print >> sys.stderr, msg
41 _PrintFormattedTrace(processed_tb, frame, exception_string)
44 def PrintFormattedFrame(frame, exception_string=None):
45 _PrintFormattedTrace(traceback.extract_stack(frame), frame, exception_string)
48 def _PrintFormattedTrace(processed_tb, frame, exception_string=None):
49 """Prints an Exception in a more useful format than the default.
51 TODO(tonyg): Consider further enhancements. For instance:
52 - Report stacks to maintainers like depot_tools does.
53 - Add a debug flag to automatically start pdb upon exception.
54 """
55 print >> sys.stderr
57 # Format the traceback.
58 base_dir = os.path.abspath(util.GetChromiumSrcDir())
59 print >> sys.stderr, 'Traceback (most recent call last):'
60 for filename, line, function, text in processed_tb:
61 filename = os.path.abspath(filename)
62 if filename.startswith(base_dir):
63 filename = filename[len(base_dir)+1:]
64 print >> sys.stderr, ' %s at %s:%d' % (function, filename, line)
65 print >> sys.stderr, ' %s' % text
67 # Format the exception.
68 if exception_string:
69 print >> sys.stderr, exception_string
71 # Format the locals.
72 local_variables = [(variable, value) for variable, value in
73 frame.f_locals.iteritems() if variable != 'self']
74 print >> sys.stderr
75 print >> sys.stderr, 'Locals:'
76 if local_variables:
77 longest_variable = max(len(v) for v, _ in local_variables)
78 for variable, value in sorted(local_variables):
79 value = repr(value)
80 possibly_truncated_value = _AbbreviateMiddleOfString(value, ' ... ', 1024)
81 truncation_indication = ''
82 if len(possibly_truncated_value) != len(value):
83 truncation_indication = ' (truncated)'
84 print >> sys.stderr, ' %s: %s%s' % (variable.ljust(longest_variable + 1),
85 possibly_truncated_value,
86 truncation_indication)
87 else:
88 print >> sys.stderr, ' No locals!'
90 print >> sys.stderr
91 sys.stderr.flush()
94 def _AbbreviateMiddleOfString(target, middle, max_length):
95 if max_length < 0:
96 raise ValueError('Must provide positive max_length')
97 if len(middle) > max_length:
98 raise ValueError('middle must not be greater than max_length')
100 if len(target) <= max_length:
101 return target
102 half_length = (max_length - len(middle)) / 2.
103 return (target[:int(math.floor(half_length))] + middle +
104 target[-int(math.ceil(half_length)):])