Skip to content

Commit

Permalink
Merge pull request google#438 from TomGoBravo/master
Browse files Browse the repository at this point in the history
update traceplus to work with Python2 and Python3, add example usage
  • Loading branch information
RachM authored Mar 29, 2018
2 parents 60ceaa1 + f8edf30 commit 54a4081
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 18 deletions.
35 changes: 17 additions & 18 deletions misc/traceplus.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python2.5

# Copyright (C) 2009 Google Inc.
# Copyright (C) 2018 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -17,13 +17,7 @@
"""
Wrapper that makes more useful stack dumps when your script crashes.
Normal use, so that your script works if with or without traceplus:
if __name__ == '__main__':
try:
import traceplus
traceplus.RunWithExpandedTrace(main)
except ImportError:
main()
See traceplus_example.py for a demonstration.
"""

def MakeExpandedTrace(frame_records):
Expand All @@ -40,14 +34,18 @@ def MakeExpandedTrace(frame_records):
else:
dump.append(' %s' % line)
for local_name, local_val in frame_obj.f_locals.items():
try:
local_type_name = type(local_val).__name__
except Exception as e:
local_type_name = ' Exception in type({}).__name__: {}'.format(local_name, e)
try:
truncated_val = repr(local_val)[0:500]
except Exception, e:
dump.append(' Exception in str(%s): %s\n' % (local_name, e))
except Exception as e:
dump.append(' Exception in repr({}): {}\n'.format(local_name, e))
else:
if len(truncated_val) >= 500:
truncated_val = '%s...' % truncated_val[0:499]
dump.append(' %s = %s\n' % (local_name, truncated_val))
dump.append(' {} = {} ({})\n'.format(local_name, truncated_val, local_type_name))
dump.append('\n')
return dump

Expand All @@ -62,21 +60,22 @@ def RunWithExpandedTrace(closure):
import sys
import traceback

# Save trace and exception now. These calls look at the most recently
# Save trace and exception now. This call looks at the most recently
# raised exception. The code that makes the report might trigger other
# exceptions.
original_trace = inspect.trace(3)[1:]
formatted_exception = traceback.format_exception_only(*(sys.exc_info()[:2]))
exc_type, exc_value, tb = sys.exc_info()
frame_records = inspect.getinnerframes(tb, 3)[1:]
formatted_exception = traceback.format_exception_only(exc_type, exc_value)

dashes = '%s\n' % ('-' * 60)
dump = []
dump.append(dashes)
dump.extend(MakeExpandedTrace(original_trace))
dump.extend(MakeExpandedTrace(frame_records))


dump.append(''.join(formatted_exception))

print ''.join(dump)
print
print dashes
print(''.join(dump))
print()
print(dashes)
sys.exit(127)
25 changes: 25 additions & 0 deletions misc/traceplus_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/python3

import argparse
parser = argparse.ArgumentParser()

def CrashOrNot(crash_commanded):
some_value = 1
if crash_commanded:
some_value -= 1
print("All good, you get {}".format(1 / some_value))

def main():
parser = argparse.ArgumentParser()
parser.add_argument("--crash", help="Do something that causes a crash", action="store_true")
args = parser.parse_args()
CrashOrNot(args.crash)

# If the traceplus module is found use it, otherwise run main() directly.
if __name__ == '__main__':
try:
import traceplus
except ImportError:
main()
else:
traceplus.RunWithExpandedTrace(main)
68 changes: 68 additions & 0 deletions misc/traceplusunittest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/python2.5

# Copyright (C) 2018 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Includes locals in the stacktrace when a failure occurs.
#
# Example use:
#
# if __name__ == '__main__':
# try:
# import traceplusunittest
# except ImportError:
# unittest.main()
# else:
# traceplusunittest.main()

import unittest
import traceplus
import traceback
import inspect


class TextBigStackTestRunner(unittest.TextTestRunner):
def _makeResult(self):
return TextBigStackTestResult(self.stream, self.descriptions, self.verbosity)


class TextBigStackTestResult(unittest._TextTestResult):
def _exc_info_to_string(self, err, test):
"""Converts a sys.exc_info()-style tuple of values into a string."""
exctype, value, tb = err
# Skip test runner traceback levels
while tb and self._is_relevant_tb_level(tb):
tb = tb.tb_next
if exctype is test.failureException:
# Skip assert*() traceback levels
length = self._count_relevant_tb_levels(tb)
return ''.join(FormatException(exctype, value, tb, length))
return ''.join(FormatException(exctype, value, tb))


def FormatException(exctype, value, tb, length=None):
frame_records = inspect.getinnerframes(tb, 3)

dump = []
if length is None:
dump.extend(traceplus.MakeExpandedTrace(frame_records))
else:
dump.extend(traceplus.MakeExpandedTrace(frame_records[:length]))
dump.extend(traceback.format_exception_only(exctype, value))
return ''.join(dump)


def main():
unittest.main(testRunner=TextBigStackTestRunner())

18 changes: 18 additions & 0 deletions misc/traceplusunittest_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import unittest

class TestStringMethods(unittest.TestCase):

def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')

def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'hello']) # This will fail

if __name__ == '__main__':
try:
import traceplusunittest
except ImportError:
unittest.main()
else:
traceplusunittest.main()

0 comments on commit 54a4081

Please sign in to comment.