#17442: Add chained traceback support to InteractiveInterpreter.

Patch by Claudiu Popa.
This commit is contained in:
R David Murray 2014-09-29 11:25:00 -04:00
parent 4d75a01798
commit c31e6227f9
5 changed files with 70 additions and 12 deletions

View File

@ -114,6 +114,9 @@ Interactive Interpreter Objects
because it is within the interpreter object implementation. The output is because it is within the interpreter object implementation. The output is
written by the :meth:`write` method. written by the :meth:`write` method.
.. versionchanged:: 3.5 The full chained traceback is displayed instead
of just the primary traceback.
.. method:: InteractiveInterpreter.write(data) .. method:: InteractiveInterpreter.write(data)

View File

@ -134,6 +134,13 @@ New Modules
Improved Modules Improved Modules
================ ================
code
----
* The :func:`code.InteractiveInterpreter.showtraceback` method now prints
the full chained traceback, just like the interactive interpreter
(contributed by Claudiu.Popa in :issue:`17442`).
compileall compileall
---------- ----------

View File

@ -137,25 +137,35 @@ class InteractiveInterpreter:
The output is written by self.write(), below. The output is written by self.write(), below.
""" """
sys.last_type, sys.last_value, last_tb = ei = sys.exc_info()
sys.last_traceback = last_tb
try: try:
type, value, tb = sys.exc_info() lines = []
sys.last_type = type for value, tb in traceback._iter_chain(*ei[1:]):
sys.last_value = value if isinstance(value, str):
sys.last_traceback = tb lines.append(value)
tblist = traceback.extract_tb(tb) lines.append('\n')
del tblist[:1] continue
lines = traceback.format_list(tblist) if tb:
if lines: tblist = traceback.extract_tb(tb)
lines.insert(0, "Traceback (most recent call last):\n") if tb is last_tb:
lines.extend(traceback.format_exception_only(type, value)) # The last traceback includes the frame we
# exec'd in
del tblist[:1]
tblines = traceback.format_list(tblist)
if tblines:
lines.append("Traceback (most recent call last):\n")
lines.extend(tblines)
lines.extend(traceback.format_exception_only(type(value),
value))
finally: finally:
tblist = tb = None tblist = last_tb = ei = None
if sys.excepthook is sys.__excepthook__: if sys.excepthook is sys.__excepthook__:
self.write(''.join(lines)) self.write(''.join(lines))
else: else:
# If someone has set sys.excepthook, we let that take precedence # If someone has set sys.excepthook, we let that take precedence
# over self.write # over self.write
sys.excepthook(type, value, tb) sys.excepthook(type, value, last_tb)
def write(self, data): def write(self, data):
"""Write a string. """Write a string.

View File

@ -1,6 +1,7 @@
"Test InteractiveConsole and InteractiveInterpreter from code module" "Test InteractiveConsole and InteractiveInterpreter from code module"
import sys import sys
import unittest import unittest
from textwrap import dedent
from contextlib import ExitStack from contextlib import ExitStack
from unittest import mock from unittest import mock
from test import support from test import support
@ -78,6 +79,40 @@ class TestInteractiveConsole(unittest.TestCase):
self.console.interact(banner='') self.console.interact(banner='')
self.assertEqual(len(self.stderr.method_calls), 1) self.assertEqual(len(self.stderr.method_calls), 1)
def test_cause_tb(self):
self.infunc.side_effect = ["raise ValueError('') from AttributeError",
EOFError('Finished')]
self.console.interact()
output = ''.join(''.join(call[1]) for call in self.stderr.method_calls)
expected = dedent("""
AttributeError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<console>", line 1, in <module>
ValueError
""")
self.assertIn(expected, output)
def test_context_tb(self):
self.infunc.side_effect = ["try: ham\nexcept: eggs\n",
EOFError('Finished')]
self.console.interact()
output = ''.join(''.join(call[1]) for call in self.stderr.method_calls)
expected = dedent("""
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'ham' is not defined
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<console>", line 2, in <module>
NameError: name 'eggs' is not defined
""")
self.assertIn(expected, output)
def test_main(): def test_main():
support.run_unittest(TestInteractiveConsole) support.run_unittest(TestInteractiveConsole)

View File

@ -145,6 +145,9 @@ Core and Builtins
Library Library
------- -------
- Issue #17442: InteractiveInterpreter now displays the full chained traceback
in its showtraceback method, to match the built in interactive interpreter.
- Issue #10510: distutils register and upload methods now use HTML standards - Issue #10510: distutils register and upload methods now use HTML standards
compliant CRLF line endings. compliant CRLF line endings.