Kaydet (Commit) c31e6227 authored tarafından R David Murray's avatar R David Murray

#17442: Add chained traceback support to InteractiveInterpreter.

Patch by Claudiu Popa.
üst 4d75a017
...@@ -114,6 +114,9 @@ Interactive Interpreter Objects ...@@ -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)
......
...@@ -134,6 +134,13 @@ New Modules ...@@ -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
---------- ----------
......
...@@ -137,25 +137,35 @@ class InteractiveInterpreter: ...@@ -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)
lines.append('\n')
continue
if tb:
tblist = traceback.extract_tb(tb) tblist = traceback.extract_tb(tb)
if tb is last_tb:
# The last traceback includes the frame we
# exec'd in
del tblist[:1] del tblist[:1]
lines = traceback.format_list(tblist) tblines = traceback.format_list(tblist)
if lines: if tblines:
lines.insert(0, "Traceback (most recent call last):\n") lines.append("Traceback (most recent call last):\n")
lines.extend(traceback.format_exception_only(type, value)) 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.
......
"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): ...@@ -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)
......
...@@ -145,6 +145,9 @@ Core and Builtins ...@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment