[pypy-commit] pypy py3k: have the code module display chained exceptions since our repl uses it

pjenvey noreply at buildbot.pypy.org
Wed Apr 10 01:46:28 CEST 2013


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r63184:1341a432e134
Date: 2013-04-09 16:45 -0700
http://bitbucket.org/pypy/pypy/changeset/1341a432e134/

Log:	have the code module display chained exceptions since our repl uses
	it

diff --git a/lib-python/3/code.py b/lib-python/3/code.py
--- a/lib-python/3/code.py
+++ b/lib-python/3/code.py
@@ -130,19 +130,29 @@
         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:
-            type, value, tb = sys.exc_info()
-            sys.last_type = type
-            sys.last_value = value
-            sys.last_traceback = tb
-            tblist = traceback.extract_tb(tb)
-            del tblist[:1]
-            lines = traceback.format_list(tblist)
-            if lines:
-                lines.insert(0, "Traceback (most recent call last):\n")
-            lines.extend(traceback.format_exception_only(type, value))
+            lines = []
+            for value, tb in traceback._iter_chain(*ei[1:]):
+                if isinstance(value, str):
+                    lines.append(value)
+                    lines.append('\n')
+                    continue
+                if tb:
+                    tblist = traceback.extract_tb(tb)
+                    if tb is last_tb:
+                        # 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:
-            tblist = tb = None
+            tblist = last_tb = ei = None
         self.write(''.join(lines))
 
     def write(self, data):
diff --git a/pypy/module/test_lib_pypy/test_code_module.py b/pypy/module/test_lib_pypy/test_code_module.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/test_code_module.py
@@ -0,0 +1,42 @@
+class AppTestCodeModule:
+
+    def w_get_interp(self):
+        import code
+        import io
+        class MockedInterpreter(code.InteractiveInterpreter):
+            def __init__(self, *args, **kwargs):
+                super().__init__(*args, **kwargs)
+                self.out = io.StringIO()
+
+            def write(self, data):
+                self.out.write(data)
+        return MockedInterpreter()
+
+    def test_cause_tb(self):
+        interp = self.get_interp()
+        interp.runsource('raise IOError from OSError')
+        result = interp.out.getvalue()
+        expected_header = """OSError
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+"""
+        assert expected_header in result
+        assert result.endswith("IOError\n")
+
+    def test_context_tb(self):
+        interp = self.get_interp()
+        interp.runsource("""\
+try: zzzeek
+except: _diana_
+""")
+        result = interp.out.getvalue()
+        expected_header = """NameError: name 'zzzeek' is not defined
+
+During handling of the above exception, another exception occurred:
+
+Traceback (most recent call last):
+"""
+        assert expected_header in result
+        assert result.endswith("NameError: name '_diana_' is not defined\n")


More information about the pypy-commit mailing list